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 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
12 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
13 #include "base/memory/shared_memory.h" | 13 #include "base/memory/shared_memory.h" |
14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
15 #include "base/process/process.h" | 15 #include "base/process/process.h" |
16 #include "content/browser/bad_message.h" | 16 #include "content/browser/bad_message.h" |
17 #include "content/browser/browser_main_loop.h" | 17 #include "content/browser/browser_main_loop.h" |
18 #include "content/browser/media/audio_stream_monitor.h" | 18 #include "content/browser/media/audio_stream_monitor.h" |
19 #include "content/browser/media/capture/audio_mirroring_manager.h" | 19 #include "content/browser/media/capture/audio_mirroring_manager.h" |
20 #include "content/browser/media/media_internals.h" | 20 #include "content/browser/media/media_internals.h" |
21 #include "content/browser/renderer_host/media/audio_input_device_manager.h" | 21 #include "content/browser/renderer_host/media/audio_input_device_manager.h" |
22 #include "content/browser/renderer_host/media/audio_sync_reader.h" | 22 #include "content/browser/renderer_host/media/audio_sync_reader.h" |
23 #include "content/browser/renderer_host/media/media_stream_manager.h" | 23 #include "content/browser/renderer_host/media/media_stream_manager.h" |
24 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" | 24 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" |
25 #include "content/browser/renderer_host/render_widget_host_impl.h" | 25 #include "content/browser/renderer_host/render_widget_host_impl.h" |
26 #include "content/common/media/audio_messages.h" | |
27 #include "content/public/browser/content_browser_client.h" | 26 #include "content/public/browser/content_browser_client.h" |
28 #include "content/public/browser/media_device_id.h" | 27 #include "content/public/browser/media_device_id.h" |
29 #include "content/public/browser/media_observer.h" | 28 #include "content/public/browser/media_observer.h" |
30 #include "content/public/browser/render_frame_host.h" | 29 #include "content/public/browser/render_frame_host.h" |
31 #include "content/public/common/content_switches.h" | 30 #include "content/public/common/content_switches.h" |
32 #include "media/audio/audio_device_description.h" | 31 #include "media/audio/audio_device_description.h" |
33 #include "media/audio/audio_streams_tracker.h" | 32 #include "media/audio/audio_streams_tracker.h" |
34 #include "media/base/audio_bus.h" | 33 #include "media/base/audio_bus.h" |
35 #include "media/base/limits.h" | 34 #include "media/base/limits.h" |
| 35 #include "media/mojo/interfaces/audio_output.mojom-shared.h" |
| 36 #include "media/mojo/interfaces/audio_output.mojom.h" |
| 37 #include "mojo/edk/embedder/embedder.h" |
| 38 #include "mojo/public/cpp/system/handle.h" |
| 39 #include "mojo/public/cpp/system/platform_handle.h" |
36 | 40 |
37 using media::AudioBus; | 41 using media::AudioBus; |
38 using media::AudioManager; | 42 using media::AudioManager; |
39 | 43 |
40 namespace content { | 44 namespace content { |
41 | 45 |
42 namespace { | 46 namespace { |
43 | 47 |
44 // Tracks the maximum number of simultaneous output streams browser-wide. | 48 // Tracks the maximum number of simultaneous output streams browser-wide. |
45 // Accessed on IO thread. | 49 // Accessed on IO thread. |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 const bool frame_exists = | 129 const bool frame_exists = |
126 !!RenderFrameHost::FromID(render_process_id, render_frame_id); | 130 !!RenderFrameHost::FromID(render_process_id, render_frame_id); |
127 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 131 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
128 base::Bind(callback, frame_exists)); | 132 base::Bind(callback, frame_exists)); |
129 } | 133 } |
130 #endif // DCHECK_IS_ON() | 134 #endif // DCHECK_IS_ON() |
131 | 135 |
132 } // namespace | 136 } // namespace |
133 | 137 |
134 class AudioRendererHost::AudioEntry | 138 class AudioRendererHost::AudioEntry |
135 : public media::AudioOutputController::EventHandler { | 139 : public media::AudioOutputController::EventHandler, |
| 140 private media::mojom::AudioOutputStream { |
136 public: | 141 public: |
137 AudioEntry(AudioRendererHost* host, | 142 AudioEntry(AudioRendererHost* host, |
| 143 CreateStreamCallback callback, |
138 int stream_id, | 144 int stream_id, |
139 int render_frame_id, | 145 int render_frame_id, |
140 const media::AudioParameters& params, | 146 const media::AudioParameters& params, |
141 const std::string& output_device_id, | 147 const std::string& output_device_id, |
142 std::unique_ptr<base::SharedMemory> shared_memory, | 148 std::unique_ptr<base::SharedMemory> shared_memory, |
143 std::unique_ptr<media::AudioOutputController::SyncReader> reader); | 149 std::unique_ptr<media::AudioOutputController::SyncReader> reader, |
| 150 media::mojom::AudioOutputStreamClientPtr output_stream_client); |
144 ~AudioEntry() override; | 151 ~AudioEntry() override; |
145 | 152 |
146 int stream_id() const { | 153 int stream_id() const { |
147 return stream_id_; | 154 return stream_id_; |
148 } | 155 } |
149 | 156 |
150 int render_frame_id() const { return render_frame_id_; } | 157 int render_frame_id() const { return render_frame_id_; } |
151 | 158 |
152 media::AudioOutputController* controller() const { return controller_.get(); } | 159 media::AudioOutputController* controller() const { return controller_.get(); } |
153 | 160 |
154 base::SharedMemory* shared_memory() { | 161 base::SharedMemory* shared_memory() { |
155 return shared_memory_.get(); | 162 return shared_memory_.get(); |
156 } | 163 } |
157 | 164 |
158 media::AudioOutputController::SyncReader* reader() const { | 165 media::AudioOutputController::SyncReader* reader() const { |
159 return reader_.get(); | 166 return reader_.get(); |
160 } | 167 } |
161 | 168 |
162 bool playing() const { return playing_; } | 169 bool playing() const { return playing_; } |
163 void set_playing(bool playing) { playing_ = playing; } | 170 void set_playing(bool playing) { playing_ = playing; } |
164 | 171 |
| 172 // media::mojom::AudioOutputStream implementation |
| 173 void Play() override; |
| 174 void Pause() override; |
| 175 void SetVolume(double volume) override; |
| 176 |
| 177 void OnConnectionError(); |
| 178 bool SendStreamStateResponse(media::mojom::AudioOutputStreamState state); |
| 179 void BindRequest(media::mojom::AudioOutputStreamRequest); |
| 180 |
165 private: | 181 private: |
166 // media::AudioOutputController::EventHandler implementation. | 182 // media::AudioOutputController::EventHandler implementation. |
167 void OnCreated() override; | 183 void OnCreated() override; |
168 void OnPlaying() override; | 184 void OnPlaying() override; |
169 void OnPaused() override; | 185 void OnPaused() override; |
170 void OnError() override; | 186 void OnError() override; |
171 | 187 |
172 AudioRendererHost* const host_; | 188 AudioRendererHost* const host_; |
173 const int stream_id_; | 189 const int stream_id_; |
174 | 190 |
175 // The routing ID of the source RenderFrame. | 191 // The routing ID of the source RenderFrame. |
176 const int render_frame_id_; | 192 const int render_frame_id_; |
177 | 193 |
178 // Shared memory for transmission of the audio data. Used by |reader_|. | 194 // Shared memory for transmission of the audio data. Used by |reader_|. |
179 const std::unique_ptr<base::SharedMemory> shared_memory_; | 195 const std::unique_ptr<base::SharedMemory> shared_memory_; |
180 | 196 |
181 // The synchronous reader to be used by |controller_|. | 197 // The synchronous reader to be used by |controller_|. |
182 const std::unique_ptr<media::AudioOutputController::SyncReader> reader_; | 198 const std::unique_ptr<media::AudioOutputController::SyncReader> reader_; |
183 | 199 |
184 // The AudioOutputController that manages the audio stream. | 200 // The AudioOutputController that manages the audio stream. |
185 const scoped_refptr<media::AudioOutputController> controller_; | 201 const scoped_refptr<media::AudioOutputController> controller_; |
186 | 202 |
| 203 // Used for communication with the bound AudioOutputStreamClient. |
| 204 media::mojom::AudioOutputStreamClientPtr output_stream_client_; |
| 205 |
| 206 // Binds |this| to an AudioOutputStreamPtr that is passed to the |
| 207 // AudioOutputStreamClient (AudioOutputIPC in the renderer process). |
| 208 std::unique_ptr<mojo::Binding<media::mojom::AudioOutputStream>> binding_; |
| 209 |
| 210 CreateStreamCallback callback_; |
| 211 |
187 bool playing_; | 212 bool playing_; |
| 213 |
| 214 DISALLOW_COPY_AND_ASSIGN(AudioEntry); |
188 }; | 215 }; |
189 | 216 |
190 AudioRendererHost::AudioEntry::AudioEntry( | 217 AudioRendererHost::AudioEntry::AudioEntry( |
191 AudioRendererHost* host, | 218 AudioRendererHost* host, |
| 219 CreateStreamCallback callback, |
192 int stream_id, | 220 int stream_id, |
193 int render_frame_id, | 221 int render_frame_id, |
194 const media::AudioParameters& params, | 222 const media::AudioParameters& params, |
195 const std::string& output_device_id, | 223 const std::string& output_device_id, |
196 std::unique_ptr<base::SharedMemory> shared_memory, | 224 std::unique_ptr<base::SharedMemory> shared_memory, |
197 std::unique_ptr<media::AudioOutputController::SyncReader> reader) | 225 std::unique_ptr<media::AudioOutputController::SyncReader> reader, |
| 226 media::mojom::AudioOutputStreamClientPtr output_stream_client) |
198 : host_(host), | 227 : host_(host), |
199 stream_id_(stream_id), | 228 stream_id_(stream_id), |
200 render_frame_id_(render_frame_id), | 229 render_frame_id_(render_frame_id), |
201 shared_memory_(std::move(shared_memory)), | 230 shared_memory_(std::move(shared_memory)), |
202 reader_(std::move(reader)), | 231 reader_(std::move(reader)), |
203 controller_(media::AudioOutputController::Create(host->audio_manager_, | 232 controller_(media::AudioOutputController::Create(host->audio_manager_, |
204 this, | 233 this, |
205 params, | 234 params, |
206 output_device_id, | 235 output_device_id, |
207 reader_.get())), | 236 reader_.get())), |
| 237 output_stream_client_(std::move(output_stream_client)), |
| 238 callback_(callback), |
208 playing_(false) { | 239 playing_(false) { |
209 DCHECK(controller_.get()); | 240 DCHECK(controller_.get()); |
| 241 |
| 242 if (output_stream_client_.is_bound()) |
| 243 output_stream_client_.set_connection_error_handler( |
| 244 base::Bind(&AudioEntry::OnConnectionError, base::Unretained(this))); |
| 245 else |
| 246 BrowserThread::PostTask( |
| 247 BrowserThread::IO, FROM_HERE, |
| 248 base::Bind(&AudioRendererHost::OnCloseStream, host_, stream_id_)); |
| 249 } |
| 250 |
| 251 void AudioRendererHost::AudioEntry::Play() { |
| 252 controller_->Play(); |
| 253 host_->audio_log_->OnStarted(stream_id_); |
| 254 } |
| 255 |
| 256 void AudioRendererHost::AudioEntry::Pause() { |
| 257 controller_->Pause(); |
| 258 host_->audio_log_->OnStopped(stream_id_); |
| 259 } |
| 260 |
| 261 void AudioRendererHost::AudioEntry::SetVolume(double volume) { |
| 262 if (volume < 0 || volume > 1.0) |
| 263 return; |
| 264 |
| 265 controller_->SetVolume(volume); |
| 266 host_->audio_log_->OnSetVolume(stream_id_, volume); |
| 267 } |
| 268 |
| 269 void AudioRendererHost::AudioEntry::OnConnectionError() { |
| 270 binding_.reset(); |
| 271 output_stream_client_.reset(); |
| 272 |
| 273 BrowserThread::PostTask( |
| 274 BrowserThread::IO, FROM_HERE, |
| 275 base::Bind(&AudioRendererHost::CloseStream, host_, stream_id_)); |
| 276 } |
| 277 |
| 278 bool AudioRendererHost::AudioEntry::SendStreamStateResponse( |
| 279 media::mojom::AudioOutputStreamState state) { |
| 280 if (!output_stream_client_.is_bound()) |
| 281 return false; |
| 282 |
| 283 output_stream_client_->OnStreamStateChange(state); |
| 284 return true; |
| 285 } |
| 286 |
| 287 void AudioRendererHost::AudioEntry::BindRequest( |
| 288 media::mojom::AudioOutputStreamRequest request) { |
| 289 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 290 |
| 291 binding_.reset(new mojo::Binding<media::mojom::AudioOutputStream>( |
| 292 this, std::move(request))); |
| 293 binding_->set_connection_error_handler( |
| 294 base::Bind(&AudioEntry::OnConnectionError, base::Unretained(this))); |
210 } | 295 } |
211 | 296 |
212 AudioRendererHost::AudioEntry::~AudioEntry() {} | 297 AudioRendererHost::AudioEntry::~AudioEntry() {} |
213 | 298 |
214 /////////////////////////////////////////////////////////////////////////////// | 299 /////////////////////////////////////////////////////////////////////////////// |
215 // AudioRendererHost implementations. | 300 // AudioRendererHost implementations. |
216 | 301 |
217 AudioRendererHost::AudioRendererHost(int render_process_id, | 302 AudioRendererHost::AudioRendererHost(int render_process_id, |
218 media::AudioManager* audio_manager, | 303 media::AudioManager* audio_manager, |
219 AudioMirroringManager* mirroring_manager, | 304 AudioMirroringManager* mirroring_manager, |
220 MediaInternals* media_internals, | 305 MediaInternals* media_internals, |
221 MediaStreamManager* media_stream_manager, | 306 MediaStreamManager* media_stream_manager, |
222 const std::string& salt) | 307 const std::string& salt) |
223 : BrowserMessageFilter(AudioMsgStart), | 308 : render_process_id_(render_process_id), |
224 render_process_id_(render_process_id), | |
225 audio_manager_(audio_manager), | 309 audio_manager_(audio_manager), |
226 mirroring_manager_(mirroring_manager), | 310 mirroring_manager_(mirroring_manager), |
227 audio_log_(media_internals->CreateAudioLog( | 311 audio_log_(media_internals->CreateAudioLog( |
228 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), | 312 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), |
229 media_stream_manager_(media_stream_manager), | 313 media_stream_manager_(media_stream_manager), |
230 num_playing_streams_(0), | 314 num_playing_streams_(0), |
231 salt_(salt), | 315 salt_(salt), |
232 #if DCHECK_IS_ON() | 316 #if DCHECK_IS_ON() |
233 validate_render_frame_id_function_(&ValidateRenderFrameId), | 317 validate_render_frame_id_function_(&ValidateRenderFrameId), |
234 #endif // DCHECK_IS_ON() | 318 #endif // DCHECK_IS_ON() |
(...skipping 21 matching lines...) Expand all Loading... |
256 } | 340 } |
257 | 341 |
258 void AudioRendererHost::GetOutputControllers( | 342 void AudioRendererHost::GetOutputControllers( |
259 const RenderProcessHost::GetAudioOutputControllersCallback& | 343 const RenderProcessHost::GetAudioOutputControllersCallback& |
260 callback) const { | 344 callback) const { |
261 BrowserThread::PostTaskAndReplyWithResult( | 345 BrowserThread::PostTaskAndReplyWithResult( |
262 BrowserThread::IO, FROM_HERE, | 346 BrowserThread::IO, FROM_HERE, |
263 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback); | 347 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback); |
264 } | 348 } |
265 | 349 |
266 void AudioRendererHost::OnChannelClosing() { | |
267 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
268 // Since the IPC sender is gone, close all requested audio streams. | |
269 while (!audio_entries_.empty()) { | |
270 // Note: OnCloseStream() removes the entries from audio_entries_. | |
271 OnCloseStream(audio_entries_.begin()->first); | |
272 } | |
273 | |
274 // Remove any authorizations for streams that were not yet created | |
275 authorizations_.clear(); | |
276 } | |
277 | |
278 void AudioRendererHost::OnDestruct() const { | |
279 BrowserThread::DeleteOnIOThread::Destruct(this); | |
280 } | |
281 | |
282 void AudioRendererHost::AudioEntry::OnCreated() { | 350 void AudioRendererHost::AudioEntry::OnCreated() { |
283 BrowserThread::PostTask( | 351 // TODO: make sure it's safe to capture |this| in the callback. |
284 BrowserThread::IO, | 352 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
285 FROM_HERE, | 353 base::Bind(&AudioRendererHost::DoCompleteCreation, |
286 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_)); | 354 host_, this, stream_id_, callback_)); |
287 } | 355 } |
288 | 356 |
289 void AudioRendererHost::AudioEntry::OnPlaying() { | 357 void AudioRendererHost::AudioEntry::OnPlaying() { |
290 BrowserThread::PostTask( | 358 output_stream_client_->OnStreamStateChange( |
291 BrowserThread::IO, | 359 ::media::mojom::AudioOutputStreamState::PLAYING); |
292 FROM_HERE, | |
293 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged, | |
294 host_, | |
295 stream_id_, | |
296 true)); | |
297 } | 360 } |
298 | 361 |
299 void AudioRendererHost::AudioEntry::OnPaused() { | 362 void AudioRendererHost::AudioEntry::OnPaused() { |
300 BrowserThread::PostTask( | 363 output_stream_client_->OnStreamStateChange( |
301 BrowserThread::IO, | 364 ::media::mojom::AudioOutputStreamState::PAUSED); |
302 FROM_HERE, | |
303 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged, | |
304 host_, | |
305 stream_id_, | |
306 false)); | |
307 } | 365 } |
308 | 366 |
309 void AudioRendererHost::AudioEntry::OnError() { | 367 void AudioRendererHost::AudioEntry::OnError() { |
| 368 output_stream_client_->OnStreamStateChange( |
| 369 ::media::mojom::AudioOutputStreamState::ERROR); |
310 BrowserThread::PostTask( | 370 BrowserThread::PostTask( |
311 BrowserThread::IO, | 371 BrowserThread::IO, FROM_HERE, |
312 FROM_HERE, | 372 base::Bind(&AudioRendererHost::OnCloseStream, host_, stream_id_)); |
313 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_)); | |
314 } | 373 } |
315 | 374 |
316 void AudioRendererHost::DoCompleteCreation(int stream_id) { | 375 void AudioRendererHost::DoCompleteCreation(AudioEntry* entry, |
| 376 int stream_id, |
| 377 CreateStreamCallback callback) { |
317 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 378 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
318 | 379 |
319 if (!PeerHandle()) { | 380 media::mojom::AudioOutputStreamPtr stream_ptr; |
320 DLOG(WARNING) << "Renderer process handle is invalid."; | 381 entry->BindRequest(mojo::GetProxy(&stream_ptr)); |
321 ReportErrorAndClose(stream_id); | |
322 return; | |
323 } | |
324 | |
325 AudioEntry* const entry = LookupById(stream_id); | |
326 if (!entry) { | |
327 ReportErrorAndClose(stream_id); | |
328 return; | |
329 } | |
330 | |
331 // Once the audio stream is created then complete the creation process by | |
332 // mapping shared memory and sharing with the renderer process. | |
333 base::SharedMemoryHandle foreign_memory_handle; | |
334 if (!entry->shared_memory()->ShareToProcess(PeerHandle(), | |
335 &foreign_memory_handle)) { | |
336 // If we failed to map and share the shared memory then close the audio | |
337 // stream and send an error message. | |
338 ReportErrorAndClose(entry->stream_id()); | |
339 return; | |
340 } | |
341 | 382 |
342 AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader()); | 383 AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader()); |
| 384 base::PlatformFile socket_fd = reader->GetSyncSocket(); |
| 385 mojo::ScopedHandle socket_handle = mojo::WrapPlatformFile(socket_fd); |
| 386 DCHECK(socket_handle.is_valid()); |
343 | 387 |
344 base::SyncSocket::TransitDescriptor socket_descriptor; | 388 base::SharedMemoryHandle shared_memory_handle = |
| 389 base::SharedMemory::DuplicateHandle(entry->shared_memory()->handle()); |
| 390 if (!base::SharedMemory::IsHandleValid(shared_memory_handle)) { |
| 391 // TODO: When can this happen? |
| 392 LOG(FATAL) << "Invalid shared mem handle"; |
| 393 return ReportErrorAndClose(stream_id); |
| 394 } |
| 395 mojo::ScopedSharedBufferHandle shared_buffer_handle = |
| 396 mojo::WrapSharedMemoryHandle(shared_memory_handle, |
| 397 entry->shared_memory()->requested_size(), |
| 398 false); |
| 399 DCHECK(shared_buffer_handle.is_valid()); |
345 | 400 |
346 // If we failed to prepare the sync socket for the renderer then we fail | 401 /*mojo::ScopedSharedBufferHandle shared_buffer_handle = |
347 // the construction of audio stream. | 402 mojo::WrapSharedMemoryHandle(shared_memory_handle, |
348 if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) { | 403 entry->shared_memory()->requested_size(), |
349 ReportErrorAndClose(entry->stream_id()); | 404 false);*/ |
350 return; | |
351 } | |
352 | 405 |
353 Send(new AudioMsg_NotifyStreamCreated( | 406 /* TODO: read comment. |
354 entry->stream_id(), foreign_memory_handle, socket_descriptor, | 407 // The socket sent from the browser to the renderer is a ForeignSocket, which |
355 entry->shared_memory()->requested_size())); | 408 // is a part of AudioSyncReader that is owned by AudioEntry. The socket handle |
| 409 // is closed when the owning AudioEntry destructs. With mojo, the ownership of |
| 410 // the handle is transferred to the target process. The handle is no longer |
| 411 // valid in the sending process, and cannot be closed there. If the socket |
| 412 // handle is closed when the AudioEntry is deleted, an error occurs. To WAR |
| 413 // this error, duplicate the socket and send the duplicate to the renderer. |
| 414 #if defined(OS_WIN) |
| 415 mojo::ScopedHandle socket_handle = |
| 416 mojo::WrapPlatformFile(socket_descriptor); |
| 417 #else |
| 418 mojo::ScopedHandle socket_handle = |
| 419 mojo::WrapPlatformFile(socket_descriptor.fd); |
| 420 #endif |
| 421 */ |
| 422 |
| 423 callback.Run(std::move(stream_ptr), std::move(shared_buffer_handle), |
| 424 std::move(socket_handle)); |
356 } | 425 } |
357 | 426 |
358 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id, | 427 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id, |
359 bool is_playing) { | 428 bool is_playing) { |
360 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 429 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
361 | 430 |
362 AudioEntry* const entry = LookupById(stream_id); | 431 AudioEntry* const entry = LookupById(stream_id); |
363 if (!entry) | 432 if (!entry) |
364 return; | 433 return; |
365 | 434 |
366 Send(new AudioMsg_NotifyStreamStateChanged( | 435 entry->SendStreamStateResponse( |
367 stream_id, | 436 is_playing ? media::mojom::AudioOutputStreamState::PLAYING |
368 is_playing ? media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING | 437 : media::mojom::AudioOutputStreamState::PAUSED); |
369 : media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED)); | |
370 | 438 |
371 if (is_playing) { | 439 if (is_playing) { |
372 AudioStreamMonitor::StartMonitoringStream( | 440 AudioStreamMonitor::StartMonitoringStream( |
373 render_process_id_, | 441 render_process_id_, |
374 entry->render_frame_id(), | 442 entry->render_frame_id(), |
375 entry->stream_id(), | 443 entry->stream_id(), |
376 base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip, | 444 base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip, |
377 entry->controller())); | 445 entry->controller())); |
378 } else { | 446 } else { |
379 AudioStreamMonitor::StopMonitoringStream( | 447 AudioStreamMonitor::StopMonitoringStream( |
380 render_process_id_, entry->render_frame_id(), entry->stream_id()); | 448 render_process_id_, entry->render_frame_id(), entry->stream_id()); |
381 } | 449 } |
382 UpdateNumPlayingStreams(entry, is_playing); | 450 UpdateNumPlayingStreams(entry, is_playing); |
383 } | 451 } |
384 | 452 |
385 RenderProcessHost::AudioOutputControllerList | 453 RenderProcessHost::AudioOutputControllerList |
386 AudioRendererHost::DoGetOutputControllers() const { | 454 AudioRendererHost::DoGetOutputControllers() const { |
387 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 455 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
388 | 456 |
389 RenderProcessHost::AudioOutputControllerList controllers; | 457 RenderProcessHost::AudioOutputControllerList controllers; |
390 for (AudioEntryMap::const_iterator it = audio_entries_.begin(); | 458 for (AudioEntryMap::const_iterator it = audio_entries_.begin(); |
391 it != audio_entries_.end(); | 459 it != audio_entries_.end(); |
392 ++it) { | 460 ++it) { |
393 controllers.push_back(it->second->controller()); | 461 controllers.push_back(it->second->controller()); |
394 } | 462 } |
395 | 463 |
396 return controllers; | 464 return controllers; |
397 } | 465 } |
398 | 466 |
399 /////////////////////////////////////////////////////////////////////////////// | 467 void AudioRendererHost::OnDeviceAuthorized( |
400 // IPC Messages handler | |
401 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) { | |
402 bool handled = true; | |
403 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message) | |
404 IPC_MESSAGE_HANDLER(AudioHostMsg_RequestDeviceAuthorization, | |
405 OnRequestDeviceAuthorization) | |
406 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream) | |
407 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream) | |
408 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) | |
409 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) | |
410 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) | |
411 IPC_MESSAGE_UNHANDLED(handled = false) | |
412 IPC_END_MESSAGE_MAP() | |
413 | |
414 return handled; | |
415 } | |
416 | |
417 void AudioRendererHost::OnRequestDeviceAuthorization( | |
418 int stream_id, | 468 int stream_id, |
419 int render_frame_id, | 469 RequestDeviceAuthorizationCallback callback, |
420 int session_id, | |
421 const std::string& device_id, | 470 const std::string& device_id, |
422 const url::Origin& security_origin) { | 471 const url::Origin& security_origin, |
423 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 472 base::TimeTicks auth_start_time, |
424 const base::TimeTicks auth_start_time = base::TimeTicks::Now(); | 473 bool have_access) { |
425 | |
426 DVLOG(1) << "AudioRendererHost@" << this << "::OnRequestDeviceAuthorization" | |
427 << "(stream_id=" << stream_id | |
428 << ", render_frame_id=" << render_frame_id | |
429 << ", session_id=" << session_id << ", device_id=" << device_id | |
430 << ", security_origin=" << security_origin << ")"; | |
431 | |
432 if (LookupById(stream_id) || IsAuthorizationStarted(stream_id)) | |
433 return; | |
434 | |
435 if (!IsValidDeviceId(device_id)) { | |
436 UMALogDeviceAuthorizationTime(auth_start_time); | |
437 Send(new AudioMsg_NotifyDeviceAuthorized( | |
438 stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, | |
439 media::AudioParameters::UnavailableDeviceParams(), std::string())); | |
440 return; | |
441 } | |
442 | |
443 // If |session_id should be used for output device selection and such output | |
444 // device is found, reuse the input device permissions. | |
445 if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id, | |
446 device_id)) { | |
447 const StreamDeviceInfo* info = | |
448 media_stream_manager_->audio_input_device_manager() | |
449 ->GetOpenedDeviceInfoById(session_id); | |
450 if (info) { | |
451 media::AudioParameters output_params( | |
452 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, | |
453 static_cast<media::ChannelLayout>( | |
454 info->device.matched_output.channel_layout), | |
455 info->device.matched_output.sample_rate, 16, | |
456 info->device.matched_output.frames_per_buffer); | |
457 output_params.set_effects(info->device.matched_output.effects); | |
458 authorizations_.insert(MakeAuthorizationData( | |
459 stream_id, true, info->device.matched_output_device_id)); | |
460 MaybeFixAudioParameters(&output_params); | |
461 UMALogDeviceAuthorizationTime(auth_start_time); | |
462 // Hash matched device id and pass it to the renderer | |
463 Send(new AudioMsg_NotifyDeviceAuthorized( | |
464 stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, | |
465 GetHMACForMediaDeviceID(salt_, security_origin, | |
466 info->device.matched_output_device_id))); | |
467 return; | |
468 } | |
469 } | |
470 | |
471 authorizations_.insert( | |
472 MakeAuthorizationData(stream_id, false, std::string())); | |
473 CheckOutputDeviceAccess( | |
474 render_frame_id, device_id, security_origin, | |
475 base::Bind(&AudioRendererHost::OnDeviceAuthorized, this, stream_id, | |
476 device_id, security_origin, auth_start_time)); | |
477 } | |
478 | |
479 void AudioRendererHost::OnDeviceAuthorized(int stream_id, | |
480 const std::string& device_id, | |
481 const url::Origin& security_origin, | |
482 base::TimeTicks auth_start_time, | |
483 bool have_access) { | |
484 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 474 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
485 const auto& auth_data = authorizations_.find(stream_id); | 475 const auto& auth_data = authorizations_.find(stream_id); |
486 | 476 |
487 // A close request was received while access check was in progress. | 477 // A close request was received while access check was in progress. |
488 if (auth_data == authorizations_.end()) { | 478 if (auth_data == authorizations_.end()) { |
489 UMALogDeviceAuthorizationTime(auth_start_time); | 479 UMALogDeviceAuthorizationTime(auth_start_time); |
490 return; | 480 return; |
491 } | 481 } |
492 | 482 |
493 if (!have_access) { | 483 if (!have_access) { |
494 authorizations_.erase(auth_data); | 484 authorizations_.erase(auth_data); |
495 UMALogDeviceAuthorizationTime(auth_start_time); | 485 UMALogDeviceAuthorizationTime(auth_start_time); |
496 Send(new AudioMsg_NotifyDeviceAuthorized( | 486 SendAuthorizationMessage( |
497 stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED, | 487 callback, stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED, |
498 media::AudioParameters::UnavailableDeviceParams(), std::string())); | 488 media::AudioParameters::UnavailableDeviceParams(), std::string()); |
499 return; | 489 return; |
500 } | 490 } |
501 | 491 |
502 // If enumerator caching is disabled, avoid the enumeration if the default | 492 // If enumerator caching is disabled, avoid the enumeration if the default |
503 // device is requested, since no device ID translation is needed. | 493 // device is requested, since no device ID translation is needed. |
504 // If enumerator caching is enabled, it is better to use its cache, even | 494 // If enumerator caching is enabled, it is better to use its cache, even |
505 // for the default device. | 495 // for the default device. |
506 if (media::AudioDeviceDescription::IsDefaultDevice(device_id) && | 496 if (media::AudioDeviceDescription::IsDefaultDevice(device_id) && |
507 !media_stream_manager_->audio_output_device_enumerator() | 497 !media_stream_manager_->audio_output_device_enumerator() |
508 ->IsCacheEnabled()) { | 498 ->IsCacheEnabled()) { |
509 base::PostTaskAndReplyWithResult( | 499 base::PostTaskAndReplyWithResult( |
510 audio_manager_->GetTaskRunner(), FROM_HERE, | 500 audio_manager_->GetTaskRunner(), FROM_HERE, |
511 base::Bind(&GetDefaultDeviceInfoOnDeviceThread, audio_manager_), | 501 base::Bind(&GetDefaultDeviceInfoOnDeviceThread, audio_manager_), |
512 base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this, stream_id, | 502 base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this, stream_id, |
513 auth_start_time, true)); | 503 auth_start_time, callback, true)); |
514 } else { | 504 } else { |
515 media_stream_manager_->audio_output_device_enumerator()->Enumerate( | 505 media_stream_manager_->audio_output_device_enumerator()->Enumerate( |
516 base::Bind(&AudioRendererHost::TranslateDeviceID, this, device_id, | 506 base::Bind(&AudioRendererHost::TranslateDeviceID, this, device_id, |
517 security_origin, | 507 security_origin, |
518 base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this, | 508 base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this, |
519 stream_id, auth_start_time))); | 509 stream_id, auth_start_time, callback))); |
520 } | 510 } |
521 } | 511 } |
522 | 512 |
523 void AudioRendererHost::OnDeviceIDTranslated( | 513 void AudioRendererHost::OnDeviceIDTranslated( |
524 int stream_id, | 514 int stream_id, |
525 base::TimeTicks auth_start_time, | 515 base::TimeTicks auth_start_time, |
| 516 RequestDeviceAuthorizationCallback callback, |
526 bool device_found, | 517 bool device_found, |
527 const AudioOutputDeviceInfo& device_info) { | 518 const AudioOutputDeviceInfo& device_info) { |
528 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 519 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
529 const auto& auth_data = authorizations_.find(stream_id); | 520 const auto& auth_data = authorizations_.find(stream_id); |
530 | 521 |
531 // A close request was received while translation was in progress | 522 // A close request was received while translation was in progress |
532 if (auth_data == authorizations_.end()) { | 523 if (auth_data == authorizations_.end()) { |
533 UMALogDeviceAuthorizationTime(auth_start_time); | 524 UMALogDeviceAuthorizationTime(auth_start_time); |
534 return; | 525 return; |
535 } | 526 } |
536 | 527 |
537 if (!device_found) { | 528 if (!device_found) { |
538 authorizations_.erase(auth_data); | 529 authorizations_.erase(auth_data); |
539 UMALogDeviceAuthorizationTime(auth_start_time); | 530 UMALogDeviceAuthorizationTime(auth_start_time); |
540 Send(new AudioMsg_NotifyDeviceAuthorized( | 531 SendAuthorizationMessage( |
541 stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, | 532 callback, stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, |
542 media::AudioParameters::UnavailableDeviceParams(), std::string())); | 533 media::AudioParameters::UnavailableDeviceParams(), std::string()); |
543 return; | 534 return; |
544 } | 535 } |
545 | 536 |
546 auth_data->second.first = true; | 537 auth_data->second.first = true; |
547 auth_data->second.second = device_info.unique_id; | 538 auth_data->second.second = device_info.unique_id; |
548 | 539 |
549 media::AudioParameters output_params = device_info.output_params; | 540 media::AudioParameters output_params = device_info.output_params; |
550 MaybeFixAudioParameters(&output_params); | 541 MaybeFixAudioParameters(&output_params); |
551 UMALogDeviceAuthorizationTime(auth_start_time); | 542 UMALogDeviceAuthorizationTime(auth_start_time); |
552 Send(new AudioMsg_NotifyDeviceAuthorized( | 543 SendAuthorizationMessage(callback, stream_id, media::OUTPUT_DEVICE_STATUS_OK, |
553 stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, std::string())); | 544 output_params, std::string()); |
554 } | 545 } |
555 | 546 |
556 void AudioRendererHost::OnCreateStream(int stream_id, | 547 void AudioRendererHost::DoCreateStream( |
557 int render_frame_id, | 548 int stream_id, |
558 const media::AudioParameters& params) { | 549 int render_frame_id, |
559 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 550 const media::AudioParameters& params, |
560 DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream" | 551 const std::string& device_unique_id, |
561 << "(stream_id=" << stream_id << ")"; | 552 media::mojom::AudioOutputStreamClientPtr client, |
562 | 553 CreateStreamCallback callback, |
563 // Determine whether to use the device_unique_id from an authorization, or an | 554 bool render_frame_id_is_valid) { |
564 // empty string (i.e., when no previous authorization was requested, assume | |
565 // default device). | |
566 std::string device_unique_id; | |
567 const auto& auth_data = authorizations_.find(stream_id); | |
568 if (auth_data != authorizations_.end()) { | |
569 CHECK(auth_data->second.first); | |
570 device_unique_id.swap(auth_data->second.second); | |
571 authorizations_.erase(auth_data); | |
572 } | |
573 | |
574 #if DCHECK_IS_ON() | |
575 // When DCHECKs are turned on, hop over to the UI thread to validate the | |
576 // |render_frame_id|, then continue stream creation on the IO thread. See | |
577 // comment at top of DoCreateStream() for further details. | |
578 BrowserThread::PostTask( | |
579 BrowserThread::UI, FROM_HERE, | |
580 base::Bind(validate_render_frame_id_function_, render_process_id_, | |
581 render_frame_id, | |
582 base::Bind(&AudioRendererHost::DoCreateStream, this, stream_id, | |
583 render_frame_id, params, device_unique_id))); | |
584 #else | |
585 DoCreateStream(stream_id, render_frame_id, params, device_unique_id, | |
586 render_frame_id > 0); | |
587 #endif // DCHECK_IS_ON() | |
588 } | |
589 | |
590 void AudioRendererHost::DoCreateStream(int stream_id, | |
591 int render_frame_id, | |
592 const media::AudioParameters& params, | |
593 const std::string& device_unique_id, | |
594 bool render_frame_id_is_valid) { | |
595 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 555 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
596 | 556 |
597 // Fail early if either of two sanity-checks fail: | 557 // Fail early if either of two sanity-checks fail: |
598 // 1. There should not yet exist an AudioEntry for the given |stream_id| | 558 // 1. There should not yet exist an AudioEntry for the given |stream_id| |
599 // since the renderer may not create two streams with the same ID. | 559 // since the renderer may not create two streams with the same ID. |
600 // 2. The render frame ID was either invalid or the render frame host it | 560 // 2. The render frame ID was either invalid or the render frame host it |
601 // references has shutdown before the request could be fulfilled (race | 561 // references has shutdown before the request could be fulfilled (race |
602 // condition). Renderers must *always* specify a valid render frame ID | 562 // condition). Renderers must *always* specify a valid render frame ID |
603 // for each audio output they create, as several browser-level features | 563 // for each audio output they create, as several browser-level features |
604 // depend on this (e.g., OOM manager, UI audio indicator, muting, audio | 564 // depend on this (e.g., OOM manager, UI audio indicator, muting, audio |
605 // capture). | 565 // capture). |
606 // Note: media::AudioParameters is validated in the deserializer, so there is | 566 // Note: media::AudioParameters is validated in the deserializer, so there is |
607 // no need to check that here. | 567 // no need to check that here. |
608 if (LookupById(stream_id)) { | 568 if (LookupById(stream_id)) { |
609 SendErrorMessage(stream_id); | 569 SendErrorMessage(stream_id); |
610 return; | 570 return; |
611 } | 571 } |
612 if (!render_frame_id_is_valid) { | 572 if (!render_frame_id_is_valid) { |
613 SendErrorMessage(stream_id); | 573 SendErrorMessage(stream_id); |
614 return; | 574 return; |
615 } | 575 } |
616 | 576 |
617 // Create the shared memory and share with the renderer process. | 577 // Create the shared memory and share with the renderer process. |
618 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + | 578 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + |
619 AudioBus::CalculateMemorySize(params); | 579 AudioBus::CalculateMemorySize(params); |
620 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); | 580 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); |
621 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { | 581 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { |
| 582 client->OnStreamStateChange(media::mojom::AudioOutputStreamState::ERROR); |
622 SendErrorMessage(stream_id); | 583 SendErrorMessage(stream_id); |
623 return; | 584 return; |
624 } | 585 } |
625 | 586 |
626 std::unique_ptr<AudioSyncReader> reader( | 587 std::unique_ptr<AudioSyncReader> reader( |
627 new AudioSyncReader(shared_memory.get(), params)); | 588 new AudioSyncReader(shared_memory.get(), params)); |
628 if (!reader->Init()) { | 589 if (!reader->Init()) { |
629 SendErrorMessage(stream_id); | 590 SendErrorMessage(stream_id); |
630 return; | 591 return; |
631 } | 592 } |
632 | 593 |
633 MediaObserver* const media_observer = | 594 MediaObserver* const media_observer = |
634 GetContentClient()->browser()->GetMediaObserver(); | 595 GetContentClient()->browser()->GetMediaObserver(); |
635 if (media_observer) | 596 if (media_observer) |
636 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id); | 597 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id); |
637 | 598 |
638 std::unique_ptr<AudioEntry> entry( | 599 std::unique_ptr<AudioEntry> entry(new AudioEntry( |
639 new AudioEntry(this, stream_id, render_frame_id, params, device_unique_id, | 600 this, callback, stream_id, render_frame_id, params, device_unique_id, |
640 std::move(shared_memory), std::move(reader))); | 601 std::move(shared_memory), std::move(reader), std::move(client))); |
641 if (mirroring_manager_) { | 602 if (mirroring_manager_) { |
642 mirroring_manager_->AddDiverter( | 603 mirroring_manager_->AddDiverter( |
643 render_process_id_, entry->render_frame_id(), entry->controller()); | 604 render_process_id_, entry->render_frame_id(), entry->controller()); |
644 } | 605 } |
645 audio_entries_.insert(std::make_pair(stream_id, entry.release())); | 606 audio_entries_.insert(std::make_pair(stream_id, entry.release())); |
646 g_audio_streams_tracker.Get().IncreaseStreamCount(); | 607 g_audio_streams_tracker.Get().IncreaseStreamCount(); |
647 | 608 |
648 audio_log_->OnCreated(stream_id, params, device_unique_id); | 609 audio_log_->OnCreated(stream_id, params, device_unique_id); |
649 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry( | 610 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry( |
650 stream_id, render_process_id_, render_frame_id, audio_log_.get()); | 611 stream_id, render_process_id_, render_frame_id, audio_log_.get()); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
689 } | 650 } |
690 | 651 |
691 // Make sure the volume is valid. | 652 // Make sure the volume is valid. |
692 if (volume < 0 || volume > 1.0) | 653 if (volume < 0 || volume > 1.0) |
693 return; | 654 return; |
694 entry->controller()->SetVolume(volume); | 655 entry->controller()->SetVolume(volume); |
695 audio_log_->OnSetVolume(stream_id, volume); | 656 audio_log_->OnSetVolume(stream_id, volume); |
696 } | 657 } |
697 | 658 |
698 void AudioRendererHost::SendErrorMessage(int stream_id) { | 659 void AudioRendererHost::SendErrorMessage(int stream_id) { |
699 Send(new AudioMsg_NotifyStreamStateChanged( | 660 AudioEntry* entry = LookupById(stream_id); |
700 stream_id, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)); | 661 if (entry) |
| 662 entry->SendStreamStateResponse(media::mojom::AudioOutputStreamState::ERROR); |
701 } | 663 } |
702 | 664 |
703 void AudioRendererHost::OnCloseStream(int stream_id) { | 665 void AudioRendererHost::OnCloseStream(int stream_id) { |
704 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 666 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
705 authorizations_.erase(stream_id); | 667 authorizations_.erase(stream_id); |
706 | 668 |
707 // Prevent oustanding callbacks from attempting to close/delete the same | 669 // Prevent oustanding callbacks from attempting to close/delete the same |
708 // AudioEntry twice. | 670 // AudioEntry twice. |
709 AudioEntryMap::iterator i = audio_entries_.find(stream_id); | 671 AudioEntryMap::iterator i = audio_entries_.find(stream_id); |
710 if (i == audio_entries_.end()) | 672 if (i == audio_entries_.end()) |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
784 base::Bind(&NotifyRenderProcessHostThatAudioStateChanged, | 746 base::Bind(&NotifyRenderProcessHostThatAudioStateChanged, |
785 render_process_id_)); | 747 render_process_id_)); |
786 } | 748 } |
787 } | 749 } |
788 } | 750 } |
789 | 751 |
790 bool AudioRendererHost::HasActiveAudio() { | 752 bool AudioRendererHost::HasActiveAudio() { |
791 return !base::AtomicRefCountIsZero(&num_playing_streams_); | 753 return !base::AtomicRefCountIsZero(&num_playing_streams_); |
792 } | 754 } |
793 | 755 |
| 756 void AudioRendererHost::BindRequest(media::mojom::AudioOutputRequest request) { |
| 757 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 758 |
| 759 binding_.reset( |
| 760 new mojo::Binding<media::mojom::AudioOutput>(this, std::move(request))); |
| 761 } |
| 762 |
| 763 // media::mojom::AudioOutput implementation |
| 764 void AudioRendererHost::RequestDeviceAuthorization( |
| 765 int stream_id, |
| 766 int render_frame_id, |
| 767 int session_id, |
| 768 const mojo::String& device_id, |
| 769 const url::Origin& origin, |
| 770 const RequestDeviceAuthorizationCallback& callback) { |
| 771 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 772 const base::TimeTicks auth_start_time = base::TimeTicks::Now(); |
| 773 |
| 774 DVLOG(1) << "AudioRendererHost@" << this << "::RequestDeviceAuthorization" |
| 775 << "(stream_id=" << stream_id |
| 776 << ", render_frame_id=" << render_frame_id |
| 777 << ", session_id=" << session_id << ", device_id=" << device_id |
| 778 << ", origin=" << origin << ")"; |
| 779 |
| 780 if (LookupById(stream_id) || IsAuthorizationStarted(stream_id)) |
| 781 return; |
| 782 |
| 783 if (!IsValidDeviceId(device_id)) { |
| 784 UMALogDeviceAuthorizationTime(auth_start_time); |
| 785 SendAuthorizationMessage( |
| 786 callback, stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, |
| 787 media::AudioParameters::UnavailableDeviceParams(), std::string()); |
| 788 return; |
| 789 } |
| 790 |
| 791 // If |session_id should be used for output device selection and such output |
| 792 // device is found, reuse the input device permissions. |
| 793 if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id, |
| 794 device_id)) { |
| 795 const StreamDeviceInfo* info = |
| 796 media_stream_manager_->audio_input_device_manager() |
| 797 ->GetOpenedDeviceInfoById(session_id); |
| 798 if (info) { |
| 799 media::AudioParameters output_params( |
| 800 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
| 801 static_cast<media::ChannelLayout>( |
| 802 info->device.matched_output.channel_layout), |
| 803 info->device.matched_output.sample_rate, 16, |
| 804 info->device.matched_output.frames_per_buffer); |
| 805 output_params.set_effects(info->device.matched_output.effects); |
| 806 authorizations_.insert(MakeAuthorizationData( |
| 807 stream_id, true, info->device.matched_output_device_id)); |
| 808 MaybeFixAudioParameters(&output_params); |
| 809 UMALogDeviceAuthorizationTime(auth_start_time); |
| 810 // Hash matched device id and pass it to the renderer |
| 811 SendAuthorizationMessage( |
| 812 callback, stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, |
| 813 GetHMACForMediaDeviceID(salt_, origin, |
| 814 info->device.matched_output_device_id)); |
| 815 return; |
| 816 } |
| 817 } |
| 818 |
| 819 authorizations_.insert( |
| 820 MakeAuthorizationData(stream_id, false, std::string())); |
| 821 CheckOutputDeviceAccess( |
| 822 render_frame_id, device_id, origin, |
| 823 base::Bind(&AudioRendererHost::OnDeviceAuthorized, this, stream_id, |
| 824 callback, device_id, origin, auth_start_time)); |
| 825 } |
| 826 |
| 827 void AudioRendererHost::CreateStream( |
| 828 int stream_id, |
| 829 int render_frame_id, |
| 830 media::mojom::AudioOutputStreamClientPtr client, |
| 831 const media::AudioParameters& params, |
| 832 const CreateStreamCallback& callback) { |
| 833 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 834 DVLOG(1) << "AudioRendererHost@" << this << "::CreateStream" |
| 835 << "(stream_id=" << stream_id << ")"; |
| 836 |
| 837 // Determine whether to use the device_unique_id from an authorization, or an |
| 838 // empty string (i.e., when no previous authorization was requested, assume |
| 839 // default device). |
| 840 std::string device_unique_id; |
| 841 const auto& auth_data = authorizations_.find(stream_id); |
| 842 if (auth_data != authorizations_.end()) { |
| 843 CHECK(auth_data->second.first); |
| 844 device_unique_id.swap(auth_data->second.second); |
| 845 authorizations_.erase(auth_data); |
| 846 } |
| 847 |
| 848 #if DCHECK_IS_ON() |
| 849 // When DCHECKs are turned on, hop over to the UI thread to validate the |
| 850 // |render_frame_id|, then continue stream creation on the IO thread. See |
| 851 // comment at top of DoCreateStream() for further details. |
| 852 BrowserThread::PostTask( |
| 853 BrowserThread::UI, FROM_HERE, |
| 854 base::Bind(validate_render_frame_id_function_, render_process_id_, |
| 855 render_frame_id, |
| 856 base::Bind(&AudioRendererHost::DoCreateStream, this, stream_id, |
| 857 render_frame_id, params, device_unique_id, |
| 858 base::Passed(&client), callback))); |
| 859 #else |
| 860 DoCreateStream(stream_id, render_frame_id, params, device_unique_id, |
| 861 std::move(client), callback, render_frame_id > 0); |
| 862 #endif // DCHECK_IS_ON() |
| 863 } |
| 864 |
| 865 void AudioRendererHost::CloseStream(int stream_id) { |
| 866 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 867 |
| 868 OnCloseStream(stream_id); |
| 869 } |
| 870 |
| 871 void AudioRendererHost::SendAuthorizationMessage( |
| 872 RequestDeviceAuthorizationCallback callback, |
| 873 int stream_id, |
| 874 media::OutputDeviceStatus status, |
| 875 const media::AudioParameters& params, |
| 876 const std::string& matched_device_id) { |
| 877 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 878 |
| 879 callback.Run(status, params, matched_device_id); |
| 880 } |
| 881 |
794 void AudioRendererHost::CheckOutputDeviceAccess( | 882 void AudioRendererHost::CheckOutputDeviceAccess( |
795 int render_frame_id, | 883 int render_frame_id, |
796 const std::string& device_id, | 884 const std::string& device_id, |
797 const url::Origin& security_origin, | 885 const url::Origin& security_origin, |
798 const OutputDeviceAccessCB& callback) { | 886 const OutputDeviceAccessCB& callback) { |
799 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 887 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
800 | 888 |
801 // Check security origin if nondefault device is requested. | 889 // Check security origin if nondefault device is requested. |
802 // Ignore check for default device, which is always authorized. | 890 // Ignore check for default device, which is always authorized. |
803 if (!media::AudioDeviceDescription::IsDefaultDevice(device_id) && | 891 if (!media::AudioDeviceDescription::IsDefaultDevice(device_id) && |
804 !MediaStreamManager::IsOriginAllowed(render_process_id_, | 892 !MediaStreamManager::IsOriginAllowed(render_process_id_, |
805 security_origin)) { | 893 security_origin)) { |
806 content::bad_message::ReceivedBadMessage(this, | 894 // content::bad_message::ReceivedBadMessage(this, |
807 bad_message::ARH_UNAUTHORIZED_URL); | 895 // bad_message::ARH_UNAUTHORIZED_URL); |
808 return; | 896 return; |
809 } | 897 } |
810 | 898 |
811 if (device_id.empty()) { | 899 if (device_id.empty()) { |
812 callback.Run(true); | 900 callback.Run(true); |
813 } else { | 901 } else { |
814 // Check that MediaStream device permissions have been granted, | 902 // Check that MediaStream device permissions have been granted, |
815 // hence the use of a MediaStreamUIProxy. | 903 // hence the use of a MediaStreamUIProxy. |
816 std::unique_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create(); | 904 std::unique_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create(); |
817 | 905 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
861 callback.Run(false, device_info); | 949 callback.Run(false, device_info); |
862 } | 950 } |
863 | 951 |
864 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { | 952 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { |
865 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 953 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
866 const auto& i = authorizations_.find(stream_id); | 954 const auto& i = authorizations_.find(stream_id); |
867 return i != authorizations_.end(); | 955 return i != authorizations_.end(); |
868 } | 956 } |
869 | 957 |
870 } // namespace content | 958 } // namespace content |
OLD | NEW |