Chromium Code Reviews| 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/browser/media_device_id.h" | |
| 21 #include "content/public/common/content_switches.h" | 22 #include "content/public/common/content_switches.h" |
| 23 #include "content/public/test/mock_render_process_host.h" | |
| 24 #include "content/public/test/test_browser_context.h" | |
| 22 #include "content/public/test/test_browser_thread_bundle.h" | 25 #include "content/public/test/test_browser_thread_bundle.h" |
| 23 #include "ipc/ipc_message_utils.h" | 26 #include "ipc/ipc_message_utils.h" |
| 24 #include "media/audio/audio_manager.h" | 27 #include "media/audio/fake_audio_log_factory.h" |
| 28 #include "media/audio/fake_audio_manager.h" | |
| 25 #include "media/base/bind_to_current_loop.h" | 29 #include "media/base/bind_to_current_loop.h" |
| 26 #include "media/base/media_switches.h" | 30 #include "media/base/media_switches.h" |
| 27 #include "testing/gmock/include/gmock/gmock.h" | 31 #include "testing/gmock/include/gmock/gmock.h" |
| 28 #include "testing/gtest/include/gtest/gtest.h" | 32 #include "testing/gtest/include/gtest/gtest.h" |
| 29 | 33 |
| 30 using ::testing::_; | 34 using ::testing::_; |
| 31 using ::testing::Assign; | 35 using ::testing::Assign; |
| 32 using ::testing::AtLeast; | 36 using ::testing::AtLeast; |
| 33 using ::testing::DoAll; | 37 using ::testing::DoAll; |
| 34 using ::testing::NotNull; | 38 using ::testing::NotNull; |
| 35 | 39 |
| 36 namespace content { | 40 namespace content { |
| 37 | 41 |
| 38 namespace { | 42 namespace { |
| 39 const int kRenderProcessId = 1; | |
| 40 const int kRenderFrameId = 5; | 43 const int kRenderFrameId = 5; |
| 41 const int kStreamId = 50; | 44 const int kStreamId = 50; |
| 42 const char kSecurityOrigin[] = "http://localhost"; | 45 const char kSecurityOrigin[] = "http://localhost"; |
| 43 const char kBadSecurityOrigin[] = "about:about"; | 46 const char kBadSecurityOrigin[] = "about:about"; |
| 44 const char kDefaultDeviceId[] = ""; | 47 const char kDefaultDeviceId[] = ""; |
| 48 const char kSalt[] = "salt"; | |
| 45 const char kNondefaultDeviceId[] = | 49 const char kNondefaultDeviceId[] = |
| 46 "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; | 50 "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; |
| 47 const char kBadDeviceId[] = | 51 const char kBadDeviceId[] = |
| 48 "badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad1"; | 52 "badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad1"; |
| 49 const char kInvalidDeviceId[] = "invalid-device-id"; | 53 const char kInvalidDeviceId[] = "invalid-device-id"; |
| 50 | 54 |
| 51 void ValidateRenderFrameId(int render_process_id, | 55 void ValidateRenderFrameId(int render_process_id, |
| 52 int render_frame_id, | 56 int render_frame_id, |
| 53 const base::Callback<void(bool)>& callback) { | 57 const base::Callback<void(bool)>& callback) { |
| 54 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 58 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 55 const bool frame_exists = (render_process_id == kRenderProcessId && | 59 const bool frame_exists = (render_frame_id == kRenderFrameId); |
| 56 render_frame_id == kRenderFrameId); | |
| 57 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 60 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 58 base::Bind(callback, frame_exists)); | 61 base::Bind(callback, frame_exists)); |
| 59 } | 62 } |
| 60 | 63 |
| 61 } // namespace | |
| 62 | 64 |
| 63 class MockAudioMirroringManager : public AudioMirroringManager { | 65 class MockAudioMirroringManager : public AudioMirroringManager { |
| 64 public: | 66 public: |
| 65 MockAudioMirroringManager() {} | 67 MockAudioMirroringManager() {} |
| 66 virtual ~MockAudioMirroringManager() {} | 68 virtual ~MockAudioMirroringManager() {} |
| 67 | 69 |
| 68 MOCK_METHOD3(AddDiverter, | 70 MOCK_METHOD3(AddDiverter, |
| 69 void(int render_process_id, | 71 void(int render_process_id, |
| 70 int render_frame_id, | 72 int render_frame_id, |
| 71 Diverter* diverter)); | 73 Diverter* diverter)); |
| 72 MOCK_METHOD1(RemoveDiverter, void(Diverter* diverter)); | 74 MOCK_METHOD1(RemoveDiverter, void(Diverter* diverter)); |
| 73 | 75 |
| 74 private: | 76 private: |
| 75 DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager); | 77 DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager); |
| 76 }; | 78 }; |
| 77 | 79 |
| 80 class MockRenderProcessHostWithSignaling : public MockRenderProcessHost { | |
| 81 public: | |
| 82 MockRenderProcessHostWithSignaling(BrowserContext* context, | |
| 83 base::RunLoop* auth_run_loop) | |
| 84 : MockRenderProcessHost(context), auth_run_loop_(auth_run_loop) {} | |
| 85 | |
| 86 void ShutdownForBadMessage(CrashReportMode crash_report_mode) override { | |
| 87 MockRenderProcessHost::ShutdownForBadMessage(crash_report_mode); | |
| 88 auth_run_loop_->Quit(); | |
| 89 } | |
| 90 | |
| 91 private: | |
| 92 base::RunLoop* auth_run_loop_; | |
| 93 }; | |
| 94 | |
| 95 class FakeAudioManagerWithAssociations : public media::FakeAudioManager { | |
| 96 public: | |
| 97 FakeAudioManagerWithAssociations( | |
| 98 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | |
| 99 media::AudioLogFactory* factory) | |
| 100 : FakeAudioManager(task_runner, task_runner, factory) {} | |
| 101 | |
| 102 void CreateDeviceAssociation(const std::string& input_device_id, | |
| 103 const std::string& output_device_id) { | |
| 104 // We shouldn't accidentally add hashed ids, since the audio manager | |
| 105 // works with raw ids. | |
|
Guido Urdaneta
2016/11/10 15:26:05
Does the audio manager not work with default and c
| |
| 106 EXPECT_FALSE(IsValidDeviceId(input_device_id)); | |
| 107 EXPECT_FALSE(IsValidDeviceId(output_device_id)); | |
| 108 | |
| 109 associations_[input_device_id] = output_device_id; | |
| 110 } | |
| 111 | |
| 112 std::string GetAssociatedOutputDeviceID( | |
| 113 const std::string& input_id) override { | |
| 114 auto it = associations_.find(input_id); | |
| 115 return it == associations_.end() ? "" : it->second; | |
| 116 } | |
| 117 | |
| 118 private: | |
| 119 std::map<std::string, std::string> associations_; | |
| 120 }; | |
| 121 | |
| 122 } // namespace | |
| 123 | |
| 78 class MockAudioRendererHost : public AudioRendererHost { | 124 class MockAudioRendererHost : public AudioRendererHost { |
| 79 public: | 125 public: |
| 80 MockAudioRendererHost(base::RunLoop* auth_run_loop, | 126 MockAudioRendererHost(base::RunLoop* auth_run_loop, |
| 127 int render_process_id, | |
| 81 media::AudioManager* audio_manager, | 128 media::AudioManager* audio_manager, |
| 82 AudioMirroringManager* mirroring_manager, | 129 AudioMirroringManager* mirroring_manager, |
| 83 MediaInternals* media_internals, | 130 MediaInternals* media_internals, |
| 84 MediaStreamManager* media_stream_manager, | 131 MediaStreamManager* media_stream_manager, |
| 85 const std::string& salt) | 132 const std::string& salt) |
| 86 : AudioRendererHost(kRenderProcessId, | 133 : AudioRendererHost(render_process_id, |
| 87 audio_manager, | 134 audio_manager, |
| 88 mirroring_manager, | 135 mirroring_manager, |
| 89 media_internals, | 136 media_internals, |
| 90 media_stream_manager, | 137 media_stream_manager, |
| 91 salt), | 138 salt), |
| 92 shared_memory_length_(0), | 139 shared_memory_length_(0), |
| 93 auth_run_loop_(auth_run_loop) { | 140 auth_run_loop_(auth_run_loop) { |
| 94 set_render_frame_id_validate_function_for_testing(&ValidateRenderFrameId); | 141 set_render_frame_id_validate_function_for_testing(&ValidateRenderFrameId); |
| 95 } | 142 } |
| 96 | 143 |
| 97 // A list of mock methods. | 144 // A list of mock methods. |
| 98 MOCK_METHOD0(ShutdownForBadMessage, void()); | |
| 99 MOCK_METHOD4(OnDeviceAuthorized, | 145 MOCK_METHOD4(OnDeviceAuthorized, |
| 100 void(int stream_id, | 146 void(int stream_id, |
| 101 media::OutputDeviceStatus device_status, | 147 media::OutputDeviceStatus device_status, |
| 102 const media::AudioParameters& output_params, | 148 const media::AudioParameters& output_params, |
| 103 const std::string& matched_device_id)); | 149 const std::string& matched_device_id)); |
| 104 MOCK_METHOD2(OnStreamCreated, void(int stream_id, int length)); | 150 MOCK_METHOD2(OnStreamCreated, void(int stream_id, int length)); |
| 105 MOCK_METHOD1(OnStreamError, void(int stream_id)); | 151 MOCK_METHOD1(OnStreamError, void(int stream_id)); |
| 106 | 152 |
| 153 void ShutdownForBadMessage() override { bad_msg_count++; } | |
| 154 | |
| 155 int bad_msg_count = 0; | |
| 156 | |
| 107 private: | 157 private: |
| 108 virtual ~MockAudioRendererHost() { | 158 virtual ~MockAudioRendererHost() { |
| 109 // Make sure all audio streams have been deleted. | 159 // Make sure all audio streams have been deleted. |
| 110 EXPECT_TRUE(audio_entries_.empty()); | 160 EXPECT_TRUE(audio_entries_.empty()); |
| 111 } | 161 } |
| 112 | 162 |
| 113 // This method is used to dispatch IPC messages to the renderer. We intercept | 163 // 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 | 164 // these messages here and dispatch to our mock methods to verify the |
| 115 // conversation between this object and the renderer. | 165 // conversation between this object and the renderer. |
| 116 // Note: this means that file descriptors won't be duplicated, | 166 // Note: this means that file descriptors won't be duplicated, |
| 117 // leading to double-close errors from SyncSocket. | 167 // leading to double-close errors from SyncSocket. |
| 118 // See crbug.com/647659. | 168 // See crbug.com/647659. |
| 119 virtual bool Send(IPC::Message* message) { | 169 bool Send(IPC::Message* message) override { |
| 120 CHECK(message); | 170 CHECK(message); |
| 121 | 171 |
| 122 // In this method we dispatch the messages to the according handlers as if | 172 // In this method we dispatch the messages to the according handlers as if |
| 123 // we are the renderer. | 173 // we are the renderer. |
| 124 bool handled = true; | 174 bool handled = true; |
| 125 IPC_BEGIN_MESSAGE_MAP(MockAudioRendererHost, *message) | 175 IPC_BEGIN_MESSAGE_MAP(MockAudioRendererHost, *message) |
| 126 IPC_MESSAGE_HANDLER(AudioMsg_NotifyDeviceAuthorized, | 176 IPC_MESSAGE_HANDLER(AudioMsg_NotifyDeviceAuthorized, |
| 127 OnNotifyDeviceAuthorized) | 177 OnNotifyDeviceAuthorized) |
| 128 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamCreated, | 178 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamCreated, |
| 129 OnNotifyStreamCreated) | 179 OnNotifyStreamCreated) |
| 130 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamError, OnNotifyStreamError) | 180 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamError, OnNotifyStreamError) |
| 131 IPC_MESSAGE_UNHANDLED(handled = false) | 181 IPC_MESSAGE_UNHANDLED(handled = false) |
| 132 IPC_END_MESSAGE_MAP() | 182 IPC_END_MESSAGE_MAP() |
| 133 EXPECT_TRUE(handled); | 183 EXPECT_TRUE(handled); |
| 134 | 184 |
| 135 delete message; | 185 delete message; |
| 136 return true; | 186 return true; |
| 137 } | 187 } |
| 138 | 188 |
| 139 void OnNotifyDeviceAuthorized(int stream_id, | 189 void OnNotifyDeviceAuthorized(int stream_id, |
| 140 media::OutputDeviceStatus device_status, | 190 media::OutputDeviceStatus device_status, |
| 141 const media::AudioParameters& output_params, | 191 const media::AudioParameters& output_params, |
| 142 const std::string& matched_device_id) { | 192 const std::string& matched_device_id) { |
| 193 // Make sure we didn't leak a raw device id. | |
| 194 EXPECT_TRUE(IsValidDeviceId(matched_device_id)); | |
| 195 | |
| 143 OnDeviceAuthorized(stream_id, device_status, output_params, | 196 OnDeviceAuthorized(stream_id, device_status, output_params, |
| 144 matched_device_id); | 197 matched_device_id); |
| 145 auth_run_loop_->Quit(); | 198 auth_run_loop_->Quit(); |
| 146 } | 199 } |
| 147 | 200 |
| 148 void OnNotifyStreamCreated( | 201 void OnNotifyStreamCreated( |
| 149 int stream_id, | 202 int stream_id, |
| 150 base::SharedMemoryHandle handle, | 203 base::SharedMemoryHandle handle, |
| 151 base::SyncSocket::TransitDescriptor socket_descriptor, | 204 base::SyncSocket::TransitDescriptor socket_descriptor, |
| 152 uint32_t length) { | 205 uint32_t length) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 170 std::unique_ptr<base::SharedMemory> shared_memory_; | 223 std::unique_ptr<base::SharedMemory> shared_memory_; |
| 171 std::unique_ptr<base::SyncSocket> sync_socket_; | 224 std::unique_ptr<base::SyncSocket> sync_socket_; |
| 172 uint32_t shared_memory_length_; | 225 uint32_t shared_memory_length_; |
| 173 base::RunLoop* auth_run_loop_; // Used to wait for authorization. | 226 base::RunLoop* auth_run_loop_; // Used to wait for authorization. |
| 174 | 227 |
| 175 DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost); | 228 DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost); |
| 176 }; | 229 }; |
| 177 | 230 |
| 178 class AudioRendererHostTest : public testing::Test { | 231 class AudioRendererHostTest : public testing::Test { |
| 179 public: | 232 public: |
| 180 AudioRendererHostTest() { | 233 AudioRendererHostTest() |
| 181 audio_manager_ = media::AudioManager::CreateForTesting( | 234 : render_process_host_(&browser_context_, &auth_run_loop_), |
| 182 base::ThreadTaskRunnerHandle::Get()); | 235 log_factory(base::MakeUnique<media::FakeAudioLogFactory>()), |
| 236 audio_manager_(base::MakeUnique<FakeAudioManagerWithAssociations>( | |
| 237 base::ThreadTaskRunnerHandle::Get(), | |
| 238 log_factory.get())) { | |
| 183 base::CommandLine::ForCurrentProcess()->AppendSwitch( | 239 base::CommandLine::ForCurrentProcess()->AppendSwitch( |
| 184 switches::kUseFakeDeviceForMediaStream); | 240 switches::kUseFakeDeviceForMediaStream); |
| 185 media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get())); | 241 media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get())); |
| 186 host_ = new MockAudioRendererHost( | 242 host_ = new MockAudioRendererHost( |
| 187 &auth_run_loop_, audio_manager_.get(), &mirroring_manager_, | 243 &auth_run_loop_, render_process_host_.GetID(), audio_manager_.get(), |
| 188 MediaInternals::GetInstance(), media_stream_manager_.get(), | 244 &mirroring_manager_, MediaInternals::GetInstance(), |
| 189 std::string()); | 245 media_stream_manager_.get(), kSalt); |
| 190 | |
| 191 EXPECT_CALL(*host_, ShutdownForBadMessage()).Times(0); | |
| 192 | 246 |
| 193 // Simulate IPC channel connected. | 247 // Simulate IPC channel connected. |
| 194 host_->set_peer_process_for_testing(base::Process::Current()); | 248 host_->set_peer_process_for_testing(base::Process::Current()); |
| 195 } | 249 } |
| 196 | 250 |
| 197 ~AudioRendererHostTest() override { | 251 ~AudioRendererHostTest() override { |
| 198 // Simulate closing the IPC channel and give the audio thread time to close | 252 // Simulate closing the IPC channel and give the audio thread time to close |
| 199 // the underlying streams. | 253 // the underlying streams. |
| 200 host_->OnChannelClosing(); | 254 host_->OnChannelClosing(); |
| 201 SyncWithAudioThread(); | 255 SyncWithAudioThread(); |
| 202 | 256 |
| 203 // Release the reference to the mock object. The object will be destructed | 257 // Release the reference to the mock object. The object will be destructed |
| 204 // on message_loop_. | 258 // on message_loop_. |
| 205 host_ = NULL; | 259 host_ = NULL; |
| 206 } | 260 } |
| 207 | 261 |
| 208 protected: | 262 protected: |
| 209 void Create() { | 263 void OverrideDevicePermissions(bool has_permissions) { |
| 210 Create(false, kDefaultDeviceId, url::Origin(GURL(kSecurityOrigin)), true); | 264 host_->OverrideDevicePermissionsForTesting(has_permissions); |
| 211 } | 265 } |
| 212 | 266 |
| 213 void Create(bool unified_stream, | 267 std::string GetNondefaultIdExpectedToPassPermissionsCheck() { |
| 214 const std::string& device_id, | 268 std::string nondefault_id; |
| 269 | |
| 270 MediaDevicesManager::BoolDeviceTypes devices_to_enumerate; | |
| 271 devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT] = true; | |
| 272 media_stream_manager_->media_devices_manager()->EnumerateDevices( | |
| 273 devices_to_enumerate, | |
| 274 base::Bind( | |
| 275 [](std::string* out, const MediaDeviceEnumeration& result) { | |
| 276 // Index 0 is default, so use 1. | |
|
Guido Urdaneta
2016/11/10 15:26:05
Shouldn't you have a check or expectation that the
Max Morin
2016/11/11 09:26:55
Done (size > 1).
| |
| 277 *out = result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_OUTPUT][1] | |
| 278 .device_id; | |
| 279 }, | |
| 280 base::Unretained(&nondefault_id))); | |
| 281 | |
| 282 // Make sure nondefault_id is set before returning. | |
| 283 base::RunLoop().RunUntilIdle(); | |
| 284 | |
| 285 return nondefault_id; | |
| 286 } | |
| 287 | |
| 288 std::string GetNondefaultInputId() { | |
| 289 std::string nondefault_id; | |
| 290 | |
| 291 MediaDevicesManager::BoolDeviceTypes devices_to_enumerate; | |
| 292 devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_INPUT] = true; | |
| 293 media_stream_manager_->media_devices_manager()->EnumerateDevices( | |
| 294 devices_to_enumerate, | |
| 295 base::Bind( | |
| 296 [](std::string* out, const MediaDeviceEnumeration& result) { | |
| 297 *out = result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_INPUT][1] | |
| 298 .device_id; | |
| 299 }, | |
| 300 base::Unretained(&nondefault_id))); | |
| 301 | |
| 302 base::RunLoop().RunUntilIdle(); | |
| 303 | |
| 304 return nondefault_id; | |
| 305 } | |
| 306 | |
| 307 void Create() { | |
| 308 Create(kDefaultDeviceId, url::Origin(GURL(kSecurityOrigin)), true, true); | |
| 309 } | |
| 310 | |
| 311 void Create(const std::string& device_id, | |
| 215 const url::Origin& security_origin, | 312 const url::Origin& security_origin, |
| 216 bool wait_for_auth) { | 313 bool wait_for_auth, |
| 314 bool expect_onauthorized) { | |
| 217 media::OutputDeviceStatus expected_device_status = | 315 media::OutputDeviceStatus expected_device_status = |
| 218 device_id == kDefaultDeviceId | 316 device_id == kDefaultDeviceId || |
| 317 device_id == | |
| 318 MediaStreamManager::GetHMACForMediaDeviceID( | |
| 319 kSalt, url::Origin(GURL(kSecurityOrigin)), | |
| 320 GetNondefaultIdExpectedToPassPermissionsCheck()) | |
| 219 ? media::OUTPUT_DEVICE_STATUS_OK | 321 ? media::OUTPUT_DEVICE_STATUS_OK |
| 220 : device_id == kBadDeviceId | 322 : device_id == kBadDeviceId |
| 221 ? media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED | 323 ? media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED |
| 222 : media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND; | 324 : media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND; |
| 223 | 325 |
| 224 EXPECT_CALL(*host_.get(), | 326 if (expect_onauthorized) |
| 225 OnDeviceAuthorized(kStreamId, expected_device_status, _, _)); | 327 EXPECT_CALL(*host_.get(), |
| 328 OnDeviceAuthorized(kStreamId, expected_device_status, _, _)); | |
| 226 | 329 |
| 227 if (expected_device_status == media::OUTPUT_DEVICE_STATUS_OK) { | 330 if (expected_device_status == media::OUTPUT_DEVICE_STATUS_OK) { |
| 228 EXPECT_CALL(*host_.get(), OnStreamCreated(kStreamId, _)); | 331 EXPECT_CALL(*host_.get(), OnStreamCreated(kStreamId, _)); |
| 229 EXPECT_CALL(mirroring_manager_, | 332 EXPECT_CALL(mirroring_manager_, AddDiverter(render_process_host_.GetID(), |
| 230 AddDiverter(kRenderProcessId, kRenderFrameId, NotNull())) | 333 kRenderFrameId, NotNull())) |
| 231 .RetiresOnSaturation(); | 334 .RetiresOnSaturation(); |
| 232 } | 335 } |
| 233 | 336 |
| 234 // Send a create stream message to the audio output stream and wait until | 337 // Send a create stream message to the audio output stream and wait until |
| 235 // we receive the created message. | 338 // we receive the created message. |
| 236 media::AudioParameters params( | 339 media::AudioParameters params( |
| 237 media::AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO, | 340 media::AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO, |
| 238 media::AudioParameters::kAudioCDSampleRate, 16, | 341 media::AudioParameters::kAudioCDSampleRate, 16, |
| 239 media::AudioParameters::kAudioCDSampleRate / 10); | 342 media::AudioParameters::kAudioCDSampleRate / 10); |
| 240 int session_id = 0; | 343 int session_id = 0; |
| 241 if (unified_stream) { | 344 |
| 242 // Use AudioInputDeviceManager::kFakeOpenSessionId as the session id to | |
| 243 // pass the permission check. | |
| 244 session_id = AudioInputDeviceManager::kFakeOpenSessionId; | |
| 245 } | |
| 246 host_->OnRequestDeviceAuthorization(kStreamId, kRenderFrameId, session_id, | 345 host_->OnRequestDeviceAuthorization(kStreamId, kRenderFrameId, session_id, |
| 247 device_id, security_origin); | 346 device_id, security_origin); |
| 248 if (wait_for_auth) | 347 if (wait_for_auth) |
| 249 auth_run_loop_.Run(); | 348 auth_run_loop_.Run(); |
| 250 | 349 |
| 251 if (!wait_for_auth || | 350 if (!wait_for_auth || |
| 252 expected_device_status == media::OUTPUT_DEVICE_STATUS_OK) | 351 expected_device_status == media::OUTPUT_DEVICE_STATUS_OK) |
| 253 host_->OnCreateStream(kStreamId, kRenderFrameId, params); | 352 host_->OnCreateStream(kStreamId, kRenderFrameId, params); |
| 254 | 353 |
| 255 if (expected_device_status == media::OUTPUT_DEVICE_STATUS_OK) | 354 if (expected_device_status == media::OUTPUT_DEVICE_STATUS_OK) |
| 256 // At some point in the future, a corresponding RemoveDiverter() call must | 355 // At some point in the future, a corresponding RemoveDiverter() call must |
| 257 // be made. | 356 // be made. |
| 258 EXPECT_CALL(mirroring_manager_, RemoveDiverter(NotNull())) | 357 EXPECT_CALL(mirroring_manager_, RemoveDiverter(NotNull())) |
| 259 .RetiresOnSaturation(); | 358 .RetiresOnSaturation(); |
| 260 SyncWithAudioThread(); | 359 SyncWithAudioThread(); |
| 261 } | 360 } |
| 262 | 361 |
| 263 void RequestDeviceAuthorizationWithBadOrigin(const std::string& device_id) { | 362 void RequestDeviceAuthorizationWithBadOrigin(const std::string& device_id) { |
| 264 int session_id = 0; | 363 int session_id = 0; |
| 265 host_->OnRequestDeviceAuthorization(kStreamId, kRenderFrameId, session_id, | 364 host_->OnRequestDeviceAuthorization(kStreamId, kRenderFrameId, session_id, |
| 266 device_id, | 365 device_id, |
| 267 url::Origin(GURL(kBadSecurityOrigin))); | 366 url::Origin(GURL(kBadSecurityOrigin))); |
| 268 SyncWithAudioThread(); | 367 SyncWithAudioThread(); |
| 269 } | 368 } |
| 270 | 369 |
| 271 void CreateWithoutWaitingForAuth(const std::string& device_id) { | 370 void CreateWithoutWaitingForAuth(const std::string& device_id) { |
| 272 Create(false, device_id, url::Origin(GURL(kSecurityOrigin)), false); | 371 Create(device_id, url::Origin(GURL(kSecurityOrigin)), false, false); |
| 273 } | 372 } |
| 274 | 373 |
| 275 void CreateWithInvalidRenderFrameId() { | 374 void CreateWithInvalidRenderFrameId() { |
| 276 // When creating a stream with an invalid render frame ID, the host will | 375 // When creating a stream with an invalid render frame ID, the host will |
| 277 // reply with a stream error message. | 376 // reply with a stream error message. |
| 278 EXPECT_CALL(*host_, OnStreamError(kStreamId)); | 377 EXPECT_CALL(*host_, OnStreamError(kStreamId)); |
| 279 | 378 |
| 280 // However, validation does not block stream creation, so these method calls | 379 // However, validation does not block stream creation, so these method calls |
| 281 // might be made: | 380 // might be made: |
| 282 EXPECT_CALL(*host_, OnStreamCreated(kStreamId, _)).Times(AtLeast(0)); | 381 EXPECT_CALL(*host_, OnStreamCreated(kStreamId, _)).Times(AtLeast(0)); |
| 283 EXPECT_CALL(mirroring_manager_, AddDiverter(_, _, _)).Times(AtLeast(0)); | 382 EXPECT_CALL(mirroring_manager_, AddDiverter(_, _, _)).Times(AtLeast(0)); |
| 284 EXPECT_CALL(mirroring_manager_, RemoveDiverter(_)).Times(AtLeast(0)); | 383 EXPECT_CALL(mirroring_manager_, RemoveDiverter(_)).Times(AtLeast(0)); |
| 285 | 384 |
| 286 // Provide a seemingly-valid render frame ID; and it should be rejected when | 385 // Provide a seemingly-valid render frame ID; and it should be rejected when |
| 287 // AudioRendererHost calls ValidateRenderFrameId(). | 386 // AudioRendererHost calls ValidateRenderFrameId(). |
| 288 const int kInvalidRenderFrameId = kRenderFrameId + 1; | 387 const int kInvalidRenderFrameId = kRenderFrameId + 1; |
| 289 const media::AudioParameters params( | 388 const media::AudioParameters params( |
| 290 media::AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO, | 389 media::AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO, |
| 291 media::AudioParameters::kAudioCDSampleRate, 16, | 390 media::AudioParameters::kAudioCDSampleRate, 16, |
| 292 media::AudioParameters::kAudioCDSampleRate / 10); | 391 media::AudioParameters::kAudioCDSampleRate / 10); |
| 293 host_->OnCreateStream(kStreamId, kInvalidRenderFrameId, params); | 392 host_->OnCreateStream(kStreamId, kInvalidRenderFrameId, params); |
| 294 base::RunLoop().RunUntilIdle(); | 393 base::RunLoop().RunUntilIdle(); |
| 295 } | 394 } |
| 296 | 395 |
| 396 void CreateUnifiedStream(const url::Origin& security_origin) { | |
| 397 std::string output_id = GetNondefaultIdExpectedToPassPermissionsCheck(); | |
| 398 std::string input_id = GetNondefaultInputId(); | |
| 399 std::string hashed_output_id = MediaStreamManager::GetHMACForMediaDeviceID( | |
| 400 kSalt, url::Origin(GURL(kSecurityOrigin)), output_id); | |
| 401 // Set up association between input and output so that the output | |
| 402 // device gets selected when using session id: | |
| 403 audio_manager_->CreateDeviceAssociation(input_id, output_id); | |
| 404 int session_id = media_stream_manager_->audio_input_device_manager()->Open( | |
| 405 StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE, "Fake input device", | |
| 406 input_id)); | |
| 407 base::RunLoop().RunUntilIdle(); | |
| 408 | |
| 409 // Send a create stream message to the audio output stream and wait until | |
| 410 // we receive the created message. | |
| 411 media::AudioParameters params( | |
| 412 media::AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO, | |
| 413 media::AudioParameters::kAudioCDSampleRate, 16, | |
| 414 media::AudioParameters::kAudioCDSampleRate / 10); | |
| 415 | |
| 416 EXPECT_CALL(*host_.get(), | |
| 417 OnDeviceAuthorized(kStreamId, media::OUTPUT_DEVICE_STATUS_OK, _, | |
| 418 hashed_output_id)) | |
| 419 .Times(1); | |
| 420 EXPECT_CALL(*host_.get(), OnStreamCreated(kStreamId, _)); | |
| 421 EXPECT_CALL(mirroring_manager_, AddDiverter(render_process_host_.GetID(), | |
| 422 kRenderFrameId, NotNull())) | |
| 423 .RetiresOnSaturation(); | |
| 424 EXPECT_CALL(mirroring_manager_, RemoveDiverter(NotNull())) | |
| 425 .RetiresOnSaturation(); | |
| 426 | |
| 427 host_->OnRequestDeviceAuthorization(kStreamId, kRenderFrameId, session_id, | |
| 428 /*device id*/ std::string(), | |
| 429 security_origin); | |
| 430 | |
| 431 auth_run_loop_.Run(); | |
| 432 | |
| 433 host_->OnCreateStream(kStreamId, kRenderFrameId, params); | |
| 434 | |
| 435 SyncWithAudioThread(); | |
| 436 } | |
| 437 | |
| 297 void Close() { | 438 void Close() { |
| 298 // Send a message to AudioRendererHost to tell it we want to close the | 439 // Send a message to AudioRendererHost to tell it we want to close the |
| 299 // stream. | 440 // stream. |
| 300 host_->OnCloseStream(kStreamId); | 441 host_->OnCloseStream(kStreamId); |
| 301 SyncWithAudioThread(); | 442 SyncWithAudioThread(); |
| 302 } | 443 } |
| 303 | 444 |
| 304 void Play() { | 445 void Play() { |
| 305 host_->OnPlayStream(kStreamId); | 446 host_->OnPlayStream(kStreamId); |
| 306 SyncWithAudioThread(); | 447 SyncWithAudioThread(); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 337 // closing an audio stream. | 478 // closing an audio stream. |
| 338 void SyncWithAudioThread() { | 479 void SyncWithAudioThread() { |
| 339 base::RunLoop().RunUntilIdle(); | 480 base::RunLoop().RunUntilIdle(); |
| 340 | 481 |
| 341 base::RunLoop run_loop; | 482 base::RunLoop run_loop; |
| 342 audio_manager_->GetTaskRunner()->PostTask( | 483 audio_manager_->GetTaskRunner()->PostTask( |
| 343 FROM_HERE, media::BindToCurrentLoop(run_loop.QuitClosure())); | 484 FROM_HERE, media::BindToCurrentLoop(run_loop.QuitClosure())); |
| 344 run_loop.Run(); | 485 run_loop.Run(); |
| 345 } | 486 } |
| 346 | 487 |
| 347 void ExpectShutdown() { | 488 void AssertBadMsgReported() { |
| 348 EXPECT_CALL(*host_, ShutdownForBadMessage()).Times(1); | 489 // Bad messages can be reported either directly to the RPH or through the |
| 490 // ARH, so we check both of them. | |
| 491 EXPECT_EQ(render_process_host_.bad_msg_count() + host_->bad_msg_count, 1); | |
| 349 } | 492 } |
| 350 | 493 |
| 351 private: | 494 private: |
| 352 // MediaStreamManager uses a DestructionObserver, so it must outlive the | 495 // MediaStreamManager uses a DestructionObserver, so it must outlive the |
| 353 // TestBrowserThreadBundle. | 496 // TestBrowserThreadBundle. |
| 354 std::unique_ptr<MediaStreamManager> media_stream_manager_; | 497 std::unique_ptr<MediaStreamManager> media_stream_manager_; |
| 355 TestBrowserThreadBundle thread_bundle_; | 498 TestBrowserThreadBundle thread_bundle_; |
| 356 media::ScopedAudioManagerPtr audio_manager_; | 499 TestBrowserContext browser_context_; |
| 500 MockRenderProcessHostWithSignaling render_process_host_; | |
| 501 std::unique_ptr<media::FakeAudioLogFactory> log_factory; | |
| 502 std::unique_ptr<FakeAudioManagerWithAssociations> audio_manager_; | |
| 357 MockAudioMirroringManager mirroring_manager_; | 503 MockAudioMirroringManager mirroring_manager_; |
| 504 base::RunLoop auth_run_loop_; | |
| 358 scoped_refptr<MockAudioRendererHost> host_; | 505 scoped_refptr<MockAudioRendererHost> host_; |
| 359 base::RunLoop auth_run_loop_; | |
| 360 | 506 |
| 361 DISALLOW_COPY_AND_ASSIGN(AudioRendererHostTest); | 507 DISALLOW_COPY_AND_ASSIGN(AudioRendererHostTest); |
| 362 }; | 508 }; |
| 363 | 509 |
| 364 TEST_F(AudioRendererHostTest, CreateAndClose) { | 510 TEST_F(AudioRendererHostTest, CreateAndClose) { |
| 365 Create(); | 511 Create(); |
| 366 Close(); | 512 Close(); |
| 367 } | 513 } |
| 368 | 514 |
| 369 // Simulate the case where a stream is not properly closed. | 515 // Simulate the case where a stream is not properly closed. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 415 // the audio device is closed but the render process try to close the | 561 // the audio device is closed but the render process try to close the |
| 416 // audio stream again. | 562 // audio stream again. |
| 417 TEST_F(AudioRendererHostTest, SimulateErrorAndClose) { | 563 TEST_F(AudioRendererHostTest, SimulateErrorAndClose) { |
| 418 Create(); | 564 Create(); |
| 419 Play(); | 565 Play(); |
| 420 SimulateError(); | 566 SimulateError(); |
| 421 Close(); | 567 Close(); |
| 422 } | 568 } |
| 423 | 569 |
| 424 TEST_F(AudioRendererHostTest, CreateUnifiedStreamAndClose) { | 570 TEST_F(AudioRendererHostTest, CreateUnifiedStreamAndClose) { |
| 425 Create(true, kDefaultDeviceId, url::Origin(GURL(kSecurityOrigin)), true); | 571 CreateUnifiedStream(url::Origin(GURL(kSecurityOrigin))); |
| 426 Close(); | 572 Close(); |
| 427 } | 573 } |
| 428 | 574 |
| 429 TEST_F(AudioRendererHostTest, CreateUnauthorizedDevice) { | 575 TEST_F(AudioRendererHostTest, CreateUnauthorizedDevice) { |
| 430 Create(false, kBadDeviceId, url::Origin(GURL(kSecurityOrigin)), true); | 576 Create(kBadDeviceId, url::Origin(GURL(kSecurityOrigin)), true, true); |
| 577 // Close(); | |
| 578 } | |
| 579 | |
| 580 TEST_F(AudioRendererHostTest, CreateAuthorizedDevice) { | |
| 581 OverrideDevicePermissions(true); | |
| 582 std::string id = GetNondefaultIdExpectedToPassPermissionsCheck(); | |
| 583 std::string hashed_id = MediaStreamManager::GetHMACForMediaDeviceID( | |
| 584 kSalt, url::Origin(GURL(kSecurityOrigin)), id); | |
| 585 Create(hashed_id, url::Origin(GURL(kSecurityOrigin)), true, true); | |
| 431 Close(); | 586 Close(); |
| 432 } | 587 } |
| 433 | 588 |
| 434 TEST_F(AudioRendererHostTest, CreateDeviceWithAuthorizationPendingIsError) { | 589 TEST_F(AudioRendererHostTest, CreateDeviceWithAuthorizationPendingIsError) { |
| 435 ExpectShutdown(); | |
| 436 CreateWithoutWaitingForAuth(kBadDeviceId); | 590 CreateWithoutWaitingForAuth(kBadDeviceId); |
| 437 Close(); | 591 Close(); |
| 592 AssertBadMsgReported(); | |
| 438 } | 593 } |
| 439 | 594 |
| 440 TEST_F(AudioRendererHostTest, CreateDeviceWithBadSecurityOrigin) { | 595 TEST_F(AudioRendererHostTest, CreateDeviceWithBadSecurityOrigin) { |
| 441 ExpectShutdown(); | |
| 442 RequestDeviceAuthorizationWithBadOrigin(kNondefaultDeviceId); | 596 RequestDeviceAuthorizationWithBadOrigin(kNondefaultDeviceId); |
| 443 Close(); | 597 Close(); |
| 598 AssertBadMsgReported(); | |
| 444 } | 599 } |
| 445 | 600 |
| 446 TEST_F(AudioRendererHostTest, CreateInvalidDevice) { | 601 TEST_F(AudioRendererHostTest, CreateInvalidDevice) { |
| 447 Create(false, kInvalidDeviceId, url::Origin(GURL(kSecurityOrigin)), true); | 602 Create(kInvalidDeviceId, url::Origin(GURL(kSecurityOrigin)), true, false); |
| 448 Close(); | 603 Close(); |
| 604 AssertBadMsgReported(); | |
| 449 } | 605 } |
| 450 | 606 |
| 451 TEST_F(AudioRendererHostTest, CreateFailsForInvalidRenderFrame) { | 607 TEST_F(AudioRendererHostTest, CreateFailsForInvalidRenderFrame) { |
| 452 CreateWithInvalidRenderFrameId(); | 608 CreateWithInvalidRenderFrameId(); |
| 453 Close(); | 609 Close(); |
| 454 } | 610 } |
| 455 | 611 |
| 456 // TODO(hclam): Add tests for data conversation in low latency mode. | 612 // TODO(hclam): Add tests for data conversation in low latency mode. |
| 457 | 613 |
| 458 } // namespace content | 614 } // namespace content |
| OLD | NEW |