Chromium Code Reviews| Index: content/renderer/media/webrtc/processed_local_audio_source_unittest.cc |
| diff --git a/content/renderer/media/webrtc_audio_capturer_unittest.cc b/content/renderer/media/webrtc/processed_local_audio_source_unittest.cc |
| similarity index 20% |
| rename from content/renderer/media/webrtc_audio_capturer_unittest.cc |
| rename to content/renderer/media/webrtc/processed_local_audio_source_unittest.cc |
| index 373b95ba50e17a28e962d3c769253082cb899ab2..3a2516e65d32ecbe8aaa9eb3408c40b0aa340c8b 100644 |
| --- a/content/renderer/media/webrtc_audio_capturer_unittest.cc |
| +++ b/content/renderer/media/webrtc/processed_local_audio_source_unittest.cc |
| @@ -1,46 +1,41 @@ |
| -// Copyright 2013 The Chromium Authors. All rights reserved. |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| #include "base/logging.h" |
| #include "build/build_config.h" |
| #include "content/public/renderer/media_stream_audio_sink.h" |
| +#include "content/renderer/media/media_stream_audio_track.h" |
| +#include "content/renderer/media/mock_audio_device_factory.h" |
| #include "content/renderer/media/mock_constraint_factory.h" |
| -#include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h" |
| -#include "content/renderer/media/webrtc_audio_capturer.h" |
| -#include "content/renderer/media/webrtc_local_audio_track.h" |
| +#include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h" |
| +#include "content/renderer/media/webrtc/processed_local_audio_source.h" |
| #include "media/base/audio_bus.h" |
| #include "media/base/audio_parameters.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/WebKit/public/platform/WebMediaConstraints.h" |
| +#include "third_party/WebKit/public/web/WebHeap.h" |
| using ::testing::_; |
| using ::testing::AtLeast; |
| +using ::testing::Invoke; |
| namespace content { |
| namespace { |
| -class MockCapturerSource : public media::AudioCapturerSource { |
| - public: |
| - MockCapturerSource() {} |
| - MOCK_METHOD3(Initialize, void(const media::AudioParameters& params, |
| - CaptureCallback* callback, |
| - int session_id)); |
| - MOCK_METHOD0(Start, void()); |
| - MOCK_METHOD0(Stop, void()); |
| - MOCK_METHOD1(SetVolume, void(double volume)); |
| - MOCK_METHOD1(SetAutomaticGainControl, void(bool enable)); |
| - |
| - protected: |
| - ~MockCapturerSource() override {} |
| -}; |
| +#if defined(OS_ANDROID) |
| +constexpr int kBufferSize = 960; // Android works with a 20ms buffer size. |
|
o1ka
2016/05/04 08:49:24
The original comment is "bigger than 20ms" (and th
miu
2016/05/04 22:10:09
Done. Made the audio parameters more explicit with
o1ka
2016/05/06 16:53:57
Thanks!
|
| +#else |
| +constexpr int kBufferSize = 128; |
| +#endif |
| class MockMediaStreamAudioSink : public MediaStreamAudioSink { |
| public: |
| MockMediaStreamAudioSink() {} |
| ~MockMediaStreamAudioSink() override {} |
| + |
| void OnData(const media::AudioBus& audio_bus, |
| base::TimeTicks estimated_capture_time) override { |
| EXPECT_EQ(audio_bus.channels(), params_.channels()); |
| @@ -49,11 +44,12 @@ class MockMediaStreamAudioSink : public MediaStreamAudioSink { |
| OnDataCallback(); |
| } |
| MOCK_METHOD0(OnDataCallback, void()); |
| + |
| void OnSetFormat(const media::AudioParameters& params) override { |
| params_ = params; |
| - FormatIsSet(); |
| + FormatIsSet(params_); |
| } |
| - MOCK_METHOD0(FormatIsSet, void()); |
| + MOCK_METHOD1(FormatIsSet, void(const media::AudioParameters& params)); |
| private: |
| media::AudioParameters params_; |
| @@ -61,92 +57,152 @@ class MockMediaStreamAudioSink : public MediaStreamAudioSink { |
| } // namespace |
| -class WebRtcAudioCapturerTest : public testing::Test { |
| +class ProcessedLocalAudioSourceTest : public testing::Test { |
| protected: |
| - WebRtcAudioCapturerTest() |
| -#if defined(OS_ANDROID) |
| - : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
| - media::CHANNEL_LAYOUT_STEREO, 48000, 16, 960) { |
| - // Android works with a buffer size bigger than 20ms. |
| -#else |
| + ProcessedLocalAudioSourceTest() |
| : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
| - media::CHANNEL_LAYOUT_STEREO, 48000, 16, 128) { |
| -#endif |
| + media::CHANNEL_LAYOUT_STEREO, 48000, 16, kBufferSize) {} |
| + |
| + ~ProcessedLocalAudioSourceTest() override {} |
| + |
| + void SetUp() override { |
| + blink_audio_source_.initialize(blink::WebString::fromUTF8("audio_label"), |
| + blink::WebMediaStreamSource::TypeAudio, |
| + blink::WebString::fromUTF8("audio_track"), |
| + false /* remote */, true /* readonly */); |
| + blink_audio_track_.initialize(blink_audio_source_.id(), |
| + blink_audio_source_); |
| } |
| - void VerifyAudioParams(const blink::WebMediaConstraints& constraints, |
| - bool need_audio_processing) { |
| - const std::unique_ptr<WebRtcAudioCapturer> capturer = |
| - WebRtcAudioCapturer::CreateCapturer( |
| - -1, StreamDeviceInfo( |
| - MEDIA_DEVICE_AUDIO_CAPTURE, "", "", params_.sample_rate(), |
| - params_.channel_layout(), params_.frames_per_buffer()), |
| - constraints, nullptr, nullptr); |
| - const scoped_refptr<MockCapturerSource> capturer_source( |
| - new MockCapturerSource()); |
| - EXPECT_CALL(*capturer_source.get(), Initialize(_, capturer.get(), -1)); |
| - EXPECT_CALL(*capturer_source.get(), SetAutomaticGainControl(true)); |
| - EXPECT_CALL(*capturer_source.get(), Start()); |
| - capturer->SetCapturerSource(capturer_source, params_); |
| - |
| - scoped_refptr<WebRtcLocalAudioTrackAdapter> adapter( |
| - WebRtcLocalAudioTrackAdapter::Create(std::string(), NULL)); |
| - const std::unique_ptr<WebRtcLocalAudioTrack> track( |
| - new WebRtcLocalAudioTrack(adapter.get())); |
| - capturer->AddTrack(track.get()); |
| - |
| - // Connect a mock sink to the track. |
| - std::unique_ptr<MockMediaStreamAudioSink> sink( |
| - new MockMediaStreamAudioSink()); |
| - track->AddSink(sink.get()); |
| - |
| - int delay_ms = 65; |
| - bool key_pressed = true; |
| - double volume = 0.9; |
| - |
| - std::unique_ptr<media::AudioBus> audio_bus = |
| - media::AudioBus::Create(params_); |
| - audio_bus->Zero(); |
| - |
| - media::AudioCapturerSource::CaptureCallback* callback = |
| - static_cast<media::AudioCapturerSource::CaptureCallback*>( |
| - capturer.get()); |
| - |
| - // Verify the sink is getting the correct values. |
| - EXPECT_CALL(*sink, FormatIsSet()); |
| - EXPECT_CALL(*sink, OnDataCallback()).Times(AtLeast(1)); |
| - callback->Capture(audio_bus.get(), delay_ms, volume, key_pressed); |
| - |
| - track->RemoveSink(sink.get()); |
| - EXPECT_CALL(*capturer_source.get(), Stop()); |
| - capturer->Stop(); |
| + void TearDown() override { |
| + blink_audio_track_.reset(); |
| + blink_audio_source_.reset(); |
| + blink::WebHeap::collectAllGarbageForTesting(); |
| } |
| - media::AudioParameters params_; |
| + void CreateProcessedLocalAudioSource( |
| + const blink::WebMediaConstraints& constraints) { |
| + ProcessedLocalAudioSource* const source = |
| + new ProcessedLocalAudioSource( |
| + -1 /* consumer_render_frame_id is N/A for non-browser tests */, |
| + StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE, "Mock audio device", |
| + "mock_audio_device_id", params_.sample_rate(), |
| + params_.channel_layout(), |
| + params_.frames_per_buffer()), |
| + &mock_dependency_factory_); |
| + source->SetAllowInvalidRenderFrameIdForTesting(true); |
| + source->SetSourceConstraints(constraints); |
| + blink_audio_source_.setExtraData(source); // Takes ownership. |
| + } |
| + |
| + void CheckAudioParametersMatch(const media::AudioParameters& params) { |
| + EXPECT_TRUE(params_.Equals(params)); |
| + } |
| + |
| + MockAudioDeviceFactory* mock_audio_device_factory() { |
| + return &mock_audio_device_factory_; |
| + } |
| + |
| + media::AudioCapturerSource::CaptureCallback* capture_source_callback() const { |
| + return static_cast<media::AudioCapturerSource::CaptureCallback*>( |
| + ProcessedLocalAudioSource::From(audio_source())); |
| + } |
| + |
| + MediaStreamAudioSource* audio_source() const { |
| + return MediaStreamAudioSource::From(blink_audio_source_); |
| + } |
| + |
| + const blink::WebMediaStreamTrack& blink_audio_track() { |
| + return blink_audio_track_; |
| + } |
| + |
| + private: |
| + MockAudioDeviceFactory mock_audio_device_factory_; |
| + const media::AudioParameters params_; |
| + MockPeerConnectionDependencyFactory mock_dependency_factory_; |
| + blink::WebMediaStreamSource blink_audio_source_; |
| + blink::WebMediaStreamTrack blink_audio_track_; |
| }; |
| -TEST_F(WebRtcAudioCapturerTest, VerifyAudioParamsWithAudioProcessing) { |
| - // Turn off the default constraints to verify that the sink will get packets |
| - // with a buffer size smaller than 10ms. |
| +// Tests a basic end-to-end start-up, track+sink connections, audio flow, and |
| +// shut-down. The unit tests in media_stream_audio_unittest.cc provide more |
| +// comprehensive testing of the object graph connections and multi-threading |
| +// concerns. |
| +TEST_F(ProcessedLocalAudioSourceTest, VerifyAudioFlowWithoutAudioProcessing) { |
| + // Turn off the default constraints so the sink will get audio in chunks of |
| + // the native buffer size. |
| MockConstraintFactory constraint_factory; |
| constraint_factory.DisableDefaultAudioConstraints(); |
| - VerifyAudioParams(constraint_factory.CreateWebMediaConstraints(), false); |
| + |
| + CreateProcessedLocalAudioSource( |
| + constraint_factory.CreateWebMediaConstraints()); |
| + |
| + // Connect the track, and expect the MockCapturerSource to be initialized and |
| + // started by ProcessedLocalAudioSource. |
| + EXPECT_CALL(*mock_audio_device_factory()->mock_capturer_source(), |
| + Initialize(_, capture_source_callback(), -1)); |
| + EXPECT_CALL(*mock_audio_device_factory()->mock_capturer_source(), |
| + SetAutomaticGainControl(true)); |
| + EXPECT_CALL(*mock_audio_device_factory()->mock_capturer_source(), Start()); |
| + ASSERT_TRUE(audio_source()->ConnectToTrack(blink_audio_track())); |
| + CheckAudioParametersMatch(audio_source()->GetAudioParameters()); |
| + |
| + // Connect a sink to the track. |
| + std::unique_ptr<MockMediaStreamAudioSink> sink( |
| + new MockMediaStreamAudioSink()); |
| + using ThisTest = |
| + ProcessedLocalAudioSourceTest_VerifyAudioFlowWithoutAudioProcessing_Test; |
| + EXPECT_CALL(*sink, FormatIsSet(_)) |
| + .WillOnce(Invoke(this, &ThisTest::CheckAudioParametersMatch)); |
| + MediaStreamAudioTrack::From(blink_audio_track())->AddSink(sink.get()); |
| + |
| + // Feed audio data into the ProcessedLocalAudioSource and expect it to reach |
| + // the sink. |
| + int delay_ms = 65; |
| + bool key_pressed = true; |
| + double volume = 0.9; |
| + std::unique_ptr<media::AudioBus> audio_bus = |
| + media::AudioBus::Create(audio_source()->GetAudioParameters()); |
| + audio_bus->Zero(); |
| + EXPECT_CALL(*sink, OnDataCallback()).Times(AtLeast(1)); |
| + capture_source_callback()->Capture(audio_bus.get(), delay_ms, volume, |
| + key_pressed); |
| + |
| + // Expect the ProcessedLocalAudioSource to auto-stop the MockCapturerSource |
| + // when the track is stopped. |
| + EXPECT_CALL(*mock_audio_device_factory()->mock_capturer_source(), Stop()); |
| + MediaStreamAudioTrack::From(blink_audio_track())->Stop(); |
| } |
| -TEST_F(WebRtcAudioCapturerTest, FailToCreateCapturerWithWrongConstraints) { |
| +// Tests that the source is not started when invalid audio constraints are |
| +// present. |
| +TEST_F(ProcessedLocalAudioSourceTest, FailToStartWithWrongConstraints) { |
| MockConstraintFactory constraint_factory; |
| const std::string dummy_constraint = "dummy"; |
| // Set a non-audio constraint. |
| constraint_factory.basic().width.setExact(240); |
| - std::unique_ptr<WebRtcAudioCapturer> capturer( |
| - WebRtcAudioCapturer::CreateCapturer( |
| - 0, StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE, "", "", |
| - params_.sample_rate(), params_.channel_layout(), |
| - params_.frames_per_buffer()), |
| - constraint_factory.CreateWebMediaConstraints(), NULL, NULL)); |
| - EXPECT_TRUE(capturer.get() == NULL); |
| + CreateProcessedLocalAudioSource( |
| + constraint_factory.CreateWebMediaConstraints()); |
| + |
| + // Expect the MockCapturerSource is never initialized/started and the |
| + // ConnectToTrack() operation fails due to the invalid constraint. |
| + EXPECT_CALL(*mock_audio_device_factory()->mock_capturer_source(), |
| + Initialize(_, capture_source_callback(), -1)) |
| + .Times(0); |
| + EXPECT_CALL(*mock_audio_device_factory()->mock_capturer_source(), |
| + SetAutomaticGainControl(true)).Times(0); |
| + EXPECT_CALL(*mock_audio_device_factory()->mock_capturer_source(), Start()) |
| + .Times(0); |
| + EXPECT_FALSE(audio_source()->ConnectToTrack(blink_audio_track())); |
| + |
| + // Even though ConnectToTrack() failed, there should still have been a new |
| + // MediaStreamAudioTrack instance created, owned by the |
| + // blink::WebMediaStreamTrack. |
| + EXPECT_TRUE(MediaStreamAudioTrack::From(blink_audio_track())); |
| } |
| +// TODO(miu): There's a lot of logic in ProcessedLocalAudioSource around |
| +// constraints processing and validation that should have unit testing. |
| } // namespace content |