Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: content/browser/renderer_host/media/audio_renderer_host.cc

Issue 1323403005: Allow AudioOutputDevice objects to be initialized with a specific hardware output device and store … (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Palmer's comments Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/shared_memory.h" 10 #include "base/memory/shared_memory.h"
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 bool is_playing, 54 bool is_playing,
55 int render_view_id) { 55 int render_view_id) {
56 DCHECK_CURRENTLY_ON(BrowserThread::IO); 56 DCHECK_CURRENTLY_ON(BrowserThread::IO);
57 if (render_view_id == MSG_ROUTING_NONE || !ResourceDispatcherHostImpl::Get()) 57 if (render_view_id == MSG_ROUTING_NONE || !ResourceDispatcherHostImpl::Get())
58 return; 58 return;
59 59
60 ResourceDispatcherHostImpl::Get()->OnAudioRenderHostStreamStateChanged( 60 ResourceDispatcherHostImpl::Get()->OnAudioRenderHostStreamStateChanged(
61 render_process_id, render_view_id, is_playing); 61 render_process_id, render_view_id, is_playing);
62 } 62 }
63 63
64 media::AudioParameters DummyParams() {
65 return media::AudioParameters(media::AudioParameters::AUDIO_PCM_LINEAR,
66 media::CHANNEL_LAYOUT_STEREO,
67 media::limits::kMinSampleRate, 1, 1);
68 }
69
70 std::pair<int, std::pair<bool, std::string>> MakeAuthorizationData(
71 int stream_id,
72 bool authorized,
73 const std::string& device_unique_id) {
74 return std::make_pair(stream_id,
75 std::make_pair(authorized, device_unique_id));
76 }
77
78 GURL ConvertToGURL(const url::Origin& origin) {
79 return origin.unique() ? GURL() : GURL(origin.Serialize());
80 }
81
82 bool IsValidDeviceId(const std::string& device_id) {
83 static const std::string::size_type kValidLength = 64;
84
85 if (device_id.empty())
palmer 2015/09/18 19:24:24 Why are empty device IDs valid? What are the seman
Guido Urdaneta 2015/09/18 20:17:56 The empty device ID represents the default output
86 return true;
87
88 if (device_id.length() != kValidLength)
89 return false;
90
91 for (const char& c : device_id) {
92 if ((c < 'a' || c > 'f') && (c < '0' || c > '9'))
93 return false;
94 }
95
96 return true;
97 }
98
64 } // namespace 99 } // namespace
65 100
66 class AudioRendererHost::AudioEntry 101 class AudioRendererHost::AudioEntry
67 : public media::AudioOutputController::EventHandler { 102 : public media::AudioOutputController::EventHandler {
68 public: 103 public:
69 AudioEntry(AudioRendererHost* host, 104 AudioEntry(AudioRendererHost* host,
70 int stream_id, 105 int stream_id,
71 int render_frame_id, 106 int render_frame_id,
72 const media::AudioParameters& params, 107 const media::AudioParameters& params,
73 const std::string& output_device_id, 108 const std::string& output_device_id,
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 BrowserThread::IO, FROM_HERE, 212 BrowserThread::IO, FROM_HERE,
178 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback); 213 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback);
179 } 214 }
180 215
181 void AudioRendererHost::OnChannelClosing() { 216 void AudioRendererHost::OnChannelClosing() {
182 // Since the IPC sender is gone, close all requested audio streams. 217 // Since the IPC sender is gone, close all requested audio streams.
183 while (!audio_entries_.empty()) { 218 while (!audio_entries_.empty()) {
184 // Note: OnCloseStream() removes the entries from audio_entries_. 219 // Note: OnCloseStream() removes the entries from audio_entries_.
185 OnCloseStream(audio_entries_.begin()->first); 220 OnCloseStream(audio_entries_.begin()->first);
186 } 221 }
222
223 // Remove any authorizations for streams that were not yet created
224 authorizations_.clear();
187 } 225 }
188 226
189 void AudioRendererHost::OnDestruct() const { 227 void AudioRendererHost::OnDestruct() const {
190 BrowserThread::DeleteOnIOThread::Destruct(this); 228 BrowserThread::DeleteOnIOThread::Destruct(this);
191 } 229 }
192 230
193 void AudioRendererHost::AudioEntry::OnCreated() { 231 void AudioRendererHost::AudioEntry::OnCreated() {
194 BrowserThread::PostTask( 232 BrowserThread::PostTask(
195 BrowserThread::IO, 233 BrowserThread::IO,
196 FROM_HERE, 234 FROM_HERE,
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 } 343 }
306 344
307 return controllers; 345 return controllers;
308 } 346 }
309 347
310 /////////////////////////////////////////////////////////////////////////////// 348 ///////////////////////////////////////////////////////////////////////////////
311 // IPC Messages handler 349 // IPC Messages handler
312 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) { 350 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
313 bool handled = true; 351 bool handled = true;
314 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message) 352 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message)
353 IPC_MESSAGE_HANDLER(AudioHostMsg_RequestDeviceAuthorization,
354 OnRequestDeviceAuthorization)
315 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream) 355 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
316 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream) 356 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
317 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) 357 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
318 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) 358 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
319 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) 359 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
320 IPC_MESSAGE_HANDLER(AudioHostMsg_SwitchOutputDevice, OnSwitchOutputDevice) 360 IPC_MESSAGE_HANDLER(AudioHostMsg_SwitchOutputDevice, OnSwitchOutputDevice)
321 IPC_MESSAGE_UNHANDLED(handled = false) 361 IPC_MESSAGE_UNHANDLED(handled = false)
322 IPC_END_MESSAGE_MAP() 362 IPC_END_MESSAGE_MAP()
323 363
324 return handled; 364 return handled;
325 } 365 }
326 366
367 void AudioRendererHost::OnRequestDeviceAuthorization(
368 int stream_id,
369 int render_frame_id,
370 int session_id,
371 const std::string& device_id,
372 const url::Origin& security_origin) {
373 DCHECK_CURRENTLY_ON(BrowserThread::IO);
374 DVLOG(1) << "AudioRendererHost@" << this << "::OnRequestDeviceAuthorization"
375 << "(stream_id=" << stream_id
376 << ", render_frame_id=" << render_frame_id
377 << ", session_id=" << session_id << ", device_id=" << device_id
378 << ", security_origin=" << security_origin << ")";
379
380 if (LookupById(stream_id) || IsAuthorizationStarted(stream_id))
381 return;
382
383 if (!IsValidDeviceId(device_id)) {
384 Send(new AudioMsg_NotifyDeviceAuthorized(stream_id, false, DummyParams()));
385 return;
386 }
387
388 // If attempting to use the output device associated to an opened input
389 // device and the output device is found, reuse the input device
390 // permissions.
391 if (session_id != 0) {
392 const StreamDeviceInfo* info =
393 media_stream_manager_->audio_input_device_manager()
394 ->GetOpenedDeviceInfoById(session_id);
395 if (info) {
396 media::AudioParameters output_params(
397 media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
398 static_cast<media::ChannelLayout>(
399 info->device.matched_output.channel_layout),
400 info->device.matched_output.sample_rate, 16,
401 info->device.matched_output.frames_per_buffer);
402 output_params.set_effects(info->device.matched_output.effects);
403 authorizations_.insert(MakeAuthorizationData(
404 stream_id, true, info->device.matched_output_device_id));
405 Send(new AudioMsg_NotifyDeviceAuthorized(stream_id, true, output_params));
406 return;
407 }
408 }
409
410 authorizations_.insert(
411 MakeAuthorizationData(stream_id, false, std::string()));
412 GURL gurl_security_origin = ConvertToGURL(security_origin);
413 CheckOutputDeviceAccess(
414 render_frame_id, device_id, gurl_security_origin,
415 base::Bind(&AudioRendererHost::OnDeviceAuthorized, this, stream_id,
416 device_id, gurl_security_origin));
417 }
418
419 void AudioRendererHost::OnDeviceAuthorized(int stream_id,
420 const std::string& device_id,
421 const GURL& gurl_security_origin,
422 bool have_access) {
423 DCHECK_CURRENTLY_ON(BrowserThread::IO);
424 const auto& auth_data = authorizations_.find(stream_id);
425
426 // A close request was received while access check was in progress.
427 if (auth_data == authorizations_.end())
428 return;
429
430 if (!have_access) {
431 authorizations_.erase(auth_data);
432 Send(new AudioMsg_NotifyDeviceAuthorized(stream_id, false, DummyParams()));
433 return;
434 }
435
436 TranslateDeviceID(
437 device_id, gurl_security_origin,
438 base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this, stream_id));
439 }
440
441 void AudioRendererHost::OnDeviceIDTranslated(
442 int stream_id,
443 bool device_found,
444 const AudioOutputDeviceInfo& device_info) {
445 DCHECK_CURRENTLY_ON(BrowserThread::IO);
446 const auto& auth_data = authorizations_.find(stream_id);
447
448 // A close request was received while translation was in progress
449 if (auth_data == authorizations_.end())
450 return;
451
452 if (!device_found) {
453 authorizations_.erase(auth_data);
454 Send(new AudioMsg_NotifyDeviceAuthorized(stream_id, false, DummyParams()));
455 return;
456 }
457
458 auth_data->second.first = true;
459 auth_data->second.second = device_info.unique_id;
460 Send(new AudioMsg_NotifyDeviceAuthorized(stream_id, true,
461 device_info.output_params));
462 }
463
327 void AudioRendererHost::OnCreateStream(int stream_id, 464 void AudioRendererHost::OnCreateStream(int stream_id,
328 int render_frame_id, 465 int render_frame_id,
329 int session_id,
330 const media::AudioParameters& params) { 466 const media::AudioParameters& params) {
331 DCHECK_CURRENTLY_ON(BrowserThread::IO); 467 DCHECK_CURRENTLY_ON(BrowserThread::IO);
468 DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream"
469 << "(stream_id=" << stream_id << ")";
332 470
333 DVLOG(1) << "AudioRendererHost@" << this 471 const auto& auth_data = authorizations_.find(stream_id);
334 << "::OnCreateStream(stream_id=" << stream_id 472
335 << ", render_frame_id=" << render_frame_id 473 // If no previous authorization requested, assume default device
336 << ", session_id=" << session_id << ")"; 474 if (auth_data == authorizations_.end()) {
337 DCHECK_GT(render_frame_id, 0); 475 DoCreateStream(stream_id, render_frame_id, params, std::string());
476 return;
477 }
478
479 CHECK(auth_data->second.first);
480 DoCreateStream(stream_id, render_frame_id, params, auth_data->second.second);
481 authorizations_.erase(auth_data);
482 }
483
484 void AudioRendererHost::DoCreateStream(int stream_id,
485 int render_frame_id,
486 const media::AudioParameters& params,
487 const std::string& device_unique_id) {
488 DCHECK_CURRENTLY_ON(BrowserThread::IO);
338 489
339 // media::AudioParameters is validated in the deserializer. 490 // media::AudioParameters is validated in the deserializer.
340 if (LookupById(stream_id) != NULL) { 491 if (LookupById(stream_id) != NULL) {
341 SendErrorMessage(stream_id); 492 SendErrorMessage(stream_id);
342 return; 493 return;
343 } 494 }
344 495
345 // Initialize the |output_device_id| to an empty string which indicates that
346 // the default device should be used. If a StreamDeviceInfo instance was found
347 // though, then we use the matched output device.
348 std::string output_device_id;
349 const StreamDeviceInfo* info = media_stream_manager_->
350 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
351 if (info)
352 output_device_id = info->device.matched_output_device_id;
353
354 // Create the shared memory and share with the renderer process. 496 // Create the shared memory and share with the renderer process.
355 uint32 shared_memory_size = AudioBus::CalculateMemorySize(params); 497 uint32 shared_memory_size = AudioBus::CalculateMemorySize(params);
356 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); 498 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
357 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { 499 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
358 SendErrorMessage(stream_id); 500 SendErrorMessage(stream_id);
359 return; 501 return;
360 } 502 }
361 503
362 scoped_ptr<AudioSyncReader> reader( 504 scoped_ptr<AudioSyncReader> reader(
363 new AudioSyncReader(shared_memory.get(), params)); 505 new AudioSyncReader(shared_memory.get(), params));
364 if (!reader->Init()) { 506 if (!reader->Init()) {
365 SendErrorMessage(stream_id); 507 SendErrorMessage(stream_id);
366 return; 508 return;
367 } 509 }
368 510
369 MediaObserver* const media_observer = 511 MediaObserver* const media_observer =
370 GetContentClient()->browser()->GetMediaObserver(); 512 GetContentClient()->browser()->GetMediaObserver();
371 if (media_observer) 513 if (media_observer)
372 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id); 514 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
373 515
374 scoped_ptr<AudioEntry> entry(new AudioEntry(this, 516 scoped_ptr<AudioEntry> entry(
375 stream_id, 517 new AudioEntry(this, stream_id, render_frame_id, params, device_unique_id,
376 render_frame_id, 518 shared_memory.Pass(), reader.Pass()));
377 params,
378 output_device_id,
379 shared_memory.Pass(),
380 reader.Pass()));
381 if (mirroring_manager_) { 519 if (mirroring_manager_) {
382 mirroring_manager_->AddDiverter( 520 mirroring_manager_->AddDiverter(
383 render_process_id_, entry->render_frame_id(), entry->controller()); 521 render_process_id_, entry->render_frame_id(), entry->controller());
384 } 522 }
385 audio_entries_.insert(std::make_pair(stream_id, entry.release())); 523 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
386 audio_log_->OnCreated(stream_id, params, output_device_id); 524
525 audio_log_->OnCreated(stream_id, params, device_unique_id);
387 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry( 526 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry(
388 stream_id, render_process_id_, render_frame_id, audio_log_.get()); 527 stream_id, render_process_id_, render_frame_id, audio_log_.get());
389 } 528 }
390 529
391 void AudioRendererHost::OnPlayStream(int stream_id) { 530 void AudioRendererHost::OnPlayStream(int stream_id) {
392 DCHECK_CURRENTLY_ON(BrowserThread::IO); 531 DCHECK_CURRENTLY_ON(BrowserThread::IO);
393 532
394 AudioEntry* entry = LookupById(stream_id); 533 AudioEntry* entry = LookupById(stream_id);
395 if (!entry) { 534 if (!entry) {
396 SendErrorMessage(stream_id); 535 SendErrorMessage(stream_id);
(...skipping 26 matching lines...) Expand all
423 return; 562 return;
424 } 563 }
425 564
426 // Make sure the volume is valid. 565 // Make sure the volume is valid.
427 if (volume < 0 || volume > 1.0) 566 if (volume < 0 || volume > 1.0)
428 return; 567 return;
429 entry->controller()->SetVolume(volume); 568 entry->controller()->SetVolume(volume);
430 audio_log_->OnSetVolume(stream_id, volume); 569 audio_log_->OnSetVolume(stream_id, volume);
431 } 570 }
432 571
433 void AudioRendererHost::OnSwitchOutputDevice(int stream_id, 572 void AudioRendererHost::OnSwitchOutputDevice(
434 int render_frame_id, 573 int stream_id,
435 const std::string& device_id, 574 int render_frame_id,
436 const GURL& security_origin, 575 const std::string& device_id,
437 int request_id) { 576 const url::Origin& security_origin) {
438 DCHECK_CURRENTLY_ON(BrowserThread::IO); 577 DCHECK_CURRENTLY_ON(BrowserThread::IO);
439 DVLOG(1) << "AudioRendererHost@" << this 578 DVLOG(1) << "AudioRendererHost@" << this
440 << "::OnSwitchOutputDevice(stream_id=" << stream_id 579 << "::OnSwitchOutputDevice(stream_id=" << stream_id
441 << ", render_frame_id=" << render_frame_id 580 << ", render_frame_id=" << render_frame_id
442 << ", device_id=" << device_id 581 << ", device_id=" << device_id
443 << ", security_origin=" << security_origin 582 << ", security_origin=" << security_origin << ")";
444 << ", request_id=" << request_id << ")"; 583 if (!LookupById(stream_id) || !IsValidDeviceId(device_id)) {
445 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL( 584 Send(new AudioMsg_NotifyOutputDeviceSwitched(
446 render_process_id_, security_origin)) { 585 stream_id, media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_INTERNAL));
447 content::bad_message::ReceivedBadMessage(this, 586 return;
448 bad_message::ARH_UNAUTHORIZED_URL); 587 }
588 GURL gurl_security_origin = ConvertToGURL(security_origin);
589 CheckOutputDeviceAccess(
590 render_frame_id, device_id, gurl_security_origin,
591 base::Bind(&AudioRendererHost::OnSwitchDeviceAuthorized, this, stream_id,
592 device_id, gurl_security_origin));
593 }
594
595 void AudioRendererHost::OnSwitchDeviceAuthorized(
596 int stream_id,
597 const std::string& device_id,
598 const GURL& gurl_security_origin,
599 bool have_access) {
600 DCHECK_CURRENTLY_ON(BrowserThread::IO);
601 if (!have_access) {
602 Send(new AudioMsg_NotifyOutputDeviceSwitched(
603 stream_id, media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_AUTHORIZED));
449 return; 604 return;
450 } 605 }
451 606
452 if (device_id.empty()) { 607 // TODO(guidou): Ensure that output parameters of the new device match the
453 DVLOG(1) << __FUNCTION__ << ": default output device requested. " 608 // output parameters of the current device to avoid shared-memory sizing
454 << "No permissions check or device translation/validation needed."; 609 // issues. http://crbug.com/526657
455 DoSwitchOutputDevice(stream_id, device_id, request_id); 610 TranslateDeviceID(device_id, gurl_security_origin,
456 } else { 611 base::Bind(&AudioRendererHost::OnSwitchDeviceIDTranslated,
457 // Check that MediaStream device permissions have been granted, 612 this, stream_id));
458 // hence the use of a MediaStreamUIProxy.
459 scoped_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create();
460
461 // Use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT
462 // because MediaStreamUIProxy::CheckAccess does not currently support
463 // MEDIA_DEVICE_AUDIO_OUTPUT.
464 // TODO(guidou): Change to MEDIA_DEVICE_AUDIO_OUTPUT when support becomes
465 // available. http://crbug.com/498675
466 ui_proxy->CheckAccess(
467 security_origin, MEDIA_DEVICE_AUDIO_CAPTURE,
468 render_process_id_, render_frame_id,
469 base::Bind(&AudioRendererHost::OutputDeviceAccessChecked, this,
470 base::Passed(&ui_proxy), stream_id, device_id,
471 security_origin, render_frame_id, request_id));
472 }
473 } 613 }
474 614
475 void AudioRendererHost::OutputDeviceAccessChecked( 615 void AudioRendererHost::OnSwitchDeviceIDTranslated(
476 scoped_ptr<MediaStreamUIProxy> ui_proxy,
477 int stream_id, 616 int stream_id,
478 const std::string& device_id, 617 bool device_found,
479 const GURL& security_origin, 618 const AudioOutputDeviceInfo& device_info) {
480 int render_frame_id,
481 int request_id,
482 bool have_access) {
483 DCHECK_CURRENTLY_ON(BrowserThread::IO); 619 DCHECK_CURRENTLY_ON(BrowserThread::IO);
484 DVLOG(1) << __FUNCTION__; 620 if (!device_found) {
485 if (!have_access) {
486 DVLOG(0) << __FUNCTION__
487 << ": Have no access to media devices. Not switching device.";
488 Send(new AudioMsg_NotifyOutputDeviceSwitched( 621 Send(new AudioMsg_NotifyOutputDeviceSwitched(
489 stream_id, request_id, 622 stream_id, media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_FOUND));
490 media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_AUTHORIZED));
491 return; 623 return;
492 } 624 }
493 625
494 scoped_refptr<base::SingleThreadTaskRunner> audio_worker_runner =
495 AudioManager::Get()->GetWorkerTaskRunner();
496 audio_worker_runner->PostTask(
497 FROM_HERE,
498 base::Bind(&AudioRendererHost::StartTranslateOutputDeviceName, this,
499 stream_id, device_id, security_origin, request_id));
500 }
501
502 void AudioRendererHost::StartTranslateOutputDeviceName(
503 int stream_id,
504 const std::string& device_id,
505 const GURL& security_origin,
506 int request_id) {
507 DCHECK(AudioManager::Get()->GetWorkerTaskRunner()->BelongsToCurrentThread());
508 DCHECK(!device_id.empty());
509 DVLOG(1) << __FUNCTION__;
510
511 media::AudioDeviceNames* device_names(new media::AudioDeviceNames);
512 AudioManager::Get()->GetAudioOutputDeviceNames(device_names);
513
514 BrowserThread::PostTask(
515 BrowserThread::IO, FROM_HERE,
516 base::Bind(&AudioRendererHost::FinishTranslateOutputDeviceName, this,
517 stream_id, device_id, security_origin, request_id,
518 base::Owned(device_names)));
519 }
520
521 void AudioRendererHost::FinishTranslateOutputDeviceName(
522 int stream_id,
523 const std::string& device_id,
524 const GURL& security_origin,
525 int request_id,
526 media::AudioDeviceNames* device_names) {
527 DCHECK_CURRENTLY_ON(BrowserThread::IO);
528 DCHECK(!device_id.empty());
529 DVLOG(1) << __FUNCTION__;
530
531 std::string raw_device_id;
532 // Process the enumeration here because |salt_callback_| can run
533 // only on the IO thread
534 for (const auto& device_name : *device_names) {
535 const std::string candidate_device_id = content::GetHMACForMediaDeviceID(
536 salt_callback_, security_origin, device_name.unique_id);
537 if (candidate_device_id == device_id) {
538 DVLOG(1) << "Requested device " << device_name.unique_id << " - "
539 << device_name.device_name;
540 raw_device_id = device_name.unique_id;
541 }
542 }
543
544 if (raw_device_id.empty()) {
545 DVLOG(1) << "Requested device " << device_id << " could not be found.";
546 Send(new AudioMsg_NotifyOutputDeviceSwitched(
547 stream_id, request_id,
548 media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_FOUND));
549 return;
550 }
551
552 DoSwitchOutputDevice(stream_id, raw_device_id, request_id);
553 }
554
555 void AudioRendererHost::DoSwitchOutputDevice(int stream_id,
556 const std::string& raw_device_id,
557 int request_id) {
558 DCHECK_CURRENTLY_ON(BrowserThread::IO);
559 DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << raw_device_id << ", "
560 << request_id << ")";
561 AudioEntry* entry = LookupById(stream_id); 626 AudioEntry* entry = LookupById(stream_id);
562 if (!entry) { 627 if (!entry) {
563 Send(new AudioMsg_NotifyOutputDeviceSwitched( 628 Send(new AudioMsg_NotifyOutputDeviceSwitched(
564 stream_id, request_id, 629 stream_id, media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_INTERNAL));
565 media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_OBSOLETE));
566 return; 630 return;
567 } 631 }
568 632
569 entry->controller()->SwitchOutputDevice( 633 entry->controller()->SwitchOutputDevice(
570 raw_device_id, base::Bind(&AudioRendererHost::DoOutputDeviceSwitched, 634 device_info.unique_id,
571 this, stream_id, request_id)); 635 base::Bind(&AudioRendererHost::OnDeviceSwitched, this, stream_id));
572 audio_log_->OnSwitchOutputDevice(entry->stream_id(), raw_device_id); 636 audio_log_->OnSwitchOutputDevice(entry->stream_id(), device_info.unique_id);
573 } 637 }
574 638
575 void AudioRendererHost::DoOutputDeviceSwitched(int stream_id, int request_id) { 639 void AudioRendererHost::OnDeviceSwitched(int stream_id) {
576 DCHECK_CURRENTLY_ON(BrowserThread::IO); 640 DCHECK_CURRENTLY_ON(BrowserThread::IO);
577 DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << request_id << ")";
578 Send(new AudioMsg_NotifyOutputDeviceSwitched( 641 Send(new AudioMsg_NotifyOutputDeviceSwitched(
579 stream_id, request_id, media::SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS)); 642 stream_id, media::SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS));
580 } 643 }
581 644
582 void AudioRendererHost::SendErrorMessage(int stream_id) { 645 void AudioRendererHost::SendErrorMessage(int stream_id) {
583 Send(new AudioMsg_NotifyStreamStateChanged( 646 Send(new AudioMsg_NotifyStreamStateChanged(
584 stream_id, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)); 647 stream_id, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR));
585 } 648 }
586 649
587 void AudioRendererHost::OnCloseStream(int stream_id) { 650 void AudioRendererHost::OnCloseStream(int stream_id) {
588 DCHECK_CURRENTLY_ON(BrowserThread::IO); 651 DCHECK_CURRENTLY_ON(BrowserThread::IO);
652 authorizations_.erase(stream_id);
589 653
590 // Prevent oustanding callbacks from attempting to close/delete the same 654 // Prevent oustanding callbacks from attempting to close/delete the same
591 // AudioEntry twice. 655 // AudioEntry twice.
592 AudioEntryMap::iterator i = audio_entries_.find(stream_id); 656 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
593 if (i == audio_entries_.end()) 657 if (i == audio_entries_.end())
594 return; 658 return;
595 scoped_ptr<AudioEntry> entry(i->second); 659 scoped_ptr<AudioEntry> entry(i->second);
596 audio_entries_.erase(i); 660 audio_entries_.erase(i);
597 661
598 media::AudioOutputController* const controller = entry->controller(); 662 media::AudioOutputController* const controller = entry->controller();
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
676 for (AudioEntryMap::const_iterator it = audio_entries_.begin(); 740 for (AudioEntryMap::const_iterator it = audio_entries_.begin();
677 it != audio_entries_.end(); 741 it != audio_entries_.end();
678 ++it) { 742 ++it) {
679 AudioEntry* entry = it->second; 743 AudioEntry* entry = it->second;
680 if (entry->render_frame_id() == render_frame_id && entry->playing()) 744 if (entry->render_frame_id() == render_frame_id && entry->playing())
681 return true; 745 return true;
682 } 746 }
683 return false; 747 return false;
684 } 748 }
685 749
750 void AudioRendererHost::CheckOutputDeviceAccess(
751 int render_frame_id,
752 const std::string& device_id,
753 const GURL& gurl_security_origin,
754 const OutputDeviceAccessCB& callback) {
755 DCHECK_CURRENTLY_ON(BrowserThread::IO);
756
757 // Skip origin check in requests for the default device with an empty
758 // security origin.
759 bool skip_origin_check = gurl_security_origin.is_empty() && device_id.empty();
760 if (!skip_origin_check &&
761 !ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
762 render_process_id_, gurl_security_origin)) {
763 content::bad_message::ReceivedBadMessage(this,
764 bad_message::ARH_UNAUTHORIZED_URL);
765 return;
766 }
767
768 if (device_id.empty()) {
769 callback.Run(true);
770 } else {
771 // Check that MediaStream device permissions have been granted,
772 // hence the use of a MediaStreamUIProxy.
773 scoped_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create();
774
775 // Use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT
776 // because MediaStreamUIProxy::CheckAccess does not currently support
777 // MEDIA_DEVICE_AUDIO_OUTPUT.
778 // TODO(guidou): Change to MEDIA_DEVICE_AUDIO_OUTPUT when support becomes
779 // available. http://crbug.com/498675
780 ui_proxy->CheckAccess(gurl_security_origin, MEDIA_DEVICE_AUDIO_CAPTURE,
781 render_process_id_, render_frame_id,
782 base::Bind(&AudioRendererHost::AccessChecked, this,
783 base::Passed(&ui_proxy), callback));
784 }
785 }
786
787 void AudioRendererHost::AccessChecked(scoped_ptr<MediaStreamUIProxy> ui_proxy,
788 const OutputDeviceAccessCB& callback,
789 bool have_access) {
790 DCHECK_CURRENTLY_ON(BrowserThread::IO);
791 callback.Run(have_access);
792 }
793
794 void AudioRendererHost::TranslateDeviceID(const std::string& device_id,
795 const GURL& gurl_security_origin,
796 const OutputDeviceInfoCB& callback) {
797 DCHECK_CURRENTLY_ON(BrowserThread::IO);
798 AudioOutputDeviceEnumerator* enumerator =
799 media_stream_manager_->audio_output_device_enumerator();
800 enumerator->Enumerate(base::Bind(&AudioRendererHost::FinishTranslateDeviceID,
801 this, device_id, gurl_security_origin,
802 callback));
803 }
804
805 void AudioRendererHost::FinishTranslateDeviceID(
806 const std::string& device_id,
807 const GURL& security_origin,
808 const OutputDeviceInfoCB& callback,
809 const AudioOutputDeviceEnumeration& device_infos) {
810 DCHECK_CURRENTLY_ON(BrowserThread::IO);
811 bool use_default_device = device_id.empty() && security_origin.is_empty();
812 for (const AudioOutputDeviceInfo& device_info : device_infos) {
813 if (use_default_device) {
814 if (device_info.unique_id == media::AudioManagerBase::kDefaultDeviceId) {
815 callback.Run(true, device_info);
816 return;
817 }
818 } else if (content::DoesMediaDeviceIDMatchHMAC(salt_callback_,
819 security_origin, device_id,
820 device_info.unique_id)) {
821 callback.Run(true, device_info);
822 return;
823 }
824 }
825 DCHECK(!use_default_device); // Default device must always be found
826 AudioOutputDeviceInfo device_info = {std::string(), std::string(),
827 DummyParams()};
828 callback.Run(false, device_info);
829 }
830
831 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) {
832 DCHECK_CURRENTLY_ON(BrowserThread::IO);
833 const auto& i = authorizations_.find(stream_id);
834 return i != authorizations_.end();
835 }
836
686 } // namespace content 837 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698