// Copyright 2013 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/command_line.h" #include "base/logging.h" #include "content/public/common/content_switches.h" #include "content/renderer/media/mock_media_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 "media/audio/audio_parameters.h" #include "media/base/audio_bus.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebMediaConstraints.h" using ::testing::_; using ::testing::AtLeast; 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: virtual ~MockCapturerSource() {} }; class MockPeerConnectionAudioSink : public PeerConnectionAudioSink { public: MockPeerConnectionAudioSink() {} ~MockPeerConnectionAudioSink() {} virtual int OnData(const int16* audio_data, int sample_rate, int number_of_channels, int number_of_frames, const std::vector& channels, int audio_delay_milliseconds, int current_volume, bool need_audio_processing, bool key_pressed) OVERRIDE { EXPECT_EQ(sample_rate, params_.sample_rate()); EXPECT_EQ(number_of_channels, params_.channels()); EXPECT_EQ(number_of_frames, params_.frames_per_buffer()); OnDataCallback(audio_data, channels, audio_delay_milliseconds, current_volume, need_audio_processing, key_pressed); return 0; } MOCK_METHOD6(OnDataCallback, void(const int16* audio_data, const std::vector& channels, int audio_delay_milliseconds, int current_volume, bool need_audio_processing, bool key_pressed)); virtual void OnSetFormat(const media::AudioParameters& params) OVERRIDE { params_ = params; FormatIsSet(); } MOCK_METHOD0(FormatIsSet, void()); private: media::AudioParameters params_; }; } // namespace class WebRtcAudioCapturerTest : 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 } void EnableAudioTrackProcessing() { CommandLine::ForCurrentProcess()->AppendSwitch( switches::kEnableAudioTrackProcessing); } void VerifyAudioParams(const blink::WebMediaConstraints& constraints, bool need_audio_processing) { capturer_ = WebRtcAudioCapturer::CreateCapturer( -1, StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE, "", "", params_.sample_rate(), params_.channel_layout(), params_.frames_per_buffer()), constraints, NULL, NULL); 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_->SetCapturerSourceForTesting(capturer_source_, params_); scoped_refptr adapter( WebRtcLocalAudioTrackAdapter::Create(std::string(), NULL)); track_.reset(new WebRtcLocalAudioTrack(adapter, capturer_, NULL)); track_->Start(); // Connect a mock sink to the track. scoped_ptr sink( new MockPeerConnectionAudioSink()); track_->AddSink(sink.get()); int delay_ms = 65; bool key_pressed = true; double volume = 0.9; // MaxVolume() in WebRtcAudioCapturer is hard-coded to return 255, we add // 0.5 to do the correct truncation like the production code does. int expected_volume_value = volume * capturer_->MaxVolume() + 0.5; scoped_ptr audio_bus = media::AudioBus::Create(params_); audio_bus->Zero(); media::AudioCapturerSource::CaptureCallback* callback = static_cast(capturer_); // Verify the sink is getting the correct values. EXPECT_CALL(*sink, FormatIsSet()); EXPECT_CALL(*sink, OnDataCallback(_, _, delay_ms, expected_volume_value, need_audio_processing, key_pressed)); callback->Capture(audio_bus.get(), delay_ms, volume, key_pressed); // Verify the cached values in the capturer fits what we expect. base::TimeDelta cached_delay; int cached_volume = !expected_volume_value; bool cached_key_pressed = !key_pressed; capturer_->GetAudioProcessingParams(&cached_delay, &cached_volume, &cached_key_pressed); EXPECT_EQ(cached_delay.InMilliseconds(), delay_ms); EXPECT_EQ(cached_volume, expected_volume_value); EXPECT_EQ(cached_key_pressed, key_pressed); track_->RemoveSink(sink.get()); EXPECT_CALL(*capturer_source_.get(), Stop()); capturer_->Stop(); } media::AudioParameters params_; scoped_refptr capturer_source_; scoped_refptr capturer_; scoped_ptr track_; }; // Pass the delay value, volume and key_pressed info via capture callback, and // those values should be correctly stored and passed to the track. TEST_F(WebRtcAudioCapturerTest, VerifyAudioParams) { // Use constraints with default settings. MockMediaConstraintFactory constraint_factory; VerifyAudioParams(constraint_factory.CreateWebMediaConstraints(), true); } TEST_F(WebRtcAudioCapturerTest, VerifyAudioParamsWithAudioProcessing) { EnableAudioTrackProcessing(); // Turn off the default constraints to verify that the sink will get packets // with a buffer size smaller than 10ms. MockMediaConstraintFactory constraint_factory; constraint_factory.DisableDefaultAudioConstraints(); VerifyAudioParams(constraint_factory.CreateWebMediaConstraints(), false); } TEST_F(WebRtcAudioCapturerTest, FailToCreateCapturerWithWrongConstraints) { EnableAudioTrackProcessing(); MockMediaConstraintFactory constraint_factory; const std::string dummy_constraint = "dummy"; constraint_factory.AddMandatory(dummy_constraint, true); scoped_refptr 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 == NULL); } } // namespace content