| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "content/renderer/media/audio_renderer_mixer_manager.h" | 5 #include "content/renderer/media/audio_renderer_mixer_manager.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 | 25 |
| 26 static const int kBitsPerChannel = 16; | 26 static const int kBitsPerChannel = 16; |
| 27 static const int kSampleRate = 48000; | 27 static const int kSampleRate = 48000; |
| 28 static const int kBufferSize = 8192; | 28 static const int kBufferSize = 8192; |
| 29 static const media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO; | 29 static const media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO; |
| 30 static const media::ChannelLayout kAnotherChannelLayout = | 30 static const media::ChannelLayout kAnotherChannelLayout = |
| 31 media::CHANNEL_LAYOUT_2_1; | 31 media::CHANNEL_LAYOUT_2_1; |
| 32 static const char* const kDefaultDeviceId = | 32 static const char* const kDefaultDeviceId = |
| 33 media::AudioManagerBase::kDefaultDeviceId; | 33 media::AudioManagerBase::kDefaultDeviceId; |
| 34 static const char kAnotherDeviceId[] = "another-device-id"; | 34 static const char kAnotherDeviceId[] = "another-device-id"; |
| 35 static const char kMatchedDeviceId[] = "matched-device-id"; |
| 35 static const char kNonexistentDeviceId[] = "nonexistent-device-id"; | 36 static const char kNonexistentDeviceId[] = "nonexistent-device-id"; |
| 36 | 37 |
| 37 static const int kRenderFrameId = 124; | 38 static const int kRenderFrameId = 124; |
| 38 static const int kAnotherRenderFrameId = 678; | 39 static const int kAnotherRenderFrameId = 678; |
| 39 | 40 |
| 40 using media::AudioParameters; | 41 using media::AudioParameters; |
| 41 | 42 |
| 42 class AudioRendererMixerManagerTest : public testing::Test, | 43 class AudioRendererMixerManagerTest : public testing::Test, |
| 43 public AudioDeviceFactory { | 44 public AudioDeviceFactory { |
| 44 public: | 45 public: |
| 45 AudioRendererMixerManagerTest() | 46 AudioRendererMixerManagerTest() |
| 46 : manager_(new AudioRendererMixerManager()), | 47 : manager_(new AudioRendererMixerManager()), |
| 47 mock_sink_(new media::MockAudioRendererSink()), | 48 mock_sink_(new media::MockAudioRendererSink()), |
| 48 mock_sink_no_device_(new media::MockAudioRendererSink( | 49 mock_sink_no_device_(new media::MockAudioRendererSink( |
| 49 kNonexistentDeviceId, | 50 kNonexistentDeviceId, |
| 50 media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND)), | 51 media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND)), |
| 52 mock_sink_matched_device_( |
| 53 new media::MockAudioRendererSink(kMatchedDeviceId, |
| 54 media::OUTPUT_DEVICE_STATUS_OK)), |
| 55 mock_sink_for_session_id_( |
| 56 new media::MockAudioRendererSink(kMatchedDeviceId, |
| 57 media::OUTPUT_DEVICE_STATUS_OK)), |
| 51 kSecurityOrigin2(GURL("http://localhost")) {} | 58 kSecurityOrigin2(GURL("http://localhost")) {} |
| 52 | 59 |
| 53 media::AudioRendererMixer* GetMixer( | 60 media::AudioRendererMixer* GetMixer( |
| 54 int source_render_frame_id, | 61 int source_render_frame_id, |
| 55 const media::AudioParameters& params, | 62 const media::AudioParameters& params, |
| 56 const std::string& device_id, | 63 const std::string& device_id, |
| 57 const url::Origin& security_origin, | 64 const url::Origin& security_origin, |
| 58 media::OutputDeviceStatus* device_status) { | 65 media::OutputDeviceStatus* device_status) { |
| 59 return manager_->GetMixer(source_render_frame_id, params, device_id, | 66 return manager_->GetMixer(source_render_frame_id, params, device_id, |
| 60 security_origin, device_status); | 67 security_origin, device_status); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 83 int, | 90 int, |
| 84 const std::string&, | 91 const std::string&, |
| 85 const url::Origin&)); | 92 const url::Origin&)); |
| 86 MOCK_METHOD5(CreateAudioRendererSink, | 93 MOCK_METHOD5(CreateAudioRendererSink, |
| 87 scoped_refptr<media::AudioRendererSink>(SourceType, | 94 scoped_refptr<media::AudioRendererSink>(SourceType, |
| 88 int, | 95 int, |
| 89 int, | 96 int, |
| 90 const std::string&, | 97 const std::string&, |
| 91 const url::Origin&)); | 98 const url::Origin&)); |
| 92 | 99 |
| 93 scoped_refptr<media::AudioRendererSink> CreateAudioRendererMixerSink( | 100 scoped_refptr<media::AudioRendererSink> CreateFinalAudioRendererSink( |
| 94 int render_frame_id, | 101 int render_frame_id, |
| 95 int session_id, | 102 int session_id, |
| 96 const std::string& device_id, | 103 const std::string& device_id, |
| 97 const url::Origin& security_origin) { | 104 const url::Origin& security_origin) { |
| 98 if ((device_id == kDefaultDeviceId) || (device_id == kAnotherDeviceId)) { | 105 if ((device_id == kDefaultDeviceId) || (device_id == kAnotherDeviceId)) { |
| 99 // We don't care about separate sinks for these devices | 106 // We don't care about separate sinks for these devices. |
| 100 return mock_sink_; | 107 return mock_sink_; |
| 101 } | 108 } |
| 102 if (device_id == kNonexistentDeviceId) { | 109 if (device_id == kNonexistentDeviceId) |
| 103 return mock_sink_no_device_; | 110 return mock_sink_no_device_; |
| 111 if (device_id.empty()) { |
| 112 // The sink used to get device ID from session ID if it's not empty |
| 113 return session_id ? mock_sink_for_session_id_ : mock_sink_; |
| 104 } | 114 } |
| 105 if (device_id.empty()) { | 115 if (device_id == kMatchedDeviceId) |
| 106 return mock_sink_; | 116 return mock_sink_matched_device_; |
| 107 } | |
| 108 | 117 |
| 109 NOTREACHED(); | 118 NOTREACHED(); |
| 110 return nullptr; | 119 return nullptr; |
| 111 } | 120 } |
| 112 | 121 |
| 113 std::unique_ptr<AudioRendererMixerManager> manager_; | 122 std::unique_ptr<AudioRendererMixerManager> manager_; |
| 114 scoped_refptr<media::MockAudioRendererSink> mock_sink_; | 123 scoped_refptr<media::MockAudioRendererSink> mock_sink_; |
| 115 scoped_refptr<media::MockAudioRendererSink> mock_sink_no_device_; | 124 scoped_refptr<media::MockAudioRendererSink> mock_sink_no_device_; |
| 125 scoped_refptr<media::MockAudioRendererSink> mock_sink_matched_device_; |
| 126 scoped_refptr<media::MockAudioRendererSink> mock_sink_for_session_id_; |
| 116 | 127 |
| 117 // To avoid global/static non-POD constants. | 128 // To avoid global/static non-POD constants. |
| 118 const url::Origin kSecurityOrigin; | 129 const url::Origin kSecurityOrigin; |
| 119 const url::Origin kSecurityOrigin2; | 130 const url::Origin kSecurityOrigin2; |
| 120 | 131 |
| 121 private: | 132 private: |
| 122 DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerManagerTest); | 133 DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerManagerTest); |
| 123 }; | 134 }; |
| 124 | 135 |
| 125 // Verify GetMixer() and RemoveMixer() both work as expected; particularly with | 136 // Verify GetMixer() and RemoveMixer() both work as expected; particularly with |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 EXPECT_CALL(*mock_sink_.get(), Start()).Times(2); | 239 EXPECT_CALL(*mock_sink_.get(), Start()).Times(2); |
| 229 EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2); | 240 EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2); |
| 230 | 241 |
| 231 media::AudioParameters params( | 242 media::AudioParameters params( |
| 232 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, | 243 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, |
| 233 kBitsPerChannel, kBufferSize); | 244 kBitsPerChannel, kBufferSize); |
| 234 | 245 |
| 235 // Create two mixer inputs and ensure this doesn't instantiate any mixers yet. | 246 // Create two mixer inputs and ensure this doesn't instantiate any mixers yet. |
| 236 EXPECT_EQ(0, mixer_count()); | 247 EXPECT_EQ(0, mixer_count()); |
| 237 media::FakeAudioRenderCallback callback(0); | 248 media::FakeAudioRenderCallback callback(0); |
| 238 scoped_refptr<media::AudioRendererMixerInput> input( | 249 scoped_refptr<media::AudioRendererMixerInput> input(manager_->CreateInput( |
| 239 manager_->CreateInput(kRenderFrameId, kDefaultDeviceId, kSecurityOrigin)); | 250 kRenderFrameId, 0, kDefaultDeviceId, kSecurityOrigin)); |
| 240 input->Initialize(params, &callback); | 251 input->Initialize(params, &callback); |
| 241 EXPECT_EQ(0, mixer_count()); | 252 EXPECT_EQ(0, mixer_count()); |
| 242 media::FakeAudioRenderCallback another_callback(1); | 253 media::FakeAudioRenderCallback another_callback(1); |
| 243 scoped_refptr<media::AudioRendererMixerInput> another_input( | 254 scoped_refptr<media::AudioRendererMixerInput> another_input( |
| 244 manager_->CreateInput(kAnotherRenderFrameId, kDefaultDeviceId, | 255 manager_->CreateInput(kAnotherRenderFrameId, 0, kDefaultDeviceId, |
| 245 kSecurityOrigin)); | 256 kSecurityOrigin)); |
| 246 another_input->Initialize(params, &another_callback); | 257 another_input->Initialize(params, &another_callback); |
| 247 EXPECT_EQ(0, mixer_count()); | 258 EXPECT_EQ(0, mixer_count()); |
| 248 | 259 |
| 249 // Implicitly test that AudioRendererMixerInput was provided with the expected | 260 // Implicitly test that AudioRendererMixerInput was provided with the expected |
| 250 // callbacks needed to acquire an AudioRendererMixer and remove it. | 261 // callbacks needed to acquire an AudioRendererMixer and remove it. |
| 251 input->Start(); | 262 input->Start(); |
| 252 EXPECT_EQ(1, mixer_count()); | 263 EXPECT_EQ(1, mixer_count()); |
| 253 another_input->Start(); | 264 another_input->Start(); |
| 254 EXPECT_EQ(2, mixer_count()); | 265 EXPECT_EQ(2, mixer_count()); |
| 255 | 266 |
| 256 // Destroying the inputs should destroy the mixers. | 267 // Destroying the inputs should destroy the mixers. |
| 257 input->Stop(); | 268 input->Stop(); |
| 258 input = nullptr; | 269 input = nullptr; |
| 259 EXPECT_EQ(1, mixer_count()); | 270 EXPECT_EQ(1, mixer_count()); |
| 260 another_input->Stop(); | 271 another_input->Stop(); |
| 261 another_input = nullptr; | 272 another_input = nullptr; |
| 262 EXPECT_EQ(0, mixer_count()); | 273 EXPECT_EQ(0, mixer_count()); |
| 263 } | 274 } |
| 264 | 275 |
| 276 // Verify CreateInput() provided with session id creates AudioRendererMixerInput |
| 277 // with the appropriate callbacks and they are working as expected. |
| 278 TEST_F(AudioRendererMixerManagerTest, CreateInputWithSessionId) { |
| 279 // Expect AudioRendererMixerManager to call Start and Stop on our mock twice |
| 280 // each: for kDefaultDeviceId and for kAnotherDeviceId. Note: Under normal |
| 281 // conditions, each mixer would get its own sink! |
| 282 EXPECT_CALL(*mock_sink_.get(), Start()).Times(2); |
| 283 EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2); |
| 284 |
| 285 // Expect AudioRendererMixerManager to call Start and Stop on the matched sink |
| 286 // once. |
| 287 EXPECT_CALL(*mock_sink_matched_device_.get(), Start()).Times(1); |
| 288 EXPECT_CALL(*mock_sink_matched_device_.get(), Stop()).Times(1); |
| 289 |
| 290 media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, |
| 291 kChannelLayout, kSampleRate, kBitsPerChannel, |
| 292 kBufferSize); |
| 293 media::FakeAudioRenderCallback callback(0); |
| 294 EXPECT_EQ(0, mixer_count()); |
| 295 |
| 296 // Empty device id, zero session id; |
| 297 scoped_refptr<media::AudioRendererMixerInput> input_to_default_device( |
| 298 manager_->CreateInput(kRenderFrameId, 0, // session_id |
| 299 std::string(), kSecurityOrigin)); |
| 300 input_to_default_device->Initialize(params, &callback); |
| 301 EXPECT_EQ(0, mixer_count()); |
| 302 |
| 303 // Specific device id, zero session id; |
| 304 scoped_refptr<media::AudioRendererMixerInput> input_to_matched_device( |
| 305 manager_->CreateInput(kRenderFrameId, 0, // session_id |
| 306 kMatchedDeviceId, kSecurityOrigin)); |
| 307 input_to_matched_device->Initialize(params, &callback); |
| 308 EXPECT_EQ(0, mixer_count()); |
| 309 |
| 310 // Specific device id, non-zero session id (to be ignored); |
| 311 scoped_refptr<media::AudioRendererMixerInput> input_to_another_device( |
| 312 manager_->CreateInput(kRenderFrameId, 1, // session id |
| 313 kAnotherDeviceId, kSecurityOrigin)); |
| 314 input_to_another_device->Initialize(params, &callback); |
| 315 EXPECT_EQ(0, mixer_count()); |
| 316 |
| 317 // Empty device id, non-zero session id; |
| 318 scoped_refptr<media::AudioRendererMixerInput> |
| 319 input_to_matched_device_with_session_id( |
| 320 manager_->CreateInput(kRenderFrameId, 2, // session id |
| 321 std::string(), kSecurityOrigin)); |
| 322 input_to_matched_device_with_session_id->Initialize(params, &callback); |
| 323 EXPECT_EQ(0, mixer_count()); |
| 324 |
| 325 // Implicitly test that AudioRendererMixerInput was provided with the expected |
| 326 // callbacks needed to acquire an AudioRendererMixer and remove it. |
| 327 input_to_default_device->Start(); |
| 328 EXPECT_EQ(1, mixer_count()); |
| 329 |
| 330 input_to_another_device->Start(); |
| 331 EXPECT_EQ(2, mixer_count()); |
| 332 |
| 333 input_to_matched_device->Start(); |
| 334 EXPECT_EQ(3, mixer_count()); |
| 335 |
| 336 // Should go to the same device as the input above. |
| 337 input_to_matched_device_with_session_id->Start(); |
| 338 EXPECT_EQ(3, mixer_count()); |
| 339 |
| 340 // Destroying the inputs should destroy the mixers. |
| 341 input_to_default_device->Stop(); |
| 342 input_to_default_device = nullptr; |
| 343 EXPECT_EQ(2, mixer_count()); |
| 344 input_to_another_device->Stop(); |
| 345 input_to_another_device = nullptr; |
| 346 EXPECT_EQ(1, mixer_count()); |
| 347 input_to_matched_device->Stop(); |
| 348 input_to_matched_device = nullptr; |
| 349 EXPECT_EQ(1, mixer_count()); |
| 350 input_to_matched_device_with_session_id->Stop(); |
| 351 input_to_matched_device_with_session_id = nullptr; |
| 352 EXPECT_EQ(0, mixer_count()); |
| 353 } |
| 354 |
| 265 // Verify GetMixer() correctly creates different mixers with the same | 355 // Verify GetMixer() correctly creates different mixers with the same |
| 266 // parameters, but different device ID and/or security origin | 356 // parameters, but different device ID and/or security origin |
| 267 TEST_F(AudioRendererMixerManagerTest, MixerDevices) { | 357 TEST_F(AudioRendererMixerManagerTest, MixerDevices) { |
| 268 EXPECT_CALL(*mock_sink_.get(), Start()).Times(3); | 358 EXPECT_CALL(*mock_sink_.get(), Start()).Times(3); |
| 269 EXPECT_CALL(*mock_sink_.get(), Stop()).Times(3); | 359 EXPECT_CALL(*mock_sink_.get(), Stop()).Times(3); |
| 270 EXPECT_EQ(0, mixer_count()); | 360 EXPECT_EQ(0, mixer_count()); |
| 271 | 361 |
| 272 media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, | 362 media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, |
| 273 kChannelLayout, kSampleRate, kBitsPerChannel, | 363 kChannelLayout, kSampleRate, kBitsPerChannel, |
| 274 kBufferSize); | 364 kBufferSize); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 291 EXPECT_NE(mixer2, mixer3); | 381 EXPECT_NE(mixer2, mixer3); |
| 292 | 382 |
| 293 RemoveMixer(kRenderFrameId, params, kDefaultDeviceId, kSecurityOrigin); | 383 RemoveMixer(kRenderFrameId, params, kDefaultDeviceId, kSecurityOrigin); |
| 294 EXPECT_EQ(2, mixer_count()); | 384 EXPECT_EQ(2, mixer_count()); |
| 295 RemoveMixer(kRenderFrameId, params, kAnotherDeviceId, kSecurityOrigin); | 385 RemoveMixer(kRenderFrameId, params, kAnotherDeviceId, kSecurityOrigin); |
| 296 EXPECT_EQ(1, mixer_count()); | 386 EXPECT_EQ(1, mixer_count()); |
| 297 RemoveMixer(kRenderFrameId, params, kAnotherDeviceId, kSecurityOrigin2); | 387 RemoveMixer(kRenderFrameId, params, kAnotherDeviceId, kSecurityOrigin2); |
| 298 EXPECT_EQ(0, mixer_count()); | 388 EXPECT_EQ(0, mixer_count()); |
| 299 } | 389 } |
| 300 | 390 |
| 391 // Verify GetMixer() correctly deduplicate mixers with the same |
| 392 // parameters, different security origins but default device ID |
| 393 TEST_F(AudioRendererMixerManagerTest, OneMixerDifferentOriginsDefaultDevice) { |
| 394 EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); |
| 395 EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1); |
| 396 EXPECT_EQ(0, mixer_count()); |
| 397 |
| 398 media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, |
| 399 kChannelLayout, kSampleRate, kBitsPerChannel, |
| 400 kBufferSize); |
| 401 media::AudioRendererMixer* mixer1 = GetMixer( |
| 402 kRenderFrameId, params, kDefaultDeviceId, kSecurityOrigin, nullptr); |
| 403 ASSERT_TRUE(mixer1); |
| 404 EXPECT_EQ(1, mixer_count()); |
| 405 |
| 406 media::AudioRendererMixer* mixer2 = |
| 407 GetMixer(kRenderFrameId, params, std::string(), kSecurityOrigin, nullptr); |
| 408 ASSERT_TRUE(mixer2); |
| 409 EXPECT_EQ(1, mixer_count()); |
| 410 EXPECT_EQ(mixer1, mixer2); |
| 411 |
| 412 media::AudioRendererMixer* mixer3 = GetMixer( |
| 413 kRenderFrameId, params, kDefaultDeviceId, kSecurityOrigin2, nullptr); |
| 414 ASSERT_TRUE(mixer3); |
| 415 EXPECT_EQ(1, mixer_count()); |
| 416 EXPECT_EQ(mixer1, mixer3); |
| 417 |
| 418 media::AudioRendererMixer* mixer4 = GetMixer( |
| 419 kRenderFrameId, params, std::string(), kSecurityOrigin2, nullptr); |
| 420 ASSERT_TRUE(mixer4); |
| 421 EXPECT_EQ(1, mixer_count()); |
| 422 EXPECT_EQ(mixer1, mixer4); |
| 423 |
| 424 RemoveMixer(kRenderFrameId, params, kDefaultDeviceId, kSecurityOrigin); |
| 425 EXPECT_EQ(1, mixer_count()); |
| 426 RemoveMixer(kRenderFrameId, params, std::string(), kSecurityOrigin); |
| 427 EXPECT_EQ(1, mixer_count()); |
| 428 RemoveMixer(kRenderFrameId, params, kDefaultDeviceId, kSecurityOrigin2); |
| 429 EXPECT_EQ(1, mixer_count()); |
| 430 RemoveMixer(kRenderFrameId, params, std::string(), kSecurityOrigin2); |
| 431 EXPECT_EQ(0, mixer_count()); |
| 432 } |
| 433 |
| 301 // Verify that GetMixer() correctly returns a null mixer and an appropriate | 434 // Verify that GetMixer() correctly returns a null mixer and an appropriate |
| 302 // status code when a nonexistent device is requested. | 435 // status code when a nonexistent device is requested. |
| 303 TEST_F(AudioRendererMixerManagerTest, NonexistentDevice) { | 436 TEST_F(AudioRendererMixerManagerTest, NonexistentDevice) { |
| 304 EXPECT_EQ(0, mixer_count()); | 437 EXPECT_EQ(0, mixer_count()); |
| 305 media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, | 438 media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, |
| 306 kChannelLayout, kSampleRate, kBitsPerChannel, | 439 kChannelLayout, kSampleRate, kBitsPerChannel, |
| 307 kBufferSize); | 440 kBufferSize); |
| 308 media::OutputDeviceStatus device_status = media::OUTPUT_DEVICE_STATUS_OK; | 441 media::OutputDeviceStatus device_status = media::OUTPUT_DEVICE_STATUS_OK; |
| 309 EXPECT_CALL(*mock_sink_no_device_.get(), Stop()); | 442 EXPECT_CALL(*mock_sink_no_device_.get(), Stop()); |
| 310 media::AudioRendererMixer* mixer = | 443 media::AudioRendererMixer* mixer = |
| 311 GetMixer(kRenderFrameId, params, kNonexistentDeviceId, kSecurityOrigin, | 444 GetMixer(kRenderFrameId, params, kNonexistentDeviceId, kSecurityOrigin, |
| 312 &device_status); | 445 &device_status); |
| 313 EXPECT_FALSE(mixer); | 446 EXPECT_FALSE(mixer); |
| 314 EXPECT_EQ(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, device_status); | 447 EXPECT_EQ(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, device_status); |
| 315 EXPECT_EQ(0, mixer_count()); | 448 EXPECT_EQ(0, mixer_count()); |
| 316 } | 449 } |
| 317 | 450 |
| 318 } // namespace content | 451 } // namespace content |
| OLD | NEW |