OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/environment.h" | 5 #include "base/environment.h" |
6 #include "base/test/test_timeouts.h" | 6 #include "base/test/test_timeouts.h" |
7 #include "content/renderer/media/webrtc_audio_device_impl.h" | 7 #include "content/renderer/media/webrtc_audio_device_impl.h" |
8 #include "content/test/webrtc_audio_device_test.h" | 8 #include "content/test/webrtc_audio_device_test.h" |
9 #include "media/audio/audio_util.h" | 9 #include "media/audio/audio_util.h" |
10 #include "testing/gmock/include/gmock/gmock.h" | 10 #include "testing/gmock/include/gmock/gmock.h" |
11 #include "third_party/webrtc/voice_engine/main/interface/voe_audio_processing.h" | 11 #include "third_party/webrtc/voice_engine/main/interface/voe_audio_processing.h" |
12 #include "third_party/webrtc/voice_engine/main/interface/voe_base.h" | 12 #include "third_party/webrtc/voice_engine/main/interface/voe_base.h" |
| 13 #include "third_party/webrtc/voice_engine/main/interface/voe_external_media.h" |
13 #include "third_party/webrtc/voice_engine/main/interface/voe_file.h" | 14 #include "third_party/webrtc/voice_engine/main/interface/voe_file.h" |
14 #include "third_party/webrtc/voice_engine/main/interface/voe_network.h" | 15 #include "third_party/webrtc/voice_engine/main/interface/voe_network.h" |
15 | 16 |
16 using testing::_; | 17 using testing::_; |
17 using testing::InvokeWithoutArgs; | 18 using testing::InvokeWithoutArgs; |
18 using testing::Return; | 19 using testing::Return; |
19 using testing::StrEq; | 20 using testing::StrEq; |
20 | 21 |
21 namespace { | 22 namespace { |
22 | 23 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 DISALLOW_COPY_AND_ASSIGN(AudioUtilNoHardware); | 58 DISALLOW_COPY_AND_ASSIGN(AudioUtilNoHardware); |
58 }; | 59 }; |
59 | 60 |
60 bool IsRunningHeadless() { | 61 bool IsRunningHeadless() { |
61 scoped_ptr<base::Environment> env(base::Environment::Create()); | 62 scoped_ptr<base::Environment> env(base::Environment::Create()); |
62 if (env->HasVar("CHROME_HEADLESS")) | 63 if (env->HasVar("CHROME_HEADLESS")) |
63 return true; | 64 return true; |
64 return false; | 65 return false; |
65 } | 66 } |
66 | 67 |
| 68 class WebRTCMediaProcessImpl : public webrtc::VoEMediaProcess { |
| 69 public: |
| 70 explicit WebRTCMediaProcessImpl(base::WaitableEvent* event) |
| 71 : event_(event), |
| 72 channel_id_(-1), |
| 73 type_(webrtc::kPlaybackPerChannel), |
| 74 packet_size_(0), |
| 75 sample_rate_(0), |
| 76 channels_(0) { |
| 77 } |
| 78 virtual ~WebRTCMediaProcessImpl() {} |
| 79 |
| 80 // TODO(henrika): Refactor in WebRTC and convert to Chrome coding style. |
| 81 virtual void Process(const int channel, |
| 82 const webrtc::ProcessingTypes type, |
| 83 WebRtc_Word16 audio_10ms[], |
| 84 const int length, |
| 85 const int sampling_freq, |
| 86 const bool is_stereo) { |
| 87 channel_id_ = channel; |
| 88 type_ = type; |
| 89 packet_size_ = length; |
| 90 sample_rate_ = sampling_freq; |
| 91 channels_ = (is_stereo ? 2 : 1); |
| 92 if (event_) { |
| 93 // Signal that a new callback has been received. |
| 94 event_->Signal(); |
| 95 } |
| 96 } |
| 97 |
| 98 int channel_id() const { return channel_id_; } |
| 99 int type() const { return type_; } |
| 100 int packet_size() const { return packet_size_; } |
| 101 int sample_rate() const { return sample_rate_; } |
| 102 int channels() const { return channels_; } |
| 103 |
| 104 private: |
| 105 base::WaitableEvent* event_; |
| 106 int channel_id_; |
| 107 webrtc::ProcessingTypes type_; |
| 108 int packet_size_; |
| 109 int sample_rate_; |
| 110 int channels_; |
| 111 DISALLOW_COPY_AND_ASSIGN(WebRTCMediaProcessImpl); |
| 112 }; |
| 113 |
67 } // end namespace | 114 } // end namespace |
68 | 115 |
69 // Basic test that instantiates and initializes an instance of | 116 // Basic test that instantiates and initializes an instance of |
70 // WebRtcAudioDeviceImpl. | 117 // WebRtcAudioDeviceImpl. |
71 TEST_F(WebRTCAudioDeviceTest, Construct) { | 118 TEST_F(WebRTCAudioDeviceTest, Construct) { |
72 AudioUtilNoHardware audio_util(48000.0, 48000.0); | 119 AudioUtilNoHardware audio_util(48000.0, 48000.0); |
73 set_audio_util_callback(&audio_util); | 120 set_audio_util_callback(&audio_util); |
74 scoped_refptr<WebRtcAudioDeviceImpl> audio_device( | 121 scoped_refptr<WebRtcAudioDeviceImpl> audio_device( |
75 new WebRtcAudioDeviceImpl()); | 122 new WebRtcAudioDeviceImpl()); |
76 audio_device->SetSessionId(1); | 123 audio_device->SetSessionId(1); |
77 | 124 |
78 WebRTCAutoDelete<webrtc::VoiceEngine> engine(webrtc::VoiceEngine::Create()); | 125 WebRTCAutoDelete<webrtc::VoiceEngine> engine(webrtc::VoiceEngine::Create()); |
79 ASSERT_TRUE(engine.valid()); | 126 ASSERT_TRUE(engine.valid()); |
80 | 127 |
81 ScopedWebRTCPtr<webrtc::VoEBase> base(engine.get()); | 128 ScopedWebRTCPtr<webrtc::VoEBase> base(engine.get()); |
82 int err = base->Init(audio_device); | 129 int err = base->Init(audio_device); |
83 EXPECT_EQ(0, err); | 130 EXPECT_EQ(0, err); |
84 EXPECT_EQ(0, base->Terminate()); | 131 EXPECT_EQ(0, base->Terminate()); |
85 } | 132 } |
86 | 133 |
| 134 // Verify that a call to webrtc::VoEBase::StartPlayout() starts audio output |
| 135 // with the correct set of parameters. A WebRtcAudioDeviceImpl instance will |
| 136 // be utilized to implement the actual audio path. The test registers a |
| 137 // webrtc::VoEExternalMedia implementation to hijack the output audio and |
| 138 // verify that streaming starts correctly. |
| 139 // Disabled when running headless since the bots don't have the required config. |
| 140 TEST_F(WebRTCAudioDeviceTest, StartPlayout) { |
| 141 if (IsRunningHeadless()) |
| 142 return; |
| 143 |
| 144 AudioUtil audio_util; |
| 145 set_audio_util_callback(&audio_util); |
| 146 |
| 147 EXPECT_CALL(media_observer(), |
| 148 OnSetAudioStreamStatus(_, 1, StrEq("created"))).Times(1); |
| 149 EXPECT_CALL(media_observer(), |
| 150 OnSetAudioStreamPlaying(_, 1, true)).Times(1); |
| 151 EXPECT_CALL(media_observer(), |
| 152 OnSetAudioStreamStatus(_, 1, StrEq("closed"))).Times(1); |
| 153 EXPECT_CALL(media_observer(), |
| 154 OnDeleteAudioStream(_, 1)).Times(1); |
| 155 |
| 156 scoped_refptr<WebRtcAudioDeviceImpl> audio_device( |
| 157 new WebRtcAudioDeviceImpl()); |
| 158 audio_device->SetSessionId(1); |
| 159 WebRTCAutoDelete<webrtc::VoiceEngine> engine(webrtc::VoiceEngine::Create()); |
| 160 ASSERT_TRUE(engine.valid()); |
| 161 |
| 162 ScopedWebRTCPtr<webrtc::VoEBase> base(engine.get()); |
| 163 ASSERT_TRUE(base.valid()); |
| 164 int err = base->Init(audio_device); |
| 165 ASSERT_EQ(0, err); |
| 166 |
| 167 int ch = base->CreateChannel(); |
| 168 EXPECT_NE(-1, ch); |
| 169 |
| 170 ScopedWebRTCPtr<webrtc::VoEExternalMedia> external_media(engine.get()); |
| 171 ASSERT_TRUE(external_media.valid()); |
| 172 |
| 173 base::WaitableEvent event(false, false); |
| 174 scoped_ptr<WebRTCMediaProcessImpl> media_process( |
| 175 new WebRTCMediaProcessImpl(&event)); |
| 176 EXPECT_EQ(0, external_media->RegisterExternalMediaProcessing( |
| 177 ch, webrtc::kPlaybackPerChannel, *media_process.get())); |
| 178 |
| 179 EXPECT_EQ(0, base->StartPlayout(ch)); |
| 180 |
| 181 EXPECT_TRUE(event.TimedWait( |
| 182 base::TimeDelta::FromMilliseconds(TestTimeouts::action_timeout_ms()))); |
| 183 WaitForIOThreadCompletion(); |
| 184 |
| 185 EXPECT_TRUE(audio_device->playing()); |
| 186 EXPECT_FALSE(audio_device->recording()); |
| 187 EXPECT_EQ(ch, media_process->channel_id()); |
| 188 EXPECT_EQ(webrtc::kPlaybackPerChannel, media_process->type()); |
| 189 EXPECT_EQ(80, media_process->packet_size()); |
| 190 EXPECT_EQ(8000, media_process->sample_rate()); |
| 191 |
| 192 EXPECT_EQ(0, external_media->DeRegisterExternalMediaProcessing( |
| 193 ch, webrtc::kPlaybackPerChannel)); |
| 194 EXPECT_EQ(0, base->StopPlayout(ch)); |
| 195 |
| 196 EXPECT_EQ(0, base->DeleteChannel(ch)); |
| 197 EXPECT_EQ(0, base->Terminate()); |
| 198 } |
| 199 |
| 200 // Verify that a call to webrtc::VoEBase::StartRecording() starts audio input |
| 201 // with the correct set of parameters. A WebRtcAudioDeviceImpl instance will |
| 202 // be utilized to implement the actual audio path. The test registers a |
| 203 // webrtc::VoEExternalMedia implementation to hijack the input audio and |
| 204 // verify that streaming starts correctly. An external transport implementation |
| 205 // is also required to ensure that "sending" can start without actually trying |
| 206 // to send encoded packets to the network. Our main interest here is to ensure |
| 207 // that the audio capturing starts as it should. |
| 208 // Disabled when running headless since the bots don't have the required config. |
| 209 TEST_F(WebRTCAudioDeviceTest, StartRecording) { |
| 210 if (IsRunningHeadless()) |
| 211 return; |
| 212 |
| 213 AudioUtil audio_util; |
| 214 set_audio_util_callback(&audio_util); |
| 215 |
| 216 // TODO(tommi): extend MediaObserver and MockMediaObserver with support |
| 217 // for new interfaces, like OnSetAudioStreamRecording(). When done, add |
| 218 // EXPECT_CALL() macros here. |
| 219 |
| 220 scoped_refptr<WebRtcAudioDeviceImpl> audio_device( |
| 221 new WebRtcAudioDeviceImpl()); |
| 222 audio_device->SetSessionId(1); |
| 223 WebRTCAutoDelete<webrtc::VoiceEngine> engine(webrtc::VoiceEngine::Create()); |
| 224 ASSERT_TRUE(engine.valid()); |
| 225 |
| 226 ScopedWebRTCPtr<webrtc::VoEBase> base(engine.get()); |
| 227 ASSERT_TRUE(base.valid()); |
| 228 int err = base->Init(audio_device); |
| 229 ASSERT_EQ(0, err); |
| 230 |
| 231 int ch = base->CreateChannel(); |
| 232 EXPECT_NE(-1, ch); |
| 233 |
| 234 ScopedWebRTCPtr<webrtc::VoEExternalMedia> external_media(engine.get()); |
| 235 ASSERT_TRUE(external_media.valid()); |
| 236 |
| 237 base::WaitableEvent event(false, false); |
| 238 scoped_ptr<WebRTCMediaProcessImpl> media_process( |
| 239 new WebRTCMediaProcessImpl(&event)); |
| 240 EXPECT_EQ(0, external_media->RegisterExternalMediaProcessing( |
| 241 ch, webrtc::kRecordingPerChannel, *media_process.get())); |
| 242 |
| 243 // We must add an external transport implementation to be able to start |
| 244 // recording without actually sending encoded packets to the network. All |
| 245 // we want to do here is to verify that audio capturing starts as it should. |
| 246 ScopedWebRTCPtr<webrtc::VoENetwork> network(engine.get()); |
| 247 scoped_ptr<WebRTCTransportImpl> transport( |
| 248 new WebRTCTransportImpl(network.get())); |
| 249 EXPECT_EQ(0, network->RegisterExternalTransport(ch, *transport.get())); |
| 250 EXPECT_EQ(0, base->StartSend(ch)); |
| 251 |
| 252 EXPECT_TRUE(event.TimedWait( |
| 253 base::TimeDelta::FromMilliseconds(TestTimeouts::action_timeout_ms()))); |
| 254 WaitForIOThreadCompletion(); |
| 255 |
| 256 EXPECT_FALSE(audio_device->playing()); |
| 257 EXPECT_TRUE(audio_device->recording()); |
| 258 EXPECT_EQ(ch, media_process->channel_id()); |
| 259 EXPECT_EQ(webrtc::kRecordingPerChannel, media_process->type()); |
| 260 EXPECT_EQ(80, media_process->packet_size()); |
| 261 EXPECT_EQ(8000, media_process->sample_rate()); |
| 262 |
| 263 EXPECT_EQ(0, external_media->DeRegisterExternalMediaProcessing( |
| 264 ch, webrtc::kRecordingPerChannel)); |
| 265 EXPECT_EQ(0, base->StopSend(ch)); |
| 266 |
| 267 EXPECT_EQ(0, base->DeleteChannel(ch)); |
| 268 EXPECT_EQ(0, base->Terminate()); |
| 269 } |
| 270 |
87 // Uses WebRtcAudioDeviceImpl to play a local wave file. | 271 // Uses WebRtcAudioDeviceImpl to play a local wave file. |
88 // Disabled when running headless since the bots don't have the required config. | 272 // Disabled when running headless since the bots don't have the required config. |
89 TEST_F(WebRTCAudioDeviceTest, PlayLocalFile) { | 273 TEST_F(WebRTCAudioDeviceTest, PlayLocalFile) { |
90 if (IsRunningHeadless()) | 274 if (IsRunningHeadless()) |
91 return; | 275 return; |
92 | 276 |
93 std::string file_path( | 277 std::string file_path( |
94 GetTestDataPath(FILE_PATH_LITERAL("speechmusic_mono_16kHz.pcm"))); | 278 GetTestDataPath(FILE_PATH_LITERAL("speechmusic_mono_16kHz.pcm"))); |
95 | 279 |
96 AudioUtil audio_util; | 280 AudioUtil audio_util; |
(...skipping 24 matching lines...) Expand all Loading... |
121 EXPECT_NE(-1, ch); | 305 EXPECT_NE(-1, ch); |
122 EXPECT_EQ(0, base->StartPlayout(ch)); | 306 EXPECT_EQ(0, base->StartPlayout(ch)); |
123 | 307 |
124 ScopedWebRTCPtr<webrtc::VoEFile> file(engine.get()); | 308 ScopedWebRTCPtr<webrtc::VoEFile> file(engine.get()); |
125 int duration = 0; | 309 int duration = 0; |
126 EXPECT_EQ(0, file->GetFileDuration(file_path.c_str(), duration, | 310 EXPECT_EQ(0, file->GetFileDuration(file_path.c_str(), duration, |
127 webrtc::kFileFormatPcm16kHzFile)); | 311 webrtc::kFileFormatPcm16kHzFile)); |
128 EXPECT_NE(0, duration); | 312 EXPECT_NE(0, duration); |
129 | 313 |
130 EXPECT_EQ(0, file->StartPlayingFileLocally(ch, file_path.c_str(), false, | 314 EXPECT_EQ(0, file->StartPlayingFileLocally(ch, file_path.c_str(), false, |
131 webrtc::kFileFormatPcm16kHzFile)); | 315 webrtc::kFileFormatPcm16kHzFile)); |
132 | 316 |
133 message_loop_.PostDelayedTask(FROM_HERE, | 317 message_loop_.PostDelayedTask(FROM_HERE, |
134 new MessageLoop::QuitTask(), | 318 new MessageLoop::QuitTask(), |
135 TestTimeouts::action_timeout_ms()); | 319 TestTimeouts::action_timeout_ms()); |
136 message_loop_.Run(); | 320 message_loop_.Run(); |
137 | 321 |
138 EXPECT_EQ(0, base->Terminate()); | 322 EXPECT_EQ(0, base->Terminate()); |
139 } | 323 } |
| 324 |
| 325 // Uses WebRtcAudioDeviceImpl to play out recorded audio in loopback. |
| 326 // An external transport implementation is utilized to feed back RTP packets |
| 327 // which are recorded, encoded, packetized into RTP packets and finally |
| 328 // "transmitted". The RTP packets are then fed back into the VoiceEngine |
| 329 // where they are decoded and played out on the default audio output device. |
| 330 // Disabled when running headless since the bots don't have the required config. |
| 331 // TODO(henrika): improve quality by using a wideband codec, enabling noise- |
| 332 // suppressions and perhaps also the digital AGC. |
| 333 TEST_F(WebRTCAudioDeviceTest, FullDuplexAudio) { |
| 334 if (IsRunningHeadless()) |
| 335 return; |
| 336 |
| 337 AudioUtil audio_util; |
| 338 set_audio_util_callback(&audio_util); |
| 339 |
| 340 scoped_refptr<WebRtcAudioDeviceImpl> audio_device( |
| 341 new WebRtcAudioDeviceImpl()); |
| 342 audio_device->SetSessionId(1); |
| 343 WebRTCAutoDelete<webrtc::VoiceEngine> engine(webrtc::VoiceEngine::Create()); |
| 344 ASSERT_TRUE(engine.valid()); |
| 345 |
| 346 ScopedWebRTCPtr<webrtc::VoEBase> base(engine.get()); |
| 347 ASSERT_TRUE(base.valid()); |
| 348 int err = base->Init(audio_device); |
| 349 ASSERT_EQ(0, err); |
| 350 |
| 351 int ch = base->CreateChannel(); |
| 352 EXPECT_NE(-1, ch); |
| 353 |
| 354 ScopedWebRTCPtr<webrtc::VoENetwork> network(engine.get()); |
| 355 scoped_ptr<WebRTCTransportImpl> transport( |
| 356 new WebRTCTransportImpl(network.get())); |
| 357 EXPECT_EQ(0, network->RegisterExternalTransport(ch, *transport.get())); |
| 358 EXPECT_EQ(0, base->StartPlayout(ch)); |
| 359 EXPECT_EQ(0, base->StartSend(ch)); |
| 360 |
| 361 LOG(INFO) << ">> You should now be able to hear yourself in loopback..."; |
| 362 message_loop_.PostDelayedTask(FROM_HERE, |
| 363 new MessageLoop::QuitTask(), |
| 364 TestTimeouts::action_timeout_ms()); |
| 365 message_loop_.Run(); |
| 366 |
| 367 EXPECT_EQ(0, base->StopSend(ch)); |
| 368 EXPECT_EQ(0, base->StopPlayout(ch)); |
| 369 |
| 370 EXPECT_EQ(0, base->DeleteChannel(ch)); |
| 371 EXPECT_EQ(0, base->Terminate()); |
| 372 } |
OLD | NEW |