webrtc_local_audio_track_unittest.cc revision 3551c9c881056c480085172ff9840cab31610854
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/synchronization/waitable_event.h" 6#include "base/test/test_timeouts.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 "media/base/audio_capturer_source.h" 12#include "testing/gmock/include/gmock/gmock.h" 13#include "testing/gtest/include/gtest/gtest.h" 14#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h" 15 16using ::testing::_; 17using ::testing::AnyNumber; 18using ::testing::AtLeast; 19using ::testing::Return; 20 21namespace content { 22 23namespace { 24 25ACTION_P(SignalEvent, event) { 26 event->Signal(); 27} 28 29// A simple thread that we use to fake the audio thread which provides data to 30// the |WebRtcAudioCapturer|. 31class FakeAudioThread : public base::PlatformThread::Delegate { 32 public: 33 explicit FakeAudioThread(const scoped_refptr<WebRtcAudioCapturer>& capturer) 34 : capturer_(capturer), 35 thread_(), 36 closure_(false, false) { 37 DCHECK(capturer.get()); 38 audio_bus_ = media::AudioBus::Create(capturer_->audio_parameters()); 39 } 40 41 virtual ~FakeAudioThread() { DCHECK(thread_.is_null()); } 42 43 // base::PlatformThread::Delegate: 44 virtual void ThreadMain() OVERRIDE { 45 while (true) { 46 if (closure_.IsSignaled()) 47 return; 48 49 media::AudioCapturerSource::CaptureCallback* callback = 50 static_cast<media::AudioCapturerSource::CaptureCallback*>( 51 capturer_.get()); 52 audio_bus_->Zero(); 53 callback->Capture(audio_bus_.get(), 0, 0, false); 54 55 // Sleep 1ms to yield the resource for the main thread. 56 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); 57 } 58 } 59 60 void Start() { 61 base::PlatformThread::CreateWithPriority( 62 0, this, &thread_, base::kThreadPriority_RealtimeAudio); 63 CHECK(!thread_.is_null()); 64 } 65 66 void Stop() { 67 closure_.Signal(); 68 base::PlatformThread::Join(thread_); 69 thread_ = base::PlatformThreadHandle(); 70 } 71 72 private: 73 scoped_ptr<media::AudioBus> audio_bus_; 74 scoped_refptr<WebRtcAudioCapturer> capturer_; 75 base::PlatformThreadHandle thread_; 76 base::WaitableEvent closure_; 77 DISALLOW_COPY_AND_ASSIGN(FakeAudioThread); 78}; 79 80class MockCapturerSource : public media::AudioCapturerSource { 81 public: 82 MockCapturerSource() {} 83 MOCK_METHOD3(Initialize, void(const media::AudioParameters& params, 84 CaptureCallback* callback, 85 int session_id)); 86 MOCK_METHOD0(Start, void()); 87 MOCK_METHOD0(Stop, void()); 88 MOCK_METHOD1(SetVolume, void(double volume)); 89 MOCK_METHOD1(SetAutomaticGainControl, void(bool enable)); 90 91 protected: 92 virtual ~MockCapturerSource() {} 93}; 94 95class MockWebRtcAudioCapturerSink : public WebRtcAudioCapturerSink { 96 public: 97 MockWebRtcAudioCapturerSink() {} 98 ~MockWebRtcAudioCapturerSink() {} 99 int CaptureData(const std::vector<int>& channels, 100 const int16* audio_data, 101 int sample_rate, 102 int number_of_channels, 103 int number_of_frames, 104 int audio_delay_milliseconds, 105 int current_volume, 106 bool need_audio_processing, 107 bool key_pressed) OVERRIDE { 108 CaptureData(channels.size(), 109 sample_rate, 110 number_of_channels, 111 number_of_frames, 112 audio_delay_milliseconds, 113 current_volume, 114 need_audio_processing, 115 key_pressed); 116 return 0; 117 } 118 MOCK_METHOD8(CaptureData, 119 void(int number_of_network_channels, 120 int sample_rate, 121 int number_of_channels, 122 int number_of_frames, 123 int audio_delay_milliseconds, 124 int current_volume, 125 bool need_audio_processing, 126 bool key_pressed)); 127 MOCK_METHOD1(SetCaptureFormat, void(const media::AudioParameters& params)); 128}; 129 130} // namespace 131 132class WebRtcLocalAudioTrackTest : public ::testing::Test { 133 protected: 134 virtual void SetUp() OVERRIDE { 135 capturer_ = WebRtcAudioCapturer::CreateCapturer(); 136 capturer_source_ = new MockCapturerSource(); 137 EXPECT_CALL(*capturer_source_.get(), Initialize(_, capturer_.get(), 0)) 138 .WillOnce(Return()); 139 capturer_->SetCapturerSource(capturer_source_, 140 media::CHANNEL_LAYOUT_STEREO, 141 48000); 142 143 EXPECT_CALL(*capturer_source_.get(), SetAutomaticGainControl(false)) 144 .WillOnce(Return()); 145 146 // Start the audio thread used by the |capturer_source_|. 147 audio_thread_.reset(new FakeAudioThread(capturer_)); 148 audio_thread_->Start(); 149 } 150 151 virtual void TearDown() { 152 audio_thread_->Stop(); 153 audio_thread_.reset(); 154 } 155 156 scoped_refptr<MockCapturerSource> capturer_source_; 157 scoped_refptr<WebRtcAudioCapturer> capturer_; 158 scoped_ptr<FakeAudioThread> audio_thread_; 159}; 160 161// Creates a capturer and audio track, fakes its audio thread, and 162// connect/disconnect the sink to the audio track on the fly, the sink should 163// get data callback when the track is connected to the capturer but not when 164// the track is disconnected from the capturer. 165TEST_F(WebRtcLocalAudioTrackTest, ConnectAndDisconnectOneSink) { 166 EXPECT_CALL(*capturer_source_.get(), Start()).WillOnce(Return()); 167 scoped_refptr<WebRtcLocalAudioTrack> track = 168 WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL); 169 track->Start(); 170 EXPECT_TRUE(track->enabled()); 171 172 // Connect a number of network channels to the audio track. 173 static const int kNumberOfNetworkChannels = 4; 174 for (int i = 0; i < kNumberOfNetworkChannels; ++i) { 175 static_cast<webrtc::AudioTrackInterface*>(track.get())-> 176 GetRenderer()->AddChannel(i); 177 } 178 scoped_ptr<MockWebRtcAudioCapturerSink> sink( 179 new MockWebRtcAudioCapturerSink()); 180 const media::AudioParameters params = capturer_->audio_parameters(); 181 base::WaitableEvent event(false, false); 182 EXPECT_CALL(*sink, SetCaptureFormat(_)).WillOnce(Return()); 183 EXPECT_CALL(*sink, 184 CaptureData(kNumberOfNetworkChannels, 185 params.sample_rate(), 186 params.channels(), 187 params.frames_per_buffer(), 188 0, 189 0, 190 false, 191 false)).Times(AtLeast(1)) 192 .WillRepeatedly(SignalEvent(&event)); 193 track->AddSink(sink.get()); 194 195 EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout())); 196 track->RemoveSink(sink.get()); 197 198 EXPECT_CALL(*capturer_source_.get(), Stop()).WillOnce(Return()); 199 track->Stop(); 200 track = NULL; 201} 202 203// The same setup as ConnectAndDisconnectOneSink, but enable and disable the 204// audio track on the fly. When the audio track is disabled, there is no data 205// callback to the sink; when the audio track is enabled, there comes data 206// callback. 207// TODO(xians): Enable this test after resolving the racing issue that TSAN 208// reports on MediaStreamTrack::enabled(); 209TEST_F(WebRtcLocalAudioTrackTest, DISABLED_DisableEnableAudioTrack) { 210 EXPECT_CALL(*capturer_source_.get(), Start()).WillOnce(Return()); 211 scoped_refptr<WebRtcLocalAudioTrack> track = 212 WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL); 213 track->Start(); 214 static_cast<webrtc::AudioTrackInterface*>(track.get())-> 215 GetRenderer()->AddChannel(0); 216 EXPECT_TRUE(track->enabled()); 217 EXPECT_TRUE(track->set_enabled(false)); 218 scoped_ptr<MockWebRtcAudioCapturerSink> sink( 219 new MockWebRtcAudioCapturerSink()); 220 const media::AudioParameters params = capturer_->audio_parameters(); 221 base::WaitableEvent event(false, false); 222 EXPECT_CALL(*sink, SetCaptureFormat(_)).WillOnce(Return()); 223 EXPECT_CALL(*sink, 224 CaptureData(1, 225 params.sample_rate(), 226 params.channels(), 227 params.frames_per_buffer(), 228 0, 229 0, 230 false, 231 false)).Times(0); 232 track->AddSink(sink.get()); 233 EXPECT_FALSE(event.TimedWait(TestTimeouts::tiny_timeout())); 234 235 event.Reset(); 236 EXPECT_CALL(*sink, 237 CaptureData(1, 238 params.sample_rate(), 239 params.channels(), 240 params.frames_per_buffer(), 241 0, 242 0, 243 false, 244 false)).Times(AtLeast(1)) 245 .WillRepeatedly(SignalEvent(&event)); 246 EXPECT_TRUE(track->set_enabled(true)); 247 EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout())); 248 track->RemoveSink(sink.get()); 249 250 EXPECT_CALL(*capturer_source_.get(), Stop()).WillOnce(Return()); 251 track->Stop(); 252 track = NULL; 253} 254 255// Create multiple audio tracks and enable/disable them, verify that the audio 256// callbacks appear/disappear. 257TEST_F(WebRtcLocalAudioTrackTest, MultipleAudioTracks) { 258 EXPECT_CALL(*capturer_source_.get(), Start()).WillOnce(Return()); 259 scoped_refptr<WebRtcLocalAudioTrack> track_1 = 260 WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL); 261 track_1->Start(); 262 static_cast<webrtc::AudioTrackInterface*>(track_1.get())-> 263 GetRenderer()->AddChannel(0); 264 EXPECT_TRUE(track_1->enabled()); 265 scoped_ptr<MockWebRtcAudioCapturerSink> sink_1( 266 new MockWebRtcAudioCapturerSink()); 267 const media::AudioParameters params = capturer_->audio_parameters(); 268 base::WaitableEvent event_1(false, false); 269 EXPECT_CALL(*sink_1, SetCaptureFormat(_)).WillOnce(Return()); 270 EXPECT_CALL(*sink_1, 271 CaptureData(1, 272 params.sample_rate(), 273 params.channels(), 274 params.frames_per_buffer(), 275 0, 276 0, 277 false, 278 false)).Times(AtLeast(1)) 279 .WillRepeatedly(SignalEvent(&event_1)); 280 track_1->AddSink(sink_1.get()); 281 EXPECT_TRUE(event_1.TimedWait(TestTimeouts::tiny_timeout())); 282 283 scoped_refptr<WebRtcLocalAudioTrack> track_2 = 284 WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL); 285 track_2->Start(); 286 static_cast<webrtc::AudioTrackInterface*>(track_2.get())-> 287 GetRenderer()->AddChannel(1); 288 EXPECT_TRUE(track_2->enabled()); 289 290 // Verify both |sink_1| and |sink_2| get data. 291 event_1.Reset(); 292 base::WaitableEvent event_2(false, false); 293 294 scoped_ptr<MockWebRtcAudioCapturerSink> sink_2( 295 new MockWebRtcAudioCapturerSink()); 296 EXPECT_CALL(*sink_2, SetCaptureFormat(_)).WillOnce(Return()); 297 EXPECT_CALL(*sink_1, 298 CaptureData(1, 299 params.sample_rate(), 300 params.channels(), 301 params.frames_per_buffer(), 302 0, 303 0, 304 false, 305 false)).Times(AtLeast(1)) 306 .WillRepeatedly(SignalEvent(&event_1)); 307 EXPECT_CALL(*sink_2, 308 CaptureData(1, 309 params.sample_rate(), 310 params.channels(), 311 params.frames_per_buffer(), 312 0, 313 0, 314 false, 315 false)).Times(AtLeast(1)) 316 .WillRepeatedly(SignalEvent(&event_2)); 317 track_2->AddSink(sink_2.get()); 318 EXPECT_TRUE(event_1.TimedWait(TestTimeouts::tiny_timeout())); 319 EXPECT_TRUE(event_2.TimedWait(TestTimeouts::tiny_timeout())); 320 321 track_1->RemoveSink(sink_1.get()); 322 track_1->Stop(); 323 track_1 = NULL; 324 325 EXPECT_CALL(*capturer_source_.get(), Stop()).WillOnce(Return()); 326 track_2->RemoveSink(sink_2.get()); 327 track_2->Stop(); 328 track_2 = NULL; 329} 330 331 332// Start one track and verify the capturer is correctly starting its source. 333// And it should be fine to not to call Stop() explicitly. 334TEST_F(WebRtcLocalAudioTrackTest, StartOneAudioTrack) { 335 EXPECT_CALL(*capturer_source_.get(), Start()).Times(1); 336 scoped_refptr<WebRtcLocalAudioTrack> track = 337 WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL); 338 track->Start(); 339 340 // When the track goes away, it will automatically stop the 341 // |capturer_source_|. 342 EXPECT_CALL(*capturer_source_.get(), Stop()); 343 track->Stop(); 344 track = NULL; 345} 346 347// Start/Stop tracks and verify the capturer is correctly starting/stopping 348// its source. 349TEST_F(WebRtcLocalAudioTrackTest, StartAndStopAudioTracks) { 350 // Starting the first audio track will start the |capturer_source_|. 351 base::WaitableEvent event(false, false); 352 EXPECT_CALL(*capturer_source_.get(), Start()).WillOnce(SignalEvent(&event)); 353 scoped_refptr<WebRtcLocalAudioTrack> track_1 = 354 WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL); 355 static_cast<webrtc::AudioTrackInterface*>(track_1.get())-> 356 GetRenderer()->AddChannel(0); 357 track_1->Start(); 358 EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout())); 359 360 // Verify the data flow by connecting the sink to |track_1|. 361 scoped_ptr<MockWebRtcAudioCapturerSink> sink( 362 new MockWebRtcAudioCapturerSink()); 363 event.Reset(); 364 EXPECT_CALL(*sink, CaptureData(_, _, _, _, 0, 0, false, false)) 365 .Times(AnyNumber()).WillRepeatedly(Return()); 366 EXPECT_CALL(*sink, SetCaptureFormat(_)).Times(1); 367 track_1->AddSink(sink.get()); 368 369 // Start the second audio track will not start the |capturer_source_| 370 // since it has been started. 371 EXPECT_CALL(*capturer_source_.get(), Start()).Times(0); 372 scoped_refptr<WebRtcLocalAudioTrack> track_2 = 373 WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL); 374 track_2->Start(); 375 static_cast<webrtc::AudioTrackInterface*>(track_2.get())-> 376 GetRenderer()->AddChannel(1); 377 378 // Stop the first audio track will not stop the |capturer_source_|. 379 EXPECT_CALL(*capturer_source_.get(), Stop()).Times(0); 380 track_1->RemoveSink(sink.get()); 381 track_1->Stop(); 382 track_1 = NULL; 383 384 EXPECT_CALL(*sink, CaptureData(_, _, _, _, 0, 0, false, false)) 385 .Times(AnyNumber()).WillRepeatedly(Return()); 386 EXPECT_CALL(*sink, SetCaptureFormat(_)).Times(1); 387 track_2->AddSink(sink.get()); 388 389 // Stop the last audio track will stop the |capturer_source_|. 390 event.Reset(); 391 EXPECT_CALL(*capturer_source_.get(), Stop()) 392 .Times(1).WillOnce(SignalEvent(&event)); 393 track_2->Stop(); 394 track_2->RemoveSink(sink.get()); 395 track_2 = NULL; 396 EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout())); 397} 398 399// Set new source to the existing capturer. 400TEST_F(WebRtcLocalAudioTrackTest, SetNewSourceForCapturerAfterStartTrack) { 401 // Setup the audio track and start the track. 402 EXPECT_CALL(*capturer_source_.get(), Start()).Times(1); 403 scoped_refptr<WebRtcLocalAudioTrack> track = 404 WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL); 405 track->Start(); 406 407 // Setting new source to the capturer and the track should still get packets. 408 scoped_refptr<MockCapturerSource> new_source(new MockCapturerSource()); 409 EXPECT_CALL(*capturer_source_.get(), Stop()); 410 EXPECT_CALL(*new_source.get(), SetAutomaticGainControl(false)); 411 EXPECT_CALL(*new_source.get(), Initialize(_, capturer_.get(), 0)) 412 .WillOnce(Return()); 413 EXPECT_CALL(*new_source.get(), Start()).WillOnce(Return()); 414 capturer_->SetCapturerSource(new_source, 415 media::CHANNEL_LAYOUT_STEREO, 416 48000); 417 418 // Stop the track. 419 EXPECT_CALL(*new_source.get(), Stop()); 420 track->Stop(); 421 track = NULL; 422} 423 424// Create a new capturer with new source, connect it to a new audio track. 425TEST_F(WebRtcLocalAudioTrackTest, ConnectTracksToDifferentCapturers) { 426 // Setup the first audio track and start it. 427 EXPECT_CALL(*capturer_source_.get(), Start()).Times(1); 428 scoped_refptr<WebRtcLocalAudioTrack> track_1 = 429 WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL); 430 track_1->Start(); 431 432 // Connect a number of network channels to the |track_1|. 433 static const int kNumberOfNetworkChannelsForTrack1 = 2; 434 for (int i = 0; i < kNumberOfNetworkChannelsForTrack1; ++i) { 435 static_cast<webrtc::AudioTrackInterface*>(track_1.get())-> 436 GetRenderer()->AddChannel(i); 437 } 438 // Verify the data flow by connecting the |sink_1| to |track_1|. 439 scoped_ptr<MockWebRtcAudioCapturerSink> sink_1( 440 new MockWebRtcAudioCapturerSink()); 441 EXPECT_CALL( 442 *sink_1.get(), 443 CaptureData( 444 kNumberOfNetworkChannelsForTrack1, 48000, 2, _, 0, 0, false, false)) 445 .Times(AnyNumber()).WillRepeatedly(Return()); 446 EXPECT_CALL(*sink_1.get(), SetCaptureFormat(_)).Times(1); 447 track_1->AddSink(sink_1.get()); 448 449 // Create a new capturer with new source with different audio format. 450 scoped_refptr<WebRtcAudioCapturer> new_capturer( 451 WebRtcAudioCapturer::CreateCapturer()); 452 scoped_refptr<MockCapturerSource> new_source(new MockCapturerSource()); 453 EXPECT_CALL(*new_source.get(), Initialize(_, new_capturer.get(), 0)) 454 .WillOnce(Return()); 455 EXPECT_CALL(*new_source.get(), SetAutomaticGainControl(false)) 456 .WillOnce(Return()); 457 new_capturer->SetCapturerSource(new_source, 458 media::CHANNEL_LAYOUT_MONO, 459 44100); 460 461 // Start the audio thread used by the new source. 462 scoped_ptr<FakeAudioThread> audio_thread(new FakeAudioThread(new_capturer)); 463 audio_thread->Start(); 464 465 // Setup the second audio track, connect it to the new capturer and start it. 466 EXPECT_CALL(*new_source.get(), Start()).Times(1); 467 scoped_refptr<WebRtcLocalAudioTrack> track_2 = 468 WebRtcLocalAudioTrack::Create(std::string(), new_capturer, NULL); 469 track_2->Start(); 470 471 // Connect a number of network channels to the |track_2|. 472 static const int kNumberOfNetworkChannelsForTrack2 = 3; 473 for (int i = 0; i < kNumberOfNetworkChannelsForTrack2; ++i) { 474 static_cast<webrtc::AudioTrackInterface*>(track_2.get())-> 475 GetRenderer()->AddChannel(i); 476 } 477 // Verify the data flow by connecting the |sink_2| to |track_2|. 478 scoped_ptr<MockWebRtcAudioCapturerSink> sink_2( 479 new MockWebRtcAudioCapturerSink()); 480 EXPECT_CALL( 481 *sink_2, 482 CaptureData( 483 kNumberOfNetworkChannelsForTrack2, 44100, 1, _, 0, 0, false, false)) 484 .Times(AnyNumber()).WillRepeatedly(Return()); 485 EXPECT_CALL(*sink_2, SetCaptureFormat(_)).Times(1); 486 track_2->AddSink(sink_2.get()); 487 488 // Stop the second audio track will stop the new source. 489 base::WaitableEvent event(false, false); 490 EXPECT_CALL(*new_source.get(), Stop()).Times(1).WillOnce(SignalEvent(&event)); 491 track_2->Stop(); 492 track_2->RemoveSink(sink_2.get()); 493 track_2 = NULL; 494 EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout())); 495 audio_thread->Stop(); 496 audio_thread.reset(); 497 498 // Stop the first audio track. 499 EXPECT_CALL(*capturer_source_.get(), Stop()); 500 track_1->Stop(); 501 track_1 = NULL; 502} 503 504} // namespace content 505