| 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
|
|
|