| 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/browser/renderer_host/media/audio_renderer_host.h" | 5 #include "content/browser/renderer_host/media/audio_renderer_host.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/run_loop.h" | 14 #include "base/run_loop.h" |
| 15 #include "base/sync_socket.h" | 15 #include "base/sync_socket.h" |
| 16 #include "content/browser/media/capture/audio_mirroring_manager.h" | 16 #include "content/browser/media/capture/audio_mirroring_manager.h" |
| 17 #include "content/browser/media/media_internals.h" | 17 #include "content/browser/media/media_internals.h" |
| 18 #include "content/browser/renderer_host/media/audio_input_device_manager.h" | 18 #include "content/browser/renderer_host/media/audio_input_device_manager.h" |
| 19 #include "content/browser/renderer_host/media/media_stream_manager.h" | 19 #include "content/browser/renderer_host/media/media_stream_manager.h" |
| 20 #include "content/common/media/audio_messages.h" | 20 #include "content/common/media/audio_messages.h" |
| 21 #include "content/public/common/content_switches.h" | 21 #include "content/public/common/content_switches.h" |
| 22 #include "content/public/test/mock_render_process_host.h" |
| 23 #include "content/public/test/test_browser_context.h" |
| 22 #include "content/public/test/test_browser_thread_bundle.h" | 24 #include "content/public/test/test_browser_thread_bundle.h" |
| 23 #include "ipc/ipc_message_utils.h" | 25 #include "ipc/ipc_message_utils.h" |
| 24 #include "media/audio/audio_manager.h" | 26 #include "media/audio/audio_manager.h" |
| 25 #include "media/base/bind_to_current_loop.h" | 27 #include "media/base/bind_to_current_loop.h" |
| 26 #include "media/base/media_switches.h" | 28 #include "media/base/media_switches.h" |
| 27 #include "testing/gmock/include/gmock/gmock.h" | 29 #include "testing/gmock/include/gmock/gmock.h" |
| 28 #include "testing/gtest/include/gtest/gtest.h" | 30 #include "testing/gtest/include/gtest/gtest.h" |
| 29 | 31 |
| 30 using ::testing::_; | 32 using ::testing::_; |
| 31 using ::testing::Assign; | 33 using ::testing::Assign; |
| 32 using ::testing::AtLeast; | 34 using ::testing::AtLeast; |
| 33 using ::testing::DoAll; | 35 using ::testing::DoAll; |
| 34 using ::testing::NotNull; | 36 using ::testing::NotNull; |
| 35 | 37 |
| 36 namespace content { | 38 namespace content { |
| 37 | 39 |
| 38 namespace { | 40 namespace { |
| 39 const int kRenderProcessId = 1; | |
| 40 const int kRenderFrameId = 5; | 41 const int kRenderFrameId = 5; |
| 41 const int kStreamId = 50; | 42 const int kStreamId = 50; |
| 42 const char kSecurityOrigin[] = "http://localhost"; | 43 const char kSecurityOrigin[] = "http://localhost"; |
| 43 const char kBadSecurityOrigin[] = "about:about"; | 44 const char kBadSecurityOrigin[] = "about:about"; |
| 44 const char kDefaultDeviceId[] = ""; | 45 const char kDefaultDeviceId[] = ""; |
| 45 const char kNondefaultDeviceId[] = | 46 const char kNondefaultDeviceId[] = |
| 46 "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; | 47 "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; |
| 47 const char kBadDeviceId[] = | 48 const char kBadDeviceId[] = |
| 48 "badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad1"; | 49 "badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad1"; |
| 49 const char kInvalidDeviceId[] = "invalid-device-id"; | 50 const char kInvalidDeviceId[] = "invalid-device-id"; |
| 50 | 51 |
| 51 void ValidateRenderFrameId(int render_process_id, | 52 void ValidateRenderFrameId(int render_process_id, |
| 52 int render_frame_id, | 53 int render_frame_id, |
| 53 const base::Callback<void(bool)>& callback) { | 54 const base::Callback<void(bool)>& callback) { |
| 54 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 55 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 55 const bool frame_exists = (render_process_id == kRenderProcessId && | 56 const bool frame_exists = (render_frame_id == kRenderFrameId); |
| 56 render_frame_id == kRenderFrameId); | |
| 57 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 57 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 58 base::Bind(callback, frame_exists)); | 58 base::Bind(callback, frame_exists)); |
| 59 } | 59 } |
| 60 | 60 |
| 61 } // namespace | 61 } // namespace |
| 62 | 62 |
| 63 class MockAudioMirroringManager : public AudioMirroringManager { | 63 class MockAudioMirroringManager : public AudioMirroringManager { |
| 64 public: | 64 public: |
| 65 MockAudioMirroringManager() {} | 65 MockAudioMirroringManager() {} |
| 66 virtual ~MockAudioMirroringManager() {} | 66 virtual ~MockAudioMirroringManager() {} |
| 67 | 67 |
| 68 MOCK_METHOD3(AddDiverter, | 68 MOCK_METHOD3(AddDiverter, |
| 69 void(int render_process_id, | 69 void(int render_process_id, |
| 70 int render_frame_id, | 70 int render_frame_id, |
| 71 Diverter* diverter)); | 71 Diverter* diverter)); |
| 72 MOCK_METHOD1(RemoveDiverter, void(Diverter* diverter)); | 72 MOCK_METHOD1(RemoveDiverter, void(Diverter* diverter)); |
| 73 | 73 |
| 74 private: | 74 private: |
| 75 DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager); | 75 DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager); |
| 76 }; | 76 }; |
| 77 | 77 |
| 78 class MockAudioRendererHost : public AudioRendererHost { | 78 class MockAudioRendererHost : public AudioRendererHost { |
| 79 public: | 79 public: |
| 80 MockAudioRendererHost(base::RunLoop* auth_run_loop, | 80 MockAudioRendererHost(base::RunLoop* auth_run_loop, |
| 81 int render_process_id, |
| 81 media::AudioManager* audio_manager, | 82 media::AudioManager* audio_manager, |
| 82 AudioMirroringManager* mirroring_manager, | 83 AudioMirroringManager* mirroring_manager, |
| 83 MediaInternals* media_internals, | 84 MediaInternals* media_internals, |
| 84 MediaStreamManager* media_stream_manager, | 85 MediaStreamManager* media_stream_manager, |
| 85 const std::string& salt) | 86 const std::string& salt) |
| 86 : AudioRendererHost(kRenderProcessId, | 87 : AudioRendererHost(render_process_id, |
| 87 audio_manager, | 88 audio_manager, |
| 88 mirroring_manager, | 89 mirroring_manager, |
| 89 media_internals, | 90 media_internals, |
| 90 media_stream_manager, | 91 media_stream_manager, |
| 91 salt), | 92 salt), |
| 92 shared_memory_length_(0), | 93 shared_memory_length_(0), |
| 93 auth_run_loop_(auth_run_loop) { | 94 auth_run_loop_(auth_run_loop) { |
| 94 set_render_frame_id_validate_function_for_testing(&ValidateRenderFrameId); | 95 set_render_frame_id_validate_function_for_testing(&ValidateRenderFrameId); |
| 95 } | 96 } |
| 96 | 97 |
| 97 // A list of mock methods. | 98 // A list of mock methods. |
| 98 MOCK_METHOD0(ShutdownForBadMessage, void()); | |
| 99 MOCK_METHOD4(OnDeviceAuthorized, | 99 MOCK_METHOD4(OnDeviceAuthorized, |
| 100 void(int stream_id, | 100 void(int stream_id, |
| 101 media::OutputDeviceStatus device_status, | 101 media::OutputDeviceStatus device_status, |
| 102 const media::AudioParameters& output_params, | 102 const media::AudioParameters& output_params, |
| 103 const std::string& matched_device_id)); | 103 const std::string& matched_device_id)); |
| 104 MOCK_METHOD2(OnStreamCreated, void(int stream_id, int length)); | 104 MOCK_METHOD2(OnStreamCreated, void(int stream_id, int length)); |
| 105 MOCK_METHOD1(OnStreamError, void(int stream_id)); | 105 MOCK_METHOD1(OnStreamError, void(int stream_id)); |
| 106 | 106 |
| 107 void ShutdownForBadMessage() override { bad_msg_count++; } |
| 108 |
| 109 int bad_msg_count = 0; |
| 110 |
| 107 private: | 111 private: |
| 108 virtual ~MockAudioRendererHost() { | 112 virtual ~MockAudioRendererHost() { |
| 109 // Make sure all audio streams have been deleted. | 113 // Make sure all audio streams have been deleted. |
| 110 EXPECT_TRUE(audio_entries_.empty()); | 114 EXPECT_TRUE(audio_entries_.empty()); |
| 111 } | 115 } |
| 112 | 116 |
| 113 // This method is used to dispatch IPC messages to the renderer. We intercept | 117 // This method is used to dispatch IPC messages to the renderer. We intercept |
| 114 // these messages here and dispatch to our mock methods to verify the | 118 // these messages here and dispatch to our mock methods to verify the |
| 115 // conversation between this object and the renderer. | 119 // conversation between this object and the renderer. |
| 116 // Note: this means that file descriptors won't be duplicated, | 120 // Note: this means that file descriptors won't be duplicated, |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 std::unique_ptr<base::SharedMemory> shared_memory_; | 174 std::unique_ptr<base::SharedMemory> shared_memory_; |
| 171 std::unique_ptr<base::SyncSocket> sync_socket_; | 175 std::unique_ptr<base::SyncSocket> sync_socket_; |
| 172 uint32_t shared_memory_length_; | 176 uint32_t shared_memory_length_; |
| 173 base::RunLoop* auth_run_loop_; // Used to wait for authorization. | 177 base::RunLoop* auth_run_loop_; // Used to wait for authorization. |
| 174 | 178 |
| 175 DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost); | 179 DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost); |
| 176 }; | 180 }; |
| 177 | 181 |
| 178 class AudioRendererHostTest : public testing::Test { | 182 class AudioRendererHostTest : public testing::Test { |
| 179 public: | 183 public: |
| 180 AudioRendererHostTest() { | 184 AudioRendererHostTest() : render_process_host_(&browser_context_) { |
| 181 audio_manager_ = media::AudioManager::CreateForTesting( | 185 audio_manager_ = media::AudioManager::CreateForTesting( |
| 182 base::ThreadTaskRunnerHandle::Get()); | 186 base::ThreadTaskRunnerHandle::Get()); |
| 183 base::CommandLine::ForCurrentProcess()->AppendSwitch( | 187 base::CommandLine::ForCurrentProcess()->AppendSwitch( |
| 184 switches::kUseFakeDeviceForMediaStream); | 188 switches::kUseFakeDeviceForMediaStream); |
| 185 media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get())); | 189 media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get())); |
| 186 host_ = new MockAudioRendererHost( | 190 host_ = new MockAudioRendererHost( |
| 187 &auth_run_loop_, audio_manager_.get(), &mirroring_manager_, | 191 &auth_run_loop_, render_process_host_.GetID(), audio_manager_.get(), |
| 188 MediaInternals::GetInstance(), media_stream_manager_.get(), | 192 &mirroring_manager_, MediaInternals::GetInstance(), |
| 189 std::string()); | 193 media_stream_manager_.get(), std::string()); |
| 190 | |
| 191 EXPECT_CALL(*host_, ShutdownForBadMessage()).Times(0); | |
| 192 | 194 |
| 193 // Simulate IPC channel connected. | 195 // Simulate IPC channel connected. |
| 194 host_->set_peer_process_for_testing(base::Process::Current()); | 196 host_->set_peer_process_for_testing(base::Process::Current()); |
| 195 } | 197 } |
| 196 | 198 |
| 197 ~AudioRendererHostTest() override { | 199 ~AudioRendererHostTest() override { |
| 198 // Simulate closing the IPC channel and give the audio thread time to close | 200 // Simulate closing the IPC channel and give the audio thread time to close |
| 199 // the underlying streams. | 201 // the underlying streams. |
| 200 host_->OnChannelClosing(); | 202 host_->OnChannelClosing(); |
| 201 SyncWithAudioThread(); | 203 SyncWithAudioThread(); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 219 ? media::OUTPUT_DEVICE_STATUS_OK | 221 ? media::OUTPUT_DEVICE_STATUS_OK |
| 220 : device_id == kBadDeviceId | 222 : device_id == kBadDeviceId |
| 221 ? media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED | 223 ? media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED |
| 222 : media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND; | 224 : media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND; |
| 223 | 225 |
| 224 EXPECT_CALL(*host_.get(), | 226 EXPECT_CALL(*host_.get(), |
| 225 OnDeviceAuthorized(kStreamId, expected_device_status, _, _)); | 227 OnDeviceAuthorized(kStreamId, expected_device_status, _, _)); |
| 226 | 228 |
| 227 if (expected_device_status == media::OUTPUT_DEVICE_STATUS_OK) { | 229 if (expected_device_status == media::OUTPUT_DEVICE_STATUS_OK) { |
| 228 EXPECT_CALL(*host_.get(), OnStreamCreated(kStreamId, _)); | 230 EXPECT_CALL(*host_.get(), OnStreamCreated(kStreamId, _)); |
| 229 EXPECT_CALL(mirroring_manager_, | 231 EXPECT_CALL(mirroring_manager_, AddDiverter(render_process_host_.GetID(), |
| 230 AddDiverter(kRenderProcessId, kRenderFrameId, NotNull())) | 232 kRenderFrameId, NotNull())) |
| 231 .RetiresOnSaturation(); | 233 .RetiresOnSaturation(); |
| 232 } | 234 } |
| 233 | 235 |
| 234 // Send a create stream message to the audio output stream and wait until | 236 // Send a create stream message to the audio output stream and wait until |
| 235 // we receive the created message. | 237 // we receive the created message. |
| 236 media::AudioParameters params( | 238 media::AudioParameters params( |
| 237 media::AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO, | 239 media::AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO, |
| 238 media::AudioParameters::kAudioCDSampleRate, 16, | 240 media::AudioParameters::kAudioCDSampleRate, 16, |
| 239 media::AudioParameters::kAudioCDSampleRate / 10); | 241 media::AudioParameters::kAudioCDSampleRate / 10); |
| 240 int session_id = 0; | 242 int session_id = 0; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 // closing an audio stream. | 339 // closing an audio stream. |
| 338 void SyncWithAudioThread() { | 340 void SyncWithAudioThread() { |
| 339 base::RunLoop().RunUntilIdle(); | 341 base::RunLoop().RunUntilIdle(); |
| 340 | 342 |
| 341 base::RunLoop run_loop; | 343 base::RunLoop run_loop; |
| 342 audio_manager_->GetTaskRunner()->PostTask( | 344 audio_manager_->GetTaskRunner()->PostTask( |
| 343 FROM_HERE, media::BindToCurrentLoop(run_loop.QuitClosure())); | 345 FROM_HERE, media::BindToCurrentLoop(run_loop.QuitClosure())); |
| 344 run_loop.Run(); | 346 run_loop.Run(); |
| 345 } | 347 } |
| 346 | 348 |
| 347 void ExpectShutdown() { | 349 void AssertBadMsgReported() { |
| 348 EXPECT_CALL(*host_, ShutdownForBadMessage()).Times(1); | 350 // Bad messages can be reported either directly to the RPH or through the |
| 351 // ARH, so we check both of them. |
| 352 EXPECT_EQ(render_process_host_.bad_msg_count() + host_->bad_msg_count, 1); |
| 349 } | 353 } |
| 350 | 354 |
| 351 private: | 355 private: |
| 352 // MediaStreamManager uses a DestructionObserver, so it must outlive the | 356 // MediaStreamManager uses a DestructionObserver, so it must outlive the |
| 353 // TestBrowserThreadBundle. | 357 // TestBrowserThreadBundle. |
| 354 std::unique_ptr<MediaStreamManager> media_stream_manager_; | 358 std::unique_ptr<MediaStreamManager> media_stream_manager_; |
| 355 TestBrowserThreadBundle thread_bundle_; | 359 TestBrowserThreadBundle thread_bundle_; |
| 356 media::ScopedAudioManagerPtr audio_manager_; | 360 media::ScopedAudioManagerPtr audio_manager_; |
| 357 MockAudioMirroringManager mirroring_manager_; | 361 MockAudioMirroringManager mirroring_manager_; |
| 362 TestBrowserContext browser_context_; |
| 363 MockRenderProcessHost render_process_host_; |
| 358 scoped_refptr<MockAudioRendererHost> host_; | 364 scoped_refptr<MockAudioRendererHost> host_; |
| 359 base::RunLoop auth_run_loop_; | 365 base::RunLoop auth_run_loop_; |
| 360 | 366 |
| 361 DISALLOW_COPY_AND_ASSIGN(AudioRendererHostTest); | 367 DISALLOW_COPY_AND_ASSIGN(AudioRendererHostTest); |
| 362 }; | 368 }; |
| 363 | 369 |
| 364 TEST_F(AudioRendererHostTest, CreateAndClose) { | 370 TEST_F(AudioRendererHostTest, CreateAndClose) { |
| 365 Create(); | 371 Create(); |
| 366 Close(); | 372 Close(); |
| 367 } | 373 } |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 Create(true, kDefaultDeviceId, url::Origin(GURL(kSecurityOrigin)), true); | 431 Create(true, kDefaultDeviceId, url::Origin(GURL(kSecurityOrigin)), true); |
| 426 Close(); | 432 Close(); |
| 427 } | 433 } |
| 428 | 434 |
| 429 TEST_F(AudioRendererHostTest, CreateUnauthorizedDevice) { | 435 TEST_F(AudioRendererHostTest, CreateUnauthorizedDevice) { |
| 430 Create(false, kBadDeviceId, url::Origin(GURL(kSecurityOrigin)), true); | 436 Create(false, kBadDeviceId, url::Origin(GURL(kSecurityOrigin)), true); |
| 431 Close(); | 437 Close(); |
| 432 } | 438 } |
| 433 | 439 |
| 434 TEST_F(AudioRendererHostTest, CreateDeviceWithAuthorizationPendingIsError) { | 440 TEST_F(AudioRendererHostTest, CreateDeviceWithAuthorizationPendingIsError) { |
| 435 ExpectShutdown(); | |
| 436 CreateWithoutWaitingForAuth(kBadDeviceId); | 441 CreateWithoutWaitingForAuth(kBadDeviceId); |
| 437 Close(); | 442 Close(); |
| 443 AssertBadMsgReported(); |
| 438 } | 444 } |
| 439 | 445 |
| 440 TEST_F(AudioRendererHostTest, CreateDeviceWithBadSecurityOrigin) { | 446 TEST_F(AudioRendererHostTest, CreateDeviceWithBadSecurityOrigin) { |
| 441 ExpectShutdown(); | |
| 442 RequestDeviceAuthorizationWithBadOrigin(kNondefaultDeviceId); | 447 RequestDeviceAuthorizationWithBadOrigin(kNondefaultDeviceId); |
| 443 Close(); | 448 Close(); |
| 449 AssertBadMsgReported(); |
| 444 } | 450 } |
| 445 | 451 |
| 446 TEST_F(AudioRendererHostTest, CreateInvalidDevice) { | 452 TEST_F(AudioRendererHostTest, CreateInvalidDevice) { |
| 447 Create(false, kInvalidDeviceId, url::Origin(GURL(kSecurityOrigin)), true); | 453 Create(false, kInvalidDeviceId, url::Origin(GURL(kSecurityOrigin)), true); |
| 448 Close(); | 454 Close(); |
| 449 } | 455 } |
| 450 | 456 |
| 451 TEST_F(AudioRendererHostTest, CreateFailsForInvalidRenderFrame) { | 457 TEST_F(AudioRendererHostTest, CreateFailsForInvalidRenderFrame) { |
| 452 CreateWithInvalidRenderFrameId(); | 458 CreateWithInvalidRenderFrameId(); |
| 453 Close(); | 459 Close(); |
| 454 } | 460 } |
| 455 | 461 |
| 456 // TODO(hclam): Add tests for data conversation in low latency mode. | 462 // TODO(hclam): Add tests for data conversation in low latency mode. |
| 457 | 463 |
| 458 } // namespace content | 464 } // namespace content |
| OLD | NEW |