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/audio_output_impl.h" | |
16 #include "content/browser/media/capture/audio_mirroring_manager.h" | 17 #include "content/browser/media/capture/audio_mirroring_manager.h" |
17 #include "content/browser/media/media_internals.h" | 18 #include "content/browser/media/media_internals.h" |
18 #include "content/browser/renderer_host/media/audio_input_device_manager.h" | 19 #include "content/browser/renderer_host/media/audio_input_device_manager.h" |
19 #include "content/browser/renderer_host/media/media_stream_manager.h" | 20 #include "content/browser/renderer_host/media/media_stream_manager.h" |
20 #include "content/common/media/audio_messages.h" | 21 #include "content/common/media/audio_messages.h" |
21 #include "content/public/common/content_switches.h" | 22 #include "content/public/common/content_switches.h" |
22 #include "content/public/test/test_browser_thread_bundle.h" | 23 #include "content/public/test/test_browser_thread_bundle.h" |
23 #include "ipc/ipc_message_utils.h" | 24 #include "ipc/ipc_message_utils.h" |
24 #include "media/audio/audio_manager.h" | 25 #include "media/audio/audio_manager.h" |
25 #include "media/base/bind_to_current_loop.h" | 26 #include "media/base/bind_to_current_loop.h" |
26 #include "media/base/media_switches.h" | 27 #include "media/base/media_switches.h" |
28 #include "media/mojo/common/media_type_converters.h" | |
29 #include "mojo/edk/embedder/embedder.h" | |
27 #include "testing/gmock/include/gmock/gmock.h" | 30 #include "testing/gmock/include/gmock/gmock.h" |
28 #include "testing/gtest/include/gtest/gtest.h" | 31 #include "testing/gtest/include/gtest/gtest.h" |
29 | 32 |
30 using ::testing::_; | 33 using ::testing::_; |
31 using ::testing::Assign; | 34 using ::testing::Assign; |
32 using ::testing::DoAll; | 35 using ::testing::DoAll; |
33 using ::testing::NotNull; | 36 using ::testing::NotNull; |
34 | 37 |
35 namespace { | 38 namespace { |
36 const int kRenderProcessId = 1; | 39 const int kRenderProcessId = 1; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
68 MediaStreamManager* media_stream_manager, | 71 MediaStreamManager* media_stream_manager, |
69 const ResourceContext::SaltCallback& salt_callback) | 72 const ResourceContext::SaltCallback& salt_callback) |
70 : AudioRendererHost(kRenderProcessId, | 73 : AudioRendererHost(kRenderProcessId, |
71 audio_manager, | 74 audio_manager, |
72 mirroring_manager, | 75 mirroring_manager, |
73 media_internals, | 76 media_internals, |
74 media_stream_manager, | 77 media_stream_manager, |
75 salt_callback), | 78 salt_callback), |
76 shared_memory_length_(0) {} | 79 shared_memory_length_(0) {} |
77 | 80 |
81 AudioOutputImpl* Init(scoped_refptr<MockAudioRendererHost> host) { | |
82 media::interfaces::AudioOutputPtr* stream = | |
83 new media::interfaces::AudioOutputPtr(); | |
84 audio_output_impl_ = (new AudioOutputImpl(0, mojo::GetProxy(stream))); | |
85 return audio_output_impl_; | |
86 } | |
87 | |
78 // A list of mock methods. | 88 // A list of mock methods. |
79 MOCK_METHOD4(OnDeviceAuthorized, | 89 MOCK_METHOD4(OnDeviceAuthorized, |
80 void(int stream_id, | 90 void(int stream_id, |
81 media::OutputDeviceStatus device_status, | 91 media::OutputDeviceStatus device_status, |
82 const media::AudioParameters& output_params, | 92 const media::AudioParameters& output_params, |
83 const std::string& matched_device_id)); | 93 const std::string& matched_device_id)); |
84 MOCK_METHOD2(OnStreamCreated, void(int stream_id, int length)); | 94 MOCK_METHOD2(OnStreamCreated, void(int stream_id, int length)); |
85 MOCK_METHOD1(OnStreamPlaying, void(int stream_id)); | 95 MOCK_METHOD1(OnStreamPlaying, void(int stream_id)); |
86 MOCK_METHOD1(OnStreamPaused, void(int stream_id)); | 96 MOCK_METHOD1(OnStreamPaused, void(int stream_id)); |
87 MOCK_METHOD1(OnStreamError, void(int stream_id)); | 97 MOCK_METHOD1(OnStreamError, void(int stream_id)); |
88 | 98 |
99 void OnNotifyStreamCreated( | |
Henrik Grunell
2016/05/02 12:12:23
As we talked about offline, this function should e
rchtara
2016/05/23 16:38:17
Done.
| |
100 int stream_id, | |
101 base::SharedMemoryHandle handle, | |
102 base::SyncSocket::TransitDescriptor socket_descriptor, | |
103 uint32_t length) { | |
104 // Maps the shared memory. | |
105 shared_memory_.reset(new base::SharedMemory(handle, false)); | |
Henrik Grunell
2016/05/02 12:12:23
As we talked about offline, storing in member vari
rchtara
2016/05/23 16:38:17
Done.
| |
106 CHECK(shared_memory_->Map(length)); | |
107 CHECK(shared_memory_->memory()); | |
108 shared_memory_length_ = length; | |
109 | |
110 // Create the SyncSocket using the handle. | |
111 base::SyncSocket::Handle sync_socket_handle = | |
112 base::SyncSocket::UnwrapHandle(socket_descriptor); | |
113 sync_socket_.reset(new base::SyncSocket(sync_socket_handle)); | |
114 | |
115 // And then delegate the call to the mock method. | |
116 OnStreamCreated(stream_id, length); | |
117 } | |
118 | |
89 private: | 119 private: |
90 virtual ~MockAudioRendererHost() { | 120 virtual ~MockAudioRendererHost() { |
91 // Make sure all audio streams have been deleted. | 121 // Make sure all audio streams have been deleted. |
92 EXPECT_TRUE(audio_entries_.empty()); | 122 EXPECT_TRUE(audio_entries_.empty()); |
93 } | 123 } |
94 | 124 |
95 // This method is used to dispatch IPC messages to the renderer. We intercept | 125 // This method is used to dispatch IPC messages to the renderer. We intercept |
96 // these messages here and dispatch to our mock methods to verify the | 126 // these messages here and dispatch to our mock methods to verify the |
97 // conversation between this object and the renderer. | 127 // conversation between this object and the renderer. |
98 virtual bool Send(IPC::Message* message) { | 128 virtual bool Send(IPC::Message* message) { |
99 CHECK(message); | 129 CHECK(message); |
100 | 130 |
101 // In this method we dispatch the messages to the according handlers as if | 131 // In this method we dispatch the messages to the according handlers as if |
102 // we are the renderer. | 132 // we are the renderer. |
103 bool handled = true; | 133 bool handled = true; |
104 IPC_BEGIN_MESSAGE_MAP(MockAudioRendererHost, *message) | 134 IPC_BEGIN_MESSAGE_MAP(MockAudioRendererHost, *message) |
105 IPC_MESSAGE_HANDLER(AudioMsg_NotifyDeviceAuthorized, | 135 IPC_MESSAGE_HANDLER(AudioMsg_NotifyDeviceAuthorized, |
106 OnNotifyDeviceAuthorized) | 136 OnNotifyDeviceAuthorized) |
107 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamCreated, | |
108 OnNotifyStreamCreated) | |
109 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamStateChanged, | 137 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamStateChanged, |
110 OnNotifyStreamStateChanged) | 138 OnNotifyStreamStateChanged) |
111 IPC_MESSAGE_UNHANDLED(handled = false) | 139 IPC_MESSAGE_UNHANDLED(handled = false) |
112 IPC_END_MESSAGE_MAP() | 140 IPC_END_MESSAGE_MAP() |
113 EXPECT_TRUE(handled); | 141 EXPECT_TRUE(handled); |
114 | 142 |
115 delete message; | 143 delete message; |
116 return true; | 144 return true; |
117 } | 145 } |
118 | 146 |
119 void OnNotifyDeviceAuthorized(int stream_id, | 147 void OnNotifyDeviceAuthorized(int stream_id, |
120 media::OutputDeviceStatus device_status, | 148 media::OutputDeviceStatus device_status, |
121 const media::AudioParameters& output_params, | 149 const media::AudioParameters& output_params, |
122 const std::string& matched_device_id) { | 150 const std::string& matched_device_id) { |
123 OnDeviceAuthorized(stream_id, device_status, output_params, | 151 OnDeviceAuthorized(stream_id, device_status, output_params, |
124 matched_device_id); | 152 matched_device_id); |
125 } | 153 } |
126 | 154 |
127 void OnNotifyStreamCreated( | |
128 int stream_id, | |
129 base::SharedMemoryHandle handle, | |
130 base::SyncSocket::TransitDescriptor socket_descriptor, | |
131 uint32_t length) { | |
132 // Maps the shared memory. | |
133 shared_memory_.reset(new base::SharedMemory(handle, false)); | |
134 CHECK(shared_memory_->Map(length)); | |
135 CHECK(shared_memory_->memory()); | |
136 shared_memory_length_ = length; | |
137 | |
138 // Create the SyncSocket using the handle. | |
139 base::SyncSocket::Handle sync_socket_handle = | |
140 base::SyncSocket::UnwrapHandle(socket_descriptor); | |
141 sync_socket_.reset(new base::SyncSocket(sync_socket_handle)); | |
142 | |
143 // And then delegate the call to the mock method. | |
144 OnStreamCreated(stream_id, length); | |
145 } | |
146 | |
147 void OnNotifyStreamStateChanged(int stream_id, | 155 void OnNotifyStreamStateChanged(int stream_id, |
148 media::AudioOutputIPCDelegateState state) { | 156 media::AudioOutputIPCDelegateState state) { |
149 switch (state) { | 157 switch (state) { |
150 case media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING: | 158 case media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING: |
151 OnStreamPlaying(stream_id); | 159 OnStreamPlaying(stream_id); |
152 break; | 160 break; |
153 case media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED: | 161 case media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED: |
154 OnStreamPaused(stream_id); | 162 OnStreamPaused(stream_id); |
155 break; | 163 break; |
156 case media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: | 164 case media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
199 base::RunLoop run_loop; | 207 base::RunLoop run_loop; |
200 media_stream_manager_->audio_output_device_enumerator()->Enumerate( | 208 media_stream_manager_->audio_output_device_enumerator()->Enumerate( |
201 base::Bind(&WaitForEnumeration, &run_loop)); | 209 base::Bind(&WaitForEnumeration, &run_loop)); |
202 run_loop.Run(); | 210 run_loop.Run(); |
203 | 211 |
204 host_ = new MockAudioRendererHost(audio_manager_.get(), &mirroring_manager_, | 212 host_ = new MockAudioRendererHost(audio_manager_.get(), &mirroring_manager_, |
205 MediaInternals::GetInstance(), | 213 MediaInternals::GetInstance(), |
206 media_stream_manager_.get(), | 214 media_stream_manager_.get(), |
207 GetMockSaltCallback()); | 215 GetMockSaltCallback()); |
208 | 216 |
217 audio_output_impl_.reset(host_->Init(host_.get())); | |
218 | |
209 // Simulate IPC channel connected. | 219 // Simulate IPC channel connected. |
210 host_->set_peer_process_for_testing(base::Process::Current()); | 220 host_->set_peer_process_for_testing(base::Process::Current()); |
211 } | 221 } |
212 | 222 |
213 ~AudioRendererHostTest() override { | 223 ~AudioRendererHostTest() override { |
214 // Simulate closing the IPC channel and give the audio thread time to close | 224 // Simulate closing the IPC channel and give the audio thread time to close |
215 // the underlying streams. | 225 // the underlying streams. |
216 host_->OnChannelClosing(); | 226 host_->OnChannelClosing(); |
217 SyncWithAudioThread(); | 227 SyncWithAudioThread(); |
218 | 228 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
254 media::AudioParameters::kAudioCDSampleRate / 10); | 264 media::AudioParameters::kAudioCDSampleRate / 10); |
255 int session_id = 0; | 265 int session_id = 0; |
256 if (unified_stream) { | 266 if (unified_stream) { |
257 // Use AudioInputDeviceManager::kFakeOpenSessionId as the session id to | 267 // Use AudioInputDeviceManager::kFakeOpenSessionId as the session id to |
258 // pass the permission check. | 268 // pass the permission check. |
259 session_id = AudioInputDeviceManager::kFakeOpenSessionId; | 269 session_id = AudioInputDeviceManager::kFakeOpenSessionId; |
260 } | 270 } |
261 host_->OnRequestDeviceAuthorization(kStreamId, kRenderFrameId, session_id, | 271 host_->OnRequestDeviceAuthorization(kStreamId, kRenderFrameId, session_id, |
262 device_id, security_origin); | 272 device_id, security_origin); |
263 if (expected_device_status == media::OUTPUT_DEVICE_STATUS_OK) { | 273 if (expected_device_status == media::OUTPUT_DEVICE_STATUS_OK) { |
264 host_->OnCreateStream(kStreamId, kRenderFrameId, params); | 274 host_->CreateStream(kStreamId, kRenderFrameId, params, |
275 base::Bind(&AudioRendererHostTest::CreateCallback, | |
276 base::Unretained(this))); | |
265 | 277 |
266 // At some point in the future, a corresponding RemoveDiverter() call must | 278 // At some point in the future, a corresponding RemoveDiverter() call must |
267 // be made. | 279 // be made. |
268 EXPECT_CALL(mirroring_manager_, RemoveDiverter(NotNull())) | 280 EXPECT_CALL(mirroring_manager_, RemoveDiverter(NotNull())) |
269 .RetiresOnSaturation(); | 281 .RetiresOnSaturation(); |
270 } | 282 } |
271 SyncWithAudioThread(); | 283 SyncWithAudioThread(); |
272 } | 284 } |
273 | 285 |
286 void CreateCallback(int stream_id, | |
287 media::interfaces::AudioOutputStreamPtr stream, | |
288 mojo::ScopedSharedBufferHandle shared_buffer, | |
289 mojo::ScopedHandle socket_descriptor) { | |
290 base::SharedMemoryHandle shared_memory_handle; | |
291 size_t length; | |
292 MojoResult pass_shared_memory_result = mojo::edk::PassSharedMemoryHandle( | |
293 shared_buffer.release().value(), &shared_memory_handle, &length, | |
294 nullptr); | |
295 | |
296 if (pass_shared_memory_result != MOJO_RESULT_OK) { | |
297 LOG(ERROR) << "Failed to pass shared memory. Closing: " | |
298 << pass_shared_memory_result; | |
299 return; | |
300 } | |
301 mojo::edk::ScopedPlatformHandle platform_handle; | |
302 | |
303 MojoResult pass_platform_handle_result = | |
304 mojo::edk::PassWrappedPlatformHandle( | |
305 socket_descriptor.release().value(), &platform_handle); | |
306 | |
307 if (pass_platform_handle_result != MOJO_RESULT_OK) { | |
308 LOG(ERROR) << "Failed to pass transit descriptor. Closing: " | |
309 << pass_platform_handle_result; | |
310 return; | |
311 } | |
312 | |
313 base::SyncSocket::TransitDescriptor descriptor; | |
314 #if defined(OS_WIN) | |
315 descriptor = platform_handle.release().handle; | |
316 #else | |
317 descriptor.fd = platform_handle.release().handle; | |
318 #endif | |
319 | |
320 host_->OnNotifyStreamCreated(stream_id, shared_memory_handle, descriptor, | |
321 length); | |
322 streams_[stream_id] = make_scoped_ptr( | |
Henrik Grunell
2016/05/02 12:12:23
This isn't used anywhere. We talked about this off
rchtara
2016/05/23 16:38:17
it's not needed anymore.
| |
323 new media::interfaces::AudioOutputStreamPtr(std::move(stream))); | |
324 } | |
325 | |
274 void Close() { | 326 void Close() { |
275 // Send a message to AudioRendererHost to tell it we want to close the | 327 // Send a message to AudioRendererHost to tell it we want to close the |
276 // stream. | 328 // stream. |
277 host_->OnCloseStream(kStreamId); | 329 host_->OnCloseStream(kStreamId); |
278 SyncWithAudioThread(); | 330 SyncWithAudioThread(); |
279 } | 331 } |
280 | 332 |
281 void Play() { | 333 void Play() { |
282 EXPECT_CALL(*host_.get(), OnStreamPlaying(kStreamId)); | 334 EXPECT_CALL(*host_.get(), OnStreamPlaying(kStreamId)); |
283 host_->OnPlayStream(kStreamId); | 335 host_->OnPlayStream(kStreamId); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
317 void SyncWithAudioThread() { | 369 void SyncWithAudioThread() { |
318 base::RunLoop().RunUntilIdle(); | 370 base::RunLoop().RunUntilIdle(); |
319 | 371 |
320 base::RunLoop run_loop; | 372 base::RunLoop run_loop; |
321 audio_manager_->GetTaskRunner()->PostTask( | 373 audio_manager_->GetTaskRunner()->PostTask( |
322 FROM_HERE, media::BindToCurrentLoop(run_loop.QuitClosure())); | 374 FROM_HERE, media::BindToCurrentLoop(run_loop.QuitClosure())); |
323 run_loop.Run(); | 375 run_loop.Run(); |
324 } | 376 } |
325 | 377 |
326 private: | 378 private: |
379 typedef std::map<int, | |
380 std::unique_ptr<media::interfaces::AudioOutputStreamPtr>> | |
381 ScopedAudioOutputStreamPtrMap; | |
327 // MediaStreamManager uses a DestructionObserver, so it must outlive the | 382 // MediaStreamManager uses a DestructionObserver, so it must outlive the |
328 // TestBrowserThreadBundle. | 383 // TestBrowserThreadBundle. |
329 std::unique_ptr<MediaStreamManager> media_stream_manager_; | 384 std::unique_ptr<MediaStreamManager> media_stream_manager_; |
330 TestBrowserThreadBundle thread_bundle_; | 385 TestBrowserThreadBundle thread_bundle_; |
331 std::unique_ptr<media::AudioManager> audio_manager_; | 386 std::unique_ptr<media::AudioManager> audio_manager_; |
332 MockAudioMirroringManager mirroring_manager_; | 387 MockAudioMirroringManager mirroring_manager_; |
333 scoped_refptr<MockAudioRendererHost> host_; | 388 scoped_refptr<MockAudioRendererHost> host_; |
389 std::unique_ptr<AudioOutputImpl> audio_output_impl_; | |
390 ScopedAudioOutputStreamPtrMap streams_; | |
334 | 391 |
335 DISALLOW_COPY_AND_ASSIGN(AudioRendererHostTest); | 392 DISALLOW_COPY_AND_ASSIGN(AudioRendererHostTest); |
336 }; | 393 }; |
337 | 394 |
338 TEST_F(AudioRendererHostTest, CreateAndClose) { | 395 TEST_F(AudioRendererHostTest, CreateAndClose) { |
339 Create(); | 396 Create(); |
340 Close(); | 397 Close(); |
341 } | 398 } |
342 | 399 |
343 // Simulate the case where a stream is not properly closed. | 400 // Simulate the case where a stream is not properly closed. |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
406 } | 463 } |
407 | 464 |
408 TEST_F(AudioRendererHostTest, CreateInvalidDevice) { | 465 TEST_F(AudioRendererHostTest, CreateInvalidDevice) { |
409 Create(false, kInvalidDeviceId, url::Origin(GURL(kSecurityOrigin))); | 466 Create(false, kInvalidDeviceId, url::Origin(GURL(kSecurityOrigin))); |
410 Close(); | 467 Close(); |
411 } | 468 } |
412 | 469 |
413 // TODO(hclam): Add tests for data conversation in low latency mode. | 470 // TODO(hclam): Add tests for data conversation in low latency mode. |
414 | 471 |
415 } // namespace content | 472 } // namespace content |
OLD | NEW |