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 18% |
rename from content/renderer/media/webrtc_audio_capturer_unittest.cc |
rename to content/renderer/media/webrtc/processed_local_audio_source_unittest.cc |
index 373b95ba50e17a28e962d3c769253082cb899ab2..0abec8ea56dd6deea7cbc541260bd3d793c1cf8a 100644 |
--- a/content/renderer/media/webrtc_audio_capturer_unittest.cc |
+++ b/content/renderer/media/webrtc/processed_local_audio_source_unittest.cc |
@@ -1,46 +1,54 @@ |
-// 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; |
+using ::testing::WithArg; |
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)); |
+// Audio parameters for the VerifyAudioFlowWithoutAudioProcessing test. |
+constexpr int kSampleRate = 48000; |
+constexpr media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO; |
+constexpr int kRequestedBufferSize = 512; |
- protected: |
- ~MockCapturerSource() override {} |
-}; |
+// On Android, ProcessedLocalAudioSource forces a 20ms buffer size from the |
+// input device. |
+#if defined(OS_ANDROID) |
+constexpr int kExpectedSourceBufferSize = kSampleRate / 50; |
+#else |
+constexpr int kExpectedSourceBufferSize = kRequestedBufferSize; |
+#endif |
+ |
+// On both platforms, even though audio processing is turned off, the |
+// MediaStreamAudioProcessor will force the use of 10ms buffer sizes on the |
+// output end of its FIFO. |
+constexpr int kExpectedOutputBufferSize = kSampleRate / 100; |
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 +57,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 +70,158 @@ 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 |
- : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
- media::CHANNEL_LAYOUT_STEREO, 48000, 16, 128) { |
-#endif |
+ ProcessedLocalAudioSourceTest() {} |
+ |
+ ~ProcessedLocalAudioSourceTest() override {} |
+ |
+ void SetUp() override { |
+ blink_audio_source_.initialize(blink::WebString::fromUTF8("audio_label"), |
+ blink::WebMediaStreamSource::TypeAudio, |
+ blink::WebString::fromUTF8("audio_track"), |
+ false /* remote */); |
+ 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", kSampleRate, |
+ kChannelLayout, kRequestedBufferSize), |
+ &mock_dependency_factory_); |
+ source->SetAllowInvalidRenderFrameIdForTesting(true); |
+ source->SetSourceConstraints(constraints); |
+ blink_audio_source_.setExtraData(source); // Takes ownership. |
+ } |
+ |
+ void CheckSourceFormatMatches(const media::AudioParameters& params) { |
+ EXPECT_EQ(kSampleRate, params.sample_rate()); |
+ EXPECT_EQ(kChannelLayout, params.channel_layout()); |
+ EXPECT_EQ(kExpectedSourceBufferSize, params.frames_per_buffer()); |
+ } |
+ |
+ void CheckOutputFormatMatches(const media::AudioParameters& params) { |
+ EXPECT_EQ(kSampleRate, params.sample_rate()); |
+ EXPECT_EQ(kChannelLayout, params.channel_layout()); |
+ EXPECT_EQ(kExpectedOutputBufferSize, params.frames_per_buffer()); |
+ } |
+ |
+ 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_; |
+ 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) { |
+ using ThisTest = |
+ ProcessedLocalAudioSourceTest_VerifyAudioFlowWithoutAudioProcessing_Test; |
+ |
+ // 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)) |
+ .WillOnce(WithArg<0>(Invoke(this, &ThisTest::CheckSourceFormatMatches))); |
+ 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())); |
+ CheckOutputFormatMatches(audio_source()->GetAudioParameters()); |
+ |
+ // Connect a sink to the track. |
+ std::unique_ptr<MockMediaStreamAudioSink> sink( |
+ new MockMediaStreamAudioSink()); |
+ EXPECT_CALL(*sink, FormatIsSet(_)) |
+ .WillOnce(Invoke(this, &ThisTest::CheckOutputFormatMatches)); |
+ 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(2, kExpectedSourceBufferSize); |
+ 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 |