| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 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 "content/browser/renderer_host/media/audio_input_renderer_host.h" |
| 6 |
| 7 #include <vector> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/command_line.h" |
| 11 #include "base/run_loop.h" |
| 12 #include "content/browser/bad_message.h" |
| 13 #include "content/browser/media/capture/audio_mirroring_manager.h" |
| 14 #include "content/browser/renderer_host/media/audio_input_device_manager.h" |
| 15 #include "content/browser/renderer_host/media/media_stream_manager.h" |
| 16 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" |
| 17 #include "content/public/browser/browser_thread.h" |
| 18 #include "content/public/common/content_switches.h" |
| 19 #include "content/public/test/mock_render_process_host.h" |
| 20 #include "content/public/test/test_browser_context.h" |
| 21 #include "content/public/test/test_browser_thread.h" |
| 22 #include "content/public/test/test_browser_thread_bundle.h" |
| 23 #include "media/audio/audio_device_description.h" |
| 24 #include "media/audio/audio_input_writer.h" |
| 25 #include "media/audio/fake_audio_log_factory.h" |
| 26 #include "media/audio/fake_audio_manager.h" |
| 27 #include "media/base/media_switches.h" |
| 28 #include "testing/gmock/include/gmock/gmock.h" |
| 29 #include "testing/gtest/include/gtest/gtest.h" |
| 30 #include "url/gurl.h" |
| 31 #include "url/origin.h" |
| 32 |
| 33 using ::media::AudioInputController; |
| 34 using ::testing::_; |
| 35 using ::testing::Assign; |
| 36 using ::testing::InSequence; |
| 37 using ::testing::Invoke; |
| 38 using ::testing::Mock; |
| 39 using ::testing::NotNull; |
| 40 using ::testing::SaveArg; |
| 41 using ::testing::StrictMock; |
| 42 |
| 43 namespace content { |
| 44 |
| 45 namespace { |
| 46 |
| 47 const int kStreamId = 100; |
| 48 const int kRenderProcessId = 42; |
| 49 const int kRendererPid = 21718; |
| 50 const int kRenderFrameId = 31415; |
| 51 const int kSharedMemoryCount = 11; |
| 52 const char kSecurityOrigin[] = "http://localhost"; |
| 53 #if defined(OS_WIN) |
| 54 const wchar_t kBaseFileName[] = L"some_file_name"; |
| 55 #else |
| 56 const char kBaseFileName[] = "some_file_name"; |
| 57 #endif |
| 58 |
| 59 url::Origin SecurityOrigin() { |
| 60 return url::Origin(GURL(kSecurityOrigin)); |
| 61 } |
| 62 |
| 63 AudioInputHostMsg_CreateStream_Config DefaultConfig() { |
| 64 AudioInputHostMsg_CreateStream_Config config; |
| 65 config.params = media::AudioParameters::UnavailableDeviceParams(); |
| 66 config.automatic_gain_control = false; |
| 67 config.shared_memory_count = kSharedMemoryCount; |
| 68 return config; |
| 69 } |
| 70 |
| 71 class MockRenderer { |
| 72 public: |
| 73 MOCK_METHOD5(NotifyStreamCreated, |
| 74 void(int /*stream_id*/, |
| 75 base::SharedMemoryHandle /*handle*/, |
| 76 base::SyncSocket::TransitDescriptor /*socket_desriptor*/, |
| 77 uint32_t /*length*/, |
| 78 uint32_t /*total_segments*/)); |
| 79 MOCK_METHOD2(NotifyStreamVolume, void(int /*stream_id*/, double /*volume*/)); |
| 80 MOCK_METHOD2(NotifyStreamStateChanged, |
| 81 void(int /*stream_id*/, |
| 82 media::AudioInputIPCDelegateState /*state*/)); |
| 83 MOCK_METHOD0(WasShutDown, void()); |
| 84 }; |
| 85 |
| 86 // This class overrides Send to intercept the messages that the |
| 87 // AudioInputRendererHost sends to the renderer. They are sent to |
| 88 // the provided MockRenderer instead. |
| 89 class AudioInputRendererHostWithInterception : public AudioInputRendererHost { |
| 90 public: |
| 91 AudioInputRendererHostWithInterception( |
| 92 int render_process_id, |
| 93 int32_t renderer_pid, |
| 94 media::AudioManager* audio_manager, |
| 95 MediaStreamManager* media_stream_manager, |
| 96 AudioMirroringManager* audio_mirroring_manager, |
| 97 media::UserInputMonitor* user_input_monitor, |
| 98 MockRenderer* renderer) |
| 99 : AudioInputRendererHost(render_process_id, |
| 100 renderer_pid, |
| 101 audio_manager, |
| 102 media_stream_manager, |
| 103 audio_mirroring_manager, |
| 104 user_input_monitor), |
| 105 renderer_(renderer) { |
| 106 set_peer_process_for_testing(base::Process::Current()); |
| 107 } |
| 108 |
| 109 protected: |
| 110 ~AudioInputRendererHostWithInterception() override = default; |
| 111 |
| 112 private: |
| 113 bool Send(IPC::Message* message) override { |
| 114 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 115 bool handled = true; |
| 116 |
| 117 IPC_BEGIN_MESSAGE_MAP(AudioInputRendererHostWithInterception, *message) |
| 118 IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamCreated, |
| 119 NotifyRendererStreamCreated) |
| 120 IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamVolume, |
| 121 NotifyRendererStreamVolume) |
| 122 IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamStateChanged, |
| 123 NotifyRendererStreamStateChanged) |
| 124 IPC_MESSAGE_UNHANDLED(handled = false) |
| 125 IPC_END_MESSAGE_MAP() |
| 126 |
| 127 EXPECT_TRUE(handled); |
| 128 delete message; |
| 129 return true; |
| 130 } |
| 131 |
| 132 void ShutdownForBadMessage() override { renderer_->WasShutDown(); } |
| 133 |
| 134 void NotifyRendererStreamCreated( |
| 135 int stream_id, |
| 136 base::SharedMemoryHandle handle, |
| 137 base::SyncSocket::TransitDescriptor socket_descriptor, |
| 138 uint32_t length, |
| 139 uint32_t total_segments) { |
| 140 // It's difficult to check that the sync socket and shared memory is |
| 141 // valid in the gmock macros, so we check them here. |
| 142 EXPECT_NE(base::SyncSocket::UnwrapHandle(socket_descriptor), |
| 143 base::SyncSocket::kInvalidHandle); |
| 144 base::SharedMemory memory(handle, /*read_only*/ true); |
| 145 EXPECT_TRUE(memory.Map(length)); |
| 146 renderer_->NotifyStreamCreated(stream_id, handle, socket_descriptor, length, |
| 147 total_segments); |
| 148 EXPECT_TRUE(memory.Unmap()); |
| 149 memory.Close(); |
| 150 } |
| 151 |
| 152 void NotifyRendererStreamVolume(int stream_id, double volume) { |
| 153 renderer_->NotifyStreamVolume(stream_id, volume); |
| 154 } |
| 155 |
| 156 void NotifyRendererStreamStateChanged( |
| 157 int stream_id, |
| 158 media::AudioInputIPCDelegateState state) { |
| 159 renderer_->NotifyStreamStateChanged(stream_id, state); |
| 160 } |
| 161 |
| 162 MockRenderer* renderer_; |
| 163 }; |
| 164 |
| 165 class MockAudioInputController : public AudioInputController { |
| 166 public: |
| 167 MockAudioInputController( |
| 168 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| 169 AudioInputController::SyncWriter* writer, |
| 170 media::AudioManager* audio_manager, |
| 171 AudioInputController::EventHandler* event_handler, |
| 172 media::UserInputMonitor* user_input_monitor) |
| 173 : AudioInputController(event_handler, |
| 174 writer, |
| 175 /*debug_writer*/ nullptr, |
| 176 user_input_monitor, |
| 177 /*agc*/ false) { |
| 178 task_runner_ = std::move(task_runner); |
| 179 task_runner_->PostTask( |
| 180 FROM_HERE, |
| 181 base::Bind(&AudioInputController::EventHandler::OnCreated, |
| 182 base::Unretained(event_handler), base::Unretained(this))); |
| 183 ON_CALL(*this, Close(_)) |
| 184 .WillByDefault(Invoke(this, &MockAudioInputController::ExecuteClose)); |
| 185 ON_CALL(*this, EnableDebugRecording(_)) |
| 186 .WillByDefault(SaveArg<0>(&file_name)); |
| 187 } |
| 188 |
| 189 EventHandler* handler() { return handler_; } |
| 190 |
| 191 // File name that we pretend to do a debug recording to, if any. |
| 192 base::FilePath debug_file_name() { return file_name; } |
| 193 |
| 194 MOCK_METHOD0(Record, void()); |
| 195 MOCK_METHOD1(Close, void(const base::Closure&)); |
| 196 MOCK_METHOD1(SetVolume, void(double)); |
| 197 MOCK_METHOD1(EnableDebugRecording, void(const base::FilePath&)); |
| 198 MOCK_METHOD0(DisableDebugRecording, void()); |
| 199 |
| 200 // AudioInputCallback impl, irrelevant to us. |
| 201 MOCK_METHOD4( |
| 202 OnData, |
| 203 void(media::AudioInputStream*, const media::AudioBus*, uint32_t, double)); |
| 204 MOCK_METHOD1(OnError, void(media::AudioInputStream*)); |
| 205 |
| 206 protected: |
| 207 ~MockAudioInputController() override = default; |
| 208 |
| 209 private: |
| 210 void ExecuteClose(const base::Closure& task) { |
| 211 // Hop to audio manager thread before calling task, since this is the real |
| 212 // behavior. |
| 213 task_runner_->PostTaskAndReply(FROM_HERE, base::Bind([]() {}), task); |
| 214 } |
| 215 |
| 216 base::FilePath file_name; |
| 217 }; |
| 218 |
| 219 class MockControllerFactory : public AudioInputController::Factory { |
| 220 public: |
| 221 using MockController = StrictMock<MockAudioInputController>; |
| 222 |
| 223 MockControllerFactory() { |
| 224 AudioInputController::set_factory_for_testing(this); |
| 225 } |
| 226 |
| 227 ~MockControllerFactory() override { |
| 228 AudioInputController::set_factory_for_testing(nullptr); |
| 229 } |
| 230 |
| 231 // AudioInputController::Factory implementaion: |
| 232 AudioInputController* Create( |
| 233 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| 234 AudioInputController::SyncWriter* sync_writer, |
| 235 media::AudioManager* audio_manager, |
| 236 AudioInputController::EventHandler* event_handler, |
| 237 media::AudioParameters params, |
| 238 media::UserInputMonitor* user_input_monitor) override { |
| 239 ControllerCreated(); |
| 240 scoped_refptr<MockController> controller = |
| 241 new MockController(std::move(task_runner), sync_writer, audio_manager, |
| 242 event_handler, user_input_monitor); |
| 243 controller_list_.push_back(controller); |
| 244 return controller.get(); |
| 245 } |
| 246 |
| 247 MockController* controller(size_t i) { |
| 248 EXPECT_GT(controller_list_.size(), i); |
| 249 return controller_list_[i].get(); |
| 250 } |
| 251 |
| 252 MOCK_METHOD0(ControllerCreated, void()); |
| 253 |
| 254 private: |
| 255 std::vector<scoped_refptr<MockController>> controller_list_; |
| 256 }; |
| 257 |
| 258 } // namespace |
| 259 |
| 260 class AudioInputRendererHostTest : public testing::Test { |
| 261 public: |
| 262 AudioInputRendererHostTest() { |
| 263 base::CommandLine* flags = base::CommandLine::ForCurrentProcess(); |
| 264 flags->AppendSwitch(switches::kUseFakeDeviceForMediaStream); |
| 265 flags->AppendSwitch(switches::kUseFakeUIForMediaStream); |
| 266 |
| 267 audio_manager_.reset(new media::FakeAudioManager( |
| 268 base::ThreadTaskRunnerHandle::Get(), |
| 269 base::ThreadTaskRunnerHandle::Get(), &log_factory_)); |
| 270 media_stream_manager_ = |
| 271 base::MakeUnique<MediaStreamManager>(audio_manager_.get()); |
| 272 airh_ = new AudioInputRendererHostWithInterception( |
| 273 kRenderProcessId, kRendererPid, media::AudioManager::Get(), |
| 274 media_stream_manager_.get(), AudioMirroringManager::GetInstance(), |
| 275 nullptr, &renderer_); |
| 276 } |
| 277 |
| 278 ~AudioInputRendererHostTest() override { |
| 279 airh_->OnChannelClosing(); |
| 280 base::RunLoop().RunUntilIdle(); |
| 281 } |
| 282 |
| 283 protected: |
| 284 // Makes device |device_id| with name |name| available to open with the |
| 285 // session id returned. |
| 286 int Open(const std::string& device_id, const std::string& name) { |
| 287 int session_id = media_stream_manager_->audio_input_device_manager()->Open( |
| 288 StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE, name, device_id)); |
| 289 base::RunLoop().RunUntilIdle(); |
| 290 return session_id; |
| 291 } |
| 292 |
| 293 std::string GetRawNondefaultId() { |
| 294 std::string id; |
| 295 MediaDevicesManager::BoolDeviceTypes devices_to_enumerate; |
| 296 devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_INPUT] = true; |
| 297 |
| 298 media_stream_manager_->media_devices_manager()->EnumerateDevices( |
| 299 devices_to_enumerate, |
| 300 base::Bind( |
| 301 [](std::string* id, const MediaDeviceEnumeration& result) { |
| 302 // Index 0 is default, so use 1. |
| 303 CHECK(result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_INPUT] |
| 304 .size() > 1) |
| 305 << "Expected to have a nondefault device."; |
| 306 *id = result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_INPUT][1] |
| 307 .device_id; |
| 308 }, |
| 309 base::Unretained(&id))); |
| 310 base::RunLoop().RunUntilIdle(); |
| 311 return id; |
| 312 } |
| 313 |
| 314 media::FakeAudioLogFactory log_factory_; |
| 315 StrictMock<MockControllerFactory> controller_factory_; |
| 316 std::unique_ptr<MediaStreamManager> media_stream_manager_; |
| 317 TestBrowserThreadBundle thread_bundle_; |
| 318 media::ScopedAudioManagerPtr audio_manager_; |
| 319 StrictMock<MockRenderer> renderer_; |
| 320 scoped_refptr<AudioInputRendererHost> airh_; |
| 321 |
| 322 private: |
| 323 DISALLOW_COPY_AND_ASSIGN(AudioInputRendererHostTest); |
| 324 }; |
| 325 |
| 326 // Checks that a controller is created and a reply is sent when creating a |
| 327 // stream. |
| 328 TEST_F(AudioInputRendererHostTest, CreateWithDefaultDevice) { |
| 329 int session_id = |
| 330 Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId); |
| 331 |
| 332 EXPECT_CALL(renderer_, |
| 333 NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount)); |
| 334 EXPECT_CALL(controller_factory_, ControllerCreated()); |
| 335 |
| 336 airh_->OnMessageReceived(AudioInputHostMsg_CreateStream( |
| 337 kStreamId, kRenderFrameId, session_id, DefaultConfig())); |
| 338 |
| 339 base::RunLoop().RunUntilIdle(); |
| 340 EXPECT_CALL(*controller_factory_.controller(0), Close(_)); |
| 341 } |
| 342 |
| 343 // If authorization hasn't been granted, only reply with and error and do |
| 344 // nothing else. |
| 345 TEST_F(AudioInputRendererHostTest, CreateWithoutAuthorization_Error) { |
| 346 EXPECT_CALL(renderer_, |
| 347 NotifyStreamStateChanged( |
| 348 kStreamId, media::AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR)); |
| 349 |
| 350 int session_id = 0; |
| 351 airh_->OnMessageReceived(AudioInputHostMsg_CreateStream( |
| 352 kStreamId, kRenderFrameId, session_id, DefaultConfig())); |
| 353 base::RunLoop().RunUntilIdle(); |
| 354 } |
| 355 |
| 356 // Like CreateWithDefaultDevice but with a nondefault device. |
| 357 TEST_F(AudioInputRendererHostTest, CreateWithNonDefaultDevice) { |
| 358 int session_id = Open("Nondefault device", GetRawNondefaultId()); |
| 359 |
| 360 EXPECT_CALL(renderer_, |
| 361 NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount)); |
| 362 EXPECT_CALL(controller_factory_, ControllerCreated()); |
| 363 |
| 364 airh_->OnMessageReceived(AudioInputHostMsg_CreateStream( |
| 365 kStreamId, kRenderFrameId, session_id, DefaultConfig())); |
| 366 |
| 367 base::RunLoop().RunUntilIdle(); |
| 368 EXPECT_CALL(*controller_factory_.controller(0), Close(_)); |
| 369 } |
| 370 |
| 371 // Checks that stream is started when calling record. |
| 372 TEST_F(AudioInputRendererHostTest, CreateRecordClose) { |
| 373 int session_id = |
| 374 Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId); |
| 375 |
| 376 EXPECT_CALL(renderer_, |
| 377 NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount)); |
| 378 EXPECT_CALL(controller_factory_, ControllerCreated()); |
| 379 |
| 380 airh_->OnMessageReceived(AudioInputHostMsg_CreateStream( |
| 381 kStreamId, kRenderFrameId, session_id, DefaultConfig())); |
| 382 base::RunLoop().RunUntilIdle(); |
| 383 |
| 384 EXPECT_CALL(*controller_factory_.controller(0), Record()); |
| 385 EXPECT_CALL(*controller_factory_.controller(0), Close(_)); |
| 386 |
| 387 airh_->OnMessageReceived(AudioInputHostMsg_RecordStream(kStreamId)); |
| 388 base::RunLoop().RunUntilIdle(); |
| 389 airh_->OnMessageReceived(AudioInputHostMsg_CloseStream(kStreamId)); |
| 390 base::RunLoop().RunUntilIdle(); |
| 391 } |
| 392 |
| 393 // In addition to the above, also check that a SetVolume message is propagated |
| 394 // to the controller. |
| 395 TEST_F(AudioInputRendererHostTest, CreateSetVolumeRecordClose) { |
| 396 int session_id = |
| 397 Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId); |
| 398 |
| 399 EXPECT_CALL(renderer_, |
| 400 NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount)); |
| 401 EXPECT_CALL(controller_factory_, ControllerCreated()); |
| 402 |
| 403 airh_->OnMessageReceived(AudioInputHostMsg_CreateStream( |
| 404 kStreamId, kRenderFrameId, session_id, DefaultConfig())); |
| 405 base::RunLoop().RunUntilIdle(); |
| 406 |
| 407 EXPECT_CALL(*controller_factory_.controller(0), SetVolume(0.5)); |
| 408 EXPECT_CALL(*controller_factory_.controller(0), Record()); |
| 409 EXPECT_CALL(*controller_factory_.controller(0), Close(_)); |
| 410 |
| 411 airh_->OnMessageReceived(AudioInputHostMsg_SetVolume(kStreamId, 0.5)); |
| 412 airh_->OnMessageReceived(AudioInputHostMsg_RecordStream(kStreamId)); |
| 413 airh_->OnMessageReceived(AudioInputHostMsg_CloseStream(kStreamId)); |
| 414 |
| 415 base::RunLoop().RunUntilIdle(); |
| 416 } |
| 417 |
| 418 // Check that a too large volume is treated like a bad message and doesn't |
| 419 // reach the controller. |
| 420 TEST_F(AudioInputRendererHostTest, SetVolumeTooLarge_BadMessage) { |
| 421 int session_id = |
| 422 Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId); |
| 423 |
| 424 EXPECT_CALL(renderer_, |
| 425 NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount)); |
| 426 EXPECT_CALL(controller_factory_, ControllerCreated()); |
| 427 |
| 428 airh_->OnMessageReceived(AudioInputHostMsg_CreateStream( |
| 429 kStreamId, kRenderFrameId, session_id, DefaultConfig())); |
| 430 base::RunLoop().RunUntilIdle(); |
| 431 |
| 432 EXPECT_CALL(*controller_factory_.controller(0), Close(_)); |
| 433 EXPECT_CALL(renderer_, WasShutDown()); |
| 434 |
| 435 airh_->OnMessageReceived(AudioInputHostMsg_SetVolume(kStreamId, 5)); |
| 436 |
| 437 base::RunLoop().RunUntilIdle(); |
| 438 } |
| 439 |
| 440 // Like above. |
| 441 TEST_F(AudioInputRendererHostTest, SetVolumeNegative_BadMessage) { |
| 442 int session_id = |
| 443 Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId); |
| 444 |
| 445 EXPECT_CALL(renderer_, |
| 446 NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount)); |
| 447 EXPECT_CALL(controller_factory_, ControllerCreated()); |
| 448 |
| 449 airh_->OnMessageReceived(AudioInputHostMsg_CreateStream( |
| 450 kStreamId, kRenderFrameId, session_id, DefaultConfig())); |
| 451 base::RunLoop().RunUntilIdle(); |
| 452 |
| 453 EXPECT_CALL(*controller_factory_.controller(0), Close(_)); |
| 454 EXPECT_CALL(renderer_, WasShutDown()); |
| 455 |
| 456 airh_->OnMessageReceived(AudioInputHostMsg_SetVolume(kStreamId, -0.5)); |
| 457 |
| 458 base::RunLoop().RunUntilIdle(); |
| 459 } |
| 460 |
| 461 // Checks that a stream_id cannot be reused. |
| 462 TEST_F(AudioInputRendererHostTest, CreateTwice_Error) { |
| 463 int session_id = |
| 464 Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId); |
| 465 |
| 466 EXPECT_CALL(renderer_, |
| 467 NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount)); |
| 468 EXPECT_CALL(renderer_, |
| 469 NotifyStreamStateChanged( |
| 470 kStreamId, media::AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR)); |
| 471 EXPECT_CALL(controller_factory_, ControllerCreated()); |
| 472 |
| 473 airh_->OnMessageReceived(AudioInputHostMsg_CreateStream( |
| 474 kStreamId, kRenderFrameId, session_id, DefaultConfig())); |
| 475 airh_->OnMessageReceived(AudioInputHostMsg_CreateStream( |
| 476 kStreamId, kRenderFrameId, session_id, DefaultConfig())); |
| 477 base::RunLoop().RunUntilIdle(); |
| 478 |
| 479 EXPECT_CALL(*controller_factory_.controller(0), Close(_)); |
| 480 } |
| 481 |
| 482 // Checks that when two streams are created, messages are routed to the correct |
| 483 // stream. Also checks that when enabling debug recording, the streams get |
| 484 // different file names. |
| 485 TEST_F(AudioInputRendererHostTest, TwoStreams) { |
| 486 int session_id = |
| 487 Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId); |
| 488 |
| 489 EXPECT_CALL(renderer_, |
| 490 NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount)); |
| 491 EXPECT_CALL(renderer_, |
| 492 NotifyStreamCreated(kStreamId + 1, _, _, _, kSharedMemoryCount)); |
| 493 EXPECT_CALL(controller_factory_, ControllerCreated()).Times(2); |
| 494 |
| 495 airh_->OnMessageReceived(AudioInputHostMsg_CreateStream( |
| 496 kStreamId, kRenderFrameId, session_id, DefaultConfig())); |
| 497 airh_->OnMessageReceived(AudioInputHostMsg_CreateStream( |
| 498 kStreamId + 1, kRenderFrameId, session_id, DefaultConfig())); |
| 499 base::RunLoop().RunUntilIdle(); |
| 500 |
| 501 #if BUILDFLAG(ENABLE_WEBRTC) |
| 502 EXPECT_CALL(*controller_factory_.controller(0), EnableDebugRecording(_)); |
| 503 EXPECT_CALL(*controller_factory_.controller(1), EnableDebugRecording(_)); |
| 504 |
| 505 airh_->EnableDebugRecording(base::FilePath(kBaseFileName)); |
| 506 base::RunLoop().RunUntilIdle(); |
| 507 |
| 508 EXPECT_NE(controller_factory_.controller(0)->debug_file_name(), |
| 509 controller_factory_.controller(1)->debug_file_name()); |
| 510 EXPECT_CALL(*controller_factory_.controller(0), DisableDebugRecording()); |
| 511 EXPECT_CALL(*controller_factory_.controller(1), DisableDebugRecording()); |
| 512 |
| 513 airh_->DisableDebugRecording(); |
| 514 #endif // ENABLE_WEBRTC |
| 515 |
| 516 EXPECT_CALL(*controller_factory_.controller(0), Close(_)); |
| 517 EXPECT_CALL(*controller_factory_.controller(1), Close(_)); |
| 518 } |
| 519 |
| 520 // Checks that the stream is properly cleaned up and a notification is sent to |
| 521 // the renderer when the stream encounters an error. |
| 522 TEST_F(AudioInputRendererHostTest, Error_ClosesController) { |
| 523 int session_id = |
| 524 Open("Default device", media::AudioDeviceDescription::kDefaultDeviceId); |
| 525 |
| 526 EXPECT_CALL(renderer_, |
| 527 NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount)); |
| 528 EXPECT_CALL(controller_factory_, ControllerCreated()); |
| 529 |
| 530 airh_->OnMessageReceived(AudioInputHostMsg_CreateStream( |
| 531 kStreamId, kRenderFrameId, session_id, DefaultConfig())); |
| 532 |
| 533 base::RunLoop().RunUntilIdle(); |
| 534 EXPECT_CALL(*controller_factory_.controller(0), Close(_)); |
| 535 EXPECT_CALL(renderer_, |
| 536 NotifyStreamStateChanged( |
| 537 kStreamId, media::AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR)); |
| 538 |
| 539 controller_factory_.controller(0)->handler()->OnError( |
| 540 controller_factory_.controller(0), AudioInputController::UNKNOWN_ERROR); |
| 541 |
| 542 // Check Close expectation before the destructor. |
| 543 base::RunLoop().RunUntilIdle(); |
| 544 Mock::VerifyAndClear(controller_factory_.controller(0)); |
| 545 } |
| 546 |
| 547 // Checks that tab capture streams can be created. |
| 548 TEST_F(AudioInputRendererHostTest, TabCaptureStream) { |
| 549 StreamControls controls(/* request_audio */ true, /* request_video */ false); |
| 550 controls.audio.device_id = base::StringPrintf( |
| 551 "web-contents-media-stream://%d:%d", kRenderProcessId, kRenderFrameId); |
| 552 controls.audio.stream_source = kMediaStreamSourceTab; |
| 553 std::string request_label = media_stream_manager_->MakeMediaAccessRequest( |
| 554 kRenderProcessId, kRenderFrameId, 0, controls, SecurityOrigin(), |
| 555 base::Bind([](const MediaStreamDevices& devices, |
| 556 std::unique_ptr<MediaStreamUIProxy>) {})); |
| 557 base::RunLoop().RunUntilIdle(); |
| 558 int session_id = Open("Tab capture", controls.audio.device_id); |
| 559 |
| 560 EXPECT_CALL(renderer_, |
| 561 NotifyStreamCreated(kStreamId, _, _, _, kSharedMemoryCount)); |
| 562 EXPECT_CALL(controller_factory_, ControllerCreated()); |
| 563 |
| 564 airh_->OnMessageReceived(AudioInputHostMsg_CreateStream( |
| 565 kStreamId, kRenderFrameId, session_id, DefaultConfig())); |
| 566 base::RunLoop().RunUntilIdle(); |
| 567 |
| 568 EXPECT_CALL(*controller_factory_.controller(0), Close(_)); |
| 569 } |
| 570 |
| 571 } // namespace content |
| OLD | NEW |