1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/command_line.h" 6 #include "base/logging.h" 7 #include "content/public/common/content_switches.h" 8 #include "content/renderer/media/mock_media_constraint_factory.h" 9 #include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h" 10 #include "content/renderer/media/webrtc_audio_capturer.h" 11 #include "content/renderer/media/webrtc_local_audio_track.h" 12 #include "media/audio/audio_parameters.h" 13 #include "media/base/audio_bus.h" 14 #include "testing/gmock/include/gmock/gmock.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" 17 18 using ::testing::_; 19 using ::testing::AtLeast; 20 21 namespace content { 22 23 namespace { 24 25 class MockCapturerSource : public media::AudioCapturerSource { 26 public: 27 MockCapturerSource() {} 28 MOCK_METHOD3(Initialize, void(const media::AudioParameters& params, 29 CaptureCallback* callback, 30 int session_id)); 31 MOCK_METHOD0(Start, void()); 32 MOCK_METHOD0(Stop, void()); 33 MOCK_METHOD1(SetVolume, void(double volume)); 34 MOCK_METHOD1(SetAutomaticGainControl, void(bool enable)); 35 36 protected: 37 virtual ~MockCapturerSource() {} 38 }; 39 40 class MockPeerConnectionAudioSink : public PeerConnectionAudioSink { 41 public: 42 MockPeerConnectionAudioSink() {} 43 ~MockPeerConnectionAudioSink() {} 44 virtual int OnData(const int16* audio_data, int sample_rate, 45 int number_of_channels, int number_of_frames, 46 const std::vector<int>& channels, 47 int audio_delay_milliseconds, int current_volume, 48 bool need_audio_processing, bool key_pressed) OVERRIDE { 49 EXPECT_EQ(sample_rate, params_.sample_rate()); 50 EXPECT_EQ(number_of_channels, params_.channels()); 51 EXPECT_EQ(number_of_frames, params_.frames_per_buffer()); 52 OnDataCallback(audio_data, channels, audio_delay_milliseconds, 53 current_volume, need_audio_processing, key_pressed); 54 return 0; 55 } 56 MOCK_METHOD6(OnDataCallback, void(const int16* audio_data, 57 const std::vector<int>& channels, 58 int audio_delay_milliseconds, 59 int current_volume, 60 bool need_audio_processing, 61 bool key_pressed)); 62 virtual void OnSetFormat(const media::AudioParameters& params) OVERRIDE { 63 params_ = params; 64 FormatIsSet(); 65 } 66 MOCK_METHOD0(FormatIsSet, void()); 67 68 private: 69 media::AudioParameters params_; 70 }; 71 72 } // namespace 73 74 class WebRtcAudioCapturerTest : public testing::Test { 75 protected: 76 WebRtcAudioCapturerTest() 77 #if defined(OS_ANDROID) 78 : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 79 media::CHANNEL_LAYOUT_STEREO, 48000, 16, 960) { 80 // Android works with a buffer size bigger than 20ms. 81 #else 82 : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 83 media::CHANNEL_LAYOUT_STEREO, 48000, 16, 128) { 84 #endif 85 } 86 87 void DisableAudioTrackProcessing() { 88 CommandLine::ForCurrentProcess()->AppendSwitch( 89 switches::kDisableAudioTrackProcessing); 90 } 91 92 void VerifyAudioParams(const blink::WebMediaConstraints& constraints, 93 bool need_audio_processing) { 94 capturer_ = WebRtcAudioCapturer::CreateCapturer( 95 -1, StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE, 96 "", "", params_.sample_rate(), 97 params_.channel_layout(), 98 params_.frames_per_buffer()), 99 constraints, NULL, NULL); 100 capturer_source_ = new MockCapturerSource(); 101 EXPECT_CALL(*capturer_source_.get(), Initialize(_, capturer_.get(), -1)); 102 EXPECT_CALL(*capturer_source_.get(), SetAutomaticGainControl(true)); 103 EXPECT_CALL(*capturer_source_.get(), Start()); 104 capturer_->SetCapturerSourceForTesting(capturer_source_, params_); 105 106 scoped_refptr<WebRtcLocalAudioTrackAdapter> adapter( 107 WebRtcLocalAudioTrackAdapter::Create(std::string(), NULL)); 108 track_.reset(new WebRtcLocalAudioTrack(adapter.get(), capturer_, NULL)); 109 track_->Start(); 110 111 // Connect a mock sink to the track. 112 scoped_ptr<MockPeerConnectionAudioSink> sink( 113 new MockPeerConnectionAudioSink()); 114 track_->AddSink(sink.get()); 115 116 int delay_ms = 65; 117 bool key_pressed = true; 118 double volume = 0.9; 119 120 // MaxVolume() in WebRtcAudioCapturer is hard-coded to return 255, we add 121 // 0.5 to do the correct truncation like the production code does. 122 int expected_volume_value = volume * capturer_->MaxVolume() + 0.5; 123 scoped_ptr<media::AudioBus> audio_bus = media::AudioBus::Create(params_); 124 audio_bus->Zero(); 125 126 media::AudioCapturerSource::CaptureCallback* callback = 127 static_cast<media::AudioCapturerSource::CaptureCallback*>( 128 capturer_.get()); 129 130 // Verify the sink is getting the correct values. 131 EXPECT_CALL(*sink, FormatIsSet()); 132 EXPECT_CALL(*sink, 133 OnDataCallback(_, _, delay_ms, expected_volume_value, 134 need_audio_processing, key_pressed)) 135 .Times(AtLeast(1)); 136 callback->Capture(audio_bus.get(), delay_ms, volume, key_pressed); 137 138 // Verify the cached values in the capturer fits what we expect. 139 base::TimeDelta cached_delay; 140 int cached_volume = !expected_volume_value; 141 bool cached_key_pressed = !key_pressed; 142 capturer_->GetAudioProcessingParams(&cached_delay, &cached_volume, 143 &cached_key_pressed); 144 EXPECT_EQ(cached_delay.InMilliseconds(), delay_ms); 145 EXPECT_EQ(cached_volume, expected_volume_value); 146 EXPECT_EQ(cached_key_pressed, key_pressed); 147 148 track_->RemoveSink(sink.get()); 149 EXPECT_CALL(*capturer_source_.get(), Stop()); 150 capturer_->Stop(); 151 } 152 153 media::AudioParameters params_; 154 scoped_refptr<MockCapturerSource> capturer_source_; 155 scoped_refptr<WebRtcAudioCapturer> capturer_; 156 scoped_ptr<WebRtcLocalAudioTrack> track_; 157 }; 158 159 // Pass the delay value, volume and key_pressed info via capture callback, and 160 // those values should be correctly stored and passed to the track. 161 TEST_F(WebRtcAudioCapturerTest, VerifyAudioParamsWithoutAudioProcessing) { 162 DisableAudioTrackProcessing(); 163 // Use constraints with default settings. 164 MockMediaConstraintFactory constraint_factory; 165 VerifyAudioParams(constraint_factory.CreateWebMediaConstraints(), true); 166 } 167 168 TEST_F(WebRtcAudioCapturerTest, VerifyAudioParamsWithAudioProcessing) { 169 // Turn off the default constraints to verify that the sink will get packets 170 // with a buffer size smaller than 10ms. 171 MockMediaConstraintFactory constraint_factory; 172 constraint_factory.DisableDefaultAudioConstraints(); 173 VerifyAudioParams(constraint_factory.CreateWebMediaConstraints(), false); 174 } 175 176 TEST_F(WebRtcAudioCapturerTest, FailToCreateCapturerWithWrongConstraints) { 177 MockMediaConstraintFactory constraint_factory; 178 const std::string dummy_constraint = "dummy"; 179 constraint_factory.AddMandatory(dummy_constraint, true); 180 181 scoped_refptr<WebRtcAudioCapturer> capturer( 182 WebRtcAudioCapturer::CreateCapturer( 183 0, StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE, 184 "", "", params_.sample_rate(), 185 params_.channel_layout(), 186 params_.frames_per_buffer()), 187 constraint_factory.CreateWebMediaConstraints(), NULL, NULL) 188 ); 189 EXPECT_TRUE(capturer.get() == NULL); 190 } 191 192 193 } // namespace content 194