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/logging.h" 6 #include "content/renderer/media/rtc_media_constraints.h" 7 #include "content/renderer/media/webrtc_audio_capturer.h" 8 #include "content/renderer/media/webrtc_local_audio_track.h" 9 #include "media/audio/audio_parameters.h" 10 #include "media/base/audio_bus.h" 11 #include "testing/gmock/include/gmock/gmock.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 14 using ::testing::_; 15 using ::testing::AtLeast; 16 17 namespace content { 18 19 namespace { 20 21 // TODO(xians): Consolidate the similar methods in different unittests into 22 // one. 23 void ApplyFixedAudioConstraints(RTCMediaConstraints* constraints) { 24 // Constant constraint keys which enables default audio constraints on 25 // mediastreams with audio. 26 struct { 27 const char* key; 28 const char* value; 29 } static const kDefaultAudioConstraints[] = { 30 { webrtc::MediaConstraintsInterface::kEchoCancellation, 31 webrtc::MediaConstraintsInterface::kValueTrue }, 32 #if defined(OS_CHROMEOS) || defined(OS_MACOSX) 33 // Enable the extended filter mode AEC on platforms with known echo issues. 34 { webrtc::MediaConstraintsInterface::kExperimentalEchoCancellation, 35 webrtc::MediaConstraintsInterface::kValueTrue }, 36 #endif 37 { webrtc::MediaConstraintsInterface::kAutoGainControl, 38 webrtc::MediaConstraintsInterface::kValueTrue }, 39 { webrtc::MediaConstraintsInterface::kExperimentalAutoGainControl, 40 webrtc::MediaConstraintsInterface::kValueTrue }, 41 { webrtc::MediaConstraintsInterface::kNoiseSuppression, 42 webrtc::MediaConstraintsInterface::kValueTrue }, 43 { webrtc::MediaConstraintsInterface::kHighpassFilter, 44 webrtc::MediaConstraintsInterface::kValueTrue }, 45 }; 46 47 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kDefaultAudioConstraints); ++i) { 48 constraints->AddMandatory(kDefaultAudioConstraints[i].key, 49 kDefaultAudioConstraints[i].value, false); 50 } 51 } 52 53 class MockCapturerSource : public media::AudioCapturerSource { 54 public: 55 MockCapturerSource() {} 56 MOCK_METHOD3(Initialize, void(const media::AudioParameters& params, 57 CaptureCallback* callback, 58 int session_id)); 59 MOCK_METHOD0(Start, void()); 60 MOCK_METHOD0(Stop, void()); 61 MOCK_METHOD1(SetVolume, void(double volume)); 62 MOCK_METHOD1(SetAutomaticGainControl, void(bool enable)); 63 64 protected: 65 virtual ~MockCapturerSource() {} 66 }; 67 68 class MockPeerConnectionAudioSink : public PeerConnectionAudioSink { 69 public: 70 MockPeerConnectionAudioSink() {} 71 ~MockPeerConnectionAudioSink() {} 72 MOCK_METHOD9(OnData, int(const int16* audio_data, 73 int sample_rate, 74 int number_of_channels, 75 int number_of_frames, 76 const std::vector<int>& channels, 77 int audio_delay_milliseconds, 78 int current_volume, 79 bool need_audio_processing, 80 bool key_pressed)); 81 MOCK_METHOD1(OnSetFormat, void(const media::AudioParameters& params)); 82 }; 83 84 } // namespace 85 86 class WebRtcAudioCapturerTest : public testing::Test { 87 protected: 88 WebRtcAudioCapturerTest() 89 #if defined(OS_ANDROID) 90 : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 91 media::CHANNEL_LAYOUT_STEREO, 48000, 16, 960) { 92 // Android works with a buffer size bigger than 20ms. 93 #else 94 : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 95 media::CHANNEL_LAYOUT_STEREO, 48000, 16, 128) { 96 #endif 97 capturer_ = WebRtcAudioCapturer::CreateCapturer(); 98 capturer_->Initialize(-1, params_.channel_layout(), params_.sample_rate(), 99 params_.frames_per_buffer(), 0, std::string(), 0, 0, 100 params_.effects()); 101 capturer_source_ = new MockCapturerSource(); 102 EXPECT_CALL(*capturer_source_.get(), Initialize(_, capturer_.get(), 0)); 103 capturer_->SetCapturerSource(capturer_source_, 104 params_.channel_layout(), 105 params_.sample_rate(), 106 params_.effects()); 107 108 EXPECT_CALL(*capturer_source_.get(), SetAutomaticGainControl(true)); 109 EXPECT_CALL(*capturer_source_.get(), Start()); 110 RTCMediaConstraints constraints; 111 ApplyFixedAudioConstraints(&constraints); 112 track_ = WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL, 113 NULL, &constraints); 114 static_cast<WebRtcLocalAudioSourceProvider*>( 115 track_->audio_source_provider())->SetSinkParamsForTesting(params_); 116 track_->Start(); 117 EXPECT_TRUE(track_->enabled()); 118 } 119 120 media::AudioParameters params_; 121 scoped_refptr<MockCapturerSource> capturer_source_; 122 scoped_refptr<WebRtcAudioCapturer> capturer_; 123 scoped_refptr<WebRtcLocalAudioTrack> track_; 124 }; 125 126 // Pass the delay value, vollume and key_pressed info via capture callback, and 127 // those values should be correctly stored and passed to the track. 128 TEST_F(WebRtcAudioCapturerTest, VerifyAudioParams) { 129 // Connect a mock sink to the track. 130 scoped_ptr<MockPeerConnectionAudioSink> sink( 131 new MockPeerConnectionAudioSink()); 132 track_->AddSink(sink.get()); 133 134 int delay_ms = 65; 135 bool key_pressed = true; 136 double volume = 0.9; 137 // MaxVolume() in WebRtcAudioCapturer is hard-coded to return 255, we add 0.5 138 // to do the correct truncation as how the production code does. 139 int expected_volume_value = volume * capturer_->MaxVolume() + 0.5; 140 scoped_ptr<media::AudioBus> audio_bus = media::AudioBus::Create(params_); 141 audio_bus->Zero(); 142 #if defined(OS_ANDROID) 143 const int expected_buffer_size = params_.sample_rate() / 100; 144 #else 145 const int expected_buffer_size = params_.frames_per_buffer(); 146 #endif 147 bool expected_need_audio_processing = true; 148 media::AudioCapturerSource::CaptureCallback* callback = 149 static_cast<media::AudioCapturerSource::CaptureCallback*>(capturer_); 150 // Verify the sink is getting the correct values. 151 EXPECT_CALL(*sink, OnSetFormat(_)); 152 EXPECT_CALL(*sink, 153 OnData(_, params_.sample_rate(), params_.channels(), 154 expected_buffer_size, _, delay_ms, 155 expected_volume_value, expected_need_audio_processing, 156 key_pressed)).Times(AtLeast(1)); 157 callback->Capture(audio_bus.get(), delay_ms, volume, key_pressed); 158 159 // Verify the cached values in the capturer fits what we expect. 160 base::TimeDelta cached_delay; 161 int cached_volume = !expected_volume_value; 162 bool cached_key_pressed = !key_pressed; 163 capturer_->GetAudioProcessingParams(&cached_delay, &cached_volume, 164 &cached_key_pressed); 165 EXPECT_EQ(cached_delay.InMilliseconds(), delay_ms); 166 EXPECT_EQ(cached_volume, expected_volume_value); 167 EXPECT_EQ(cached_key_pressed, key_pressed); 168 169 track_->RemoveSink(sink.get()); 170 EXPECT_CALL(*capturer_source_.get(), Stop()); 171 capturer_->Stop(); 172 } 173 174 } // namespace content 175