| 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" |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 return false; | 68 return false; |
| 69 | 69 |
| 70 for (const char& c : device_id) { | 70 for (const char& c : device_id) { |
| 71 if ((c < 'a' || c > 'f') && (c < '0' || c > '9')) | 71 if ((c < 'a' || c > 'f') && (c < '0' || c > '9')) |
| 72 return false; | 72 return false; |
| 73 } | 73 } |
| 74 | 74 |
| 75 return true; | 75 return true; |
| 76 } | 76 } |
| 77 | 77 |
| 78 AudioOutputDeviceInfo GetDefaultDeviceInfoOnDeviceThread( | |
| 79 media::AudioManager* audio_manager) { | |
| 80 DCHECK(audio_manager->GetTaskRunner()->BelongsToCurrentThread()); | |
| 81 AudioOutputDeviceInfo default_device_info = { | |
| 82 media::AudioDeviceDescription::kDefaultDeviceId, | |
| 83 media::AudioDeviceDescription::GetDefaultDeviceName(), | |
| 84 audio_manager->GetGroupIDOutput( | |
| 85 media::AudioDeviceDescription::kDefaultDeviceId), | |
| 86 audio_manager->GetDefaultOutputStreamParameters()}; | |
| 87 | |
| 88 return default_device_info; | |
| 89 } | |
| 90 | |
| 91 void NotifyRenderProcessHostThatAudioStateChanged(int render_process_id) { | 78 void NotifyRenderProcessHostThatAudioStateChanged(int render_process_id) { |
| 92 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 79 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 93 | 80 |
| 94 RenderProcessHost* render_process_host = | 81 RenderProcessHost* render_process_host = |
| 95 RenderProcessHost::FromID(render_process_id); | 82 RenderProcessHost::FromID(render_process_id); |
| 96 | 83 |
| 97 if (render_process_host) | 84 if (render_process_host) |
| 98 render_process_host->AudioStateChanged(); | 85 render_process_host->AudioStateChanged(); |
| 99 } | 86 } |
| 100 | 87 |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 484 Send(new AudioMsg_NotifyDeviceAuthorized( | 471 Send(new AudioMsg_NotifyDeviceAuthorized( |
| 485 stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, | 472 stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, |
| 486 GetHMACForMediaDeviceID(salt_, security_origin, | 473 GetHMACForMediaDeviceID(salt_, security_origin, |
| 487 info->device.matched_output_device_id))); | 474 info->device.matched_output_device_id))); |
| 488 return; | 475 return; |
| 489 } | 476 } |
| 490 } | 477 } |
| 491 | 478 |
| 492 authorizations_.insert( | 479 authorizations_.insert( |
| 493 MakeAuthorizationData(stream_id, false, std::string())); | 480 MakeAuthorizationData(stream_id, false, std::string())); |
| 494 CheckOutputDeviceAccess( | 481 CheckOutputDeviceAccess(render_frame_id, device_id, security_origin, |
| 495 render_frame_id, device_id, security_origin, | 482 stream_id, auth_start_time); |
| 496 base::Bind(&AudioRendererHost::OnDeviceAuthorized, this, stream_id, | |
| 497 device_id, security_origin, auth_start_time)); | |
| 498 } | |
| 499 | |
| 500 void AudioRendererHost::OnDeviceAuthorized(int stream_id, | |
| 501 const std::string& device_id, | |
| 502 const url::Origin& security_origin, | |
| 503 base::TimeTicks auth_start_time, | |
| 504 bool have_access) { | |
| 505 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 506 const auto& auth_data = authorizations_.find(stream_id); | |
| 507 | |
| 508 // A close request was received while access check was in progress. | |
| 509 if (auth_data == authorizations_.end()) { | |
| 510 UMALogDeviceAuthorizationTime(auth_start_time); | |
| 511 return; | |
| 512 } | |
| 513 | |
| 514 if (!have_access) { | |
| 515 authorizations_.erase(auth_data); | |
| 516 UMALogDeviceAuthorizationTime(auth_start_time); | |
| 517 Send(new AudioMsg_NotifyDeviceAuthorized( | |
| 518 stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED, | |
| 519 media::AudioParameters::UnavailableDeviceParams(), std::string())); | |
| 520 return; | |
| 521 } | |
| 522 | |
| 523 // If enumerator caching is disabled, avoid the enumeration if the default | |
| 524 // device is requested, since no device ID translation is needed. | |
| 525 // If enumerator caching is enabled, it is better to use its cache, even | |
| 526 // for the default device. | |
| 527 if (media::AudioDeviceDescription::IsDefaultDevice(device_id) && | |
| 528 !media_stream_manager_->audio_output_device_enumerator() | |
| 529 ->IsCacheEnabled()) { | |
| 530 base::PostTaskAndReplyWithResult( | |
| 531 audio_manager_->GetTaskRunner(), FROM_HERE, | |
| 532 base::Bind(&GetDefaultDeviceInfoOnDeviceThread, audio_manager_), | |
| 533 base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this, stream_id, | |
| 534 auth_start_time, true)); | |
| 535 } else { | |
| 536 media_stream_manager_->audio_output_device_enumerator()->Enumerate( | |
| 537 base::Bind(&AudioRendererHost::TranslateDeviceID, this, device_id, | |
| 538 security_origin, | |
| 539 base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this, | |
| 540 stream_id, auth_start_time))); | |
| 541 } | |
| 542 } | |
| 543 | |
| 544 void AudioRendererHost::OnDeviceIDTranslated( | |
| 545 int stream_id, | |
| 546 base::TimeTicks auth_start_time, | |
| 547 bool device_found, | |
| 548 const AudioOutputDeviceInfo& device_info) { | |
| 549 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 550 const auto& auth_data = authorizations_.find(stream_id); | |
| 551 | |
| 552 // A close request was received while translation was in progress | |
| 553 if (auth_data == authorizations_.end()) { | |
| 554 UMALogDeviceAuthorizationTime(auth_start_time); | |
| 555 return; | |
| 556 } | |
| 557 | |
| 558 if (!device_found) { | |
| 559 authorizations_.erase(auth_data); | |
| 560 UMALogDeviceAuthorizationTime(auth_start_time); | |
| 561 Send(new AudioMsg_NotifyDeviceAuthorized( | |
| 562 stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, | |
| 563 media::AudioParameters::UnavailableDeviceParams(), std::string())); | |
| 564 return; | |
| 565 } | |
| 566 | |
| 567 auth_data->second.first = true; | |
| 568 auth_data->second.second = device_info.unique_id; | |
| 569 | |
| 570 media::AudioParameters output_params = device_info.output_params; | |
| 571 MaybeFixAudioParameters(&output_params); | |
| 572 UMALogDeviceAuthorizationTime(auth_start_time); | |
| 573 Send(new AudioMsg_NotifyDeviceAuthorized( | |
| 574 stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, std::string())); | |
| 575 } | 483 } |
| 576 | 484 |
| 577 void AudioRendererHost::OnCreateStream(int stream_id, | 485 void AudioRendererHost::OnCreateStream(int stream_id, |
| 578 int render_frame_id, | 486 int render_frame_id, |
| 579 const media::AudioParameters& params) { | 487 const media::AudioParameters& params) { |
| 580 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 488 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 581 DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream" | 489 DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream" |
| 582 << "(stream_id=" << stream_id << ")"; | 490 << "(stream_id=" << stream_id << ")"; |
| 583 | 491 |
| 584 // Determine whether to use the device_unique_id from an authorization, or an | 492 // Determine whether to use the device_unique_id from an authorization, or an |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 783 } | 691 } |
| 784 | 692 |
| 785 bool AudioRendererHost::HasActiveAudio() { | 693 bool AudioRendererHost::HasActiveAudio() { |
| 786 return !base::AtomicRefCountIsZero(&num_playing_streams_); | 694 return !base::AtomicRefCountIsZero(&num_playing_streams_); |
| 787 } | 695 } |
| 788 | 696 |
| 789 void AudioRendererHost::CheckOutputDeviceAccess( | 697 void AudioRendererHost::CheckOutputDeviceAccess( |
| 790 int render_frame_id, | 698 int render_frame_id, |
| 791 const std::string& device_id, | 699 const std::string& device_id, |
| 792 const url::Origin& security_origin, | 700 const url::Origin& security_origin, |
| 793 const OutputDeviceAccessCB& callback) { | 701 int stream_id, |
| 702 base::TimeTicks auth_start_time) { |
| 794 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 703 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 795 | 704 |
| 796 // Check security origin if nondefault device is requested. | 705 // Check security origin if nondefault device is requested. |
| 797 // Ignore check for default device, which is always authorized. | 706 // Ignore check for default device, which is always authorized. |
| 798 if (!media::AudioDeviceDescription::IsDefaultDevice(device_id) && | 707 if (!media::AudioDeviceDescription::IsDefaultDevice(device_id) && |
| 799 !MediaStreamManager::IsOriginAllowed(render_process_id_, | 708 !MediaStreamManager::IsOriginAllowed(render_process_id_, |
| 800 security_origin)) { | 709 security_origin)) { |
| 801 content::bad_message::ReceivedBadMessage(this, | 710 content::bad_message::ReceivedBadMessage(this, |
| 802 bad_message::ARH_UNAUTHORIZED_URL); | 711 bad_message::ARH_UNAUTHORIZED_URL); |
| 803 return; | 712 return; |
| 804 } | 713 } |
| 805 | 714 |
| 806 if (device_id.empty()) { | 715 if (media::AudioDeviceDescription::IsDefaultDevice(device_id)) { |
| 807 callback.Run(true); | 716 AccessChecked(nullptr, device_id, security_origin, stream_id, |
| 717 auth_start_time, true); |
| 808 } else { | 718 } else { |
| 809 // Check that MediaStream device permissions have been granted, | 719 // Check that MediaStream device permissions have been granted, |
| 810 // hence the use of a MediaStreamUIProxy. | 720 // hence the use of a MediaStreamUIProxy. |
| 811 std::unique_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create(); | 721 std::unique_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create(); |
| 812 | 722 |
| 813 // Use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT | 723 // Use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT |
| 814 // because MediaStreamUIProxy::CheckAccess does not currently support | 724 // because MediaStreamUIProxy::CheckAccess does not currently support |
| 815 // MEDIA_DEVICE_AUDIO_OUTPUT. | 725 // MEDIA_DEVICE_AUDIO_OUTPUT. |
| 816 // TODO(guidou): Change to MEDIA_DEVICE_AUDIO_OUTPUT when support becomes | 726 // TODO(guidou): Change to MEDIA_DEVICE_AUDIO_OUTPUT when support becomes |
| 817 // available. http://crbug.com/498675 | 727 // available. http://crbug.com/498675 |
| 818 ui_proxy->CheckAccess(security_origin, MEDIA_DEVICE_AUDIO_CAPTURE, | 728 ui_proxy->CheckAccess( |
| 819 render_process_id_, render_frame_id, | 729 security_origin, MEDIA_DEVICE_AUDIO_CAPTURE, render_process_id_, |
| 820 base::Bind(&AudioRendererHost::AccessChecked, this, | 730 render_frame_id, |
| 821 base::Passed(&ui_proxy), callback)); | 731 base::Bind(&AudioRendererHost::AccessChecked, this, |
| 732 base::Passed(&ui_proxy), device_id, security_origin, |
| 733 stream_id, auth_start_time)); |
| 822 } | 734 } |
| 823 } | 735 } |
| 824 | 736 |
| 825 void AudioRendererHost::AccessChecked( | 737 void AudioRendererHost::AccessChecked( |
| 826 std::unique_ptr<MediaStreamUIProxy> ui_proxy, | 738 std::unique_ptr<MediaStreamUIProxy> ui_proxy, |
| 827 const OutputDeviceAccessCB& callback, | 739 const std::string& device_id, |
| 740 const url::Origin& security_origin, |
| 741 int stream_id, |
| 742 base::TimeTicks auth_start_time, |
| 828 bool have_access) { | 743 bool have_access) { |
| 829 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 744 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 830 callback.Run(have_access); | 745 |
| 746 const auto& auth_data = authorizations_.find(stream_id); |
| 747 if (auth_data == authorizations_.end()) { |
| 748 // A close request was received while access check was in progress. |
| 749 UMALogDeviceAuthorizationTime(auth_start_time); |
| 750 return; |
| 751 } |
| 752 |
| 753 if (!have_access) { |
| 754 authorizations_.erase(auth_data); |
| 755 UMALogDeviceAuthorizationTime(auth_start_time); |
| 756 Send(new AudioMsg_NotifyDeviceAuthorized( |
| 757 stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED, |
| 758 media::AudioParameters::UnavailableDeviceParams(), std::string())); |
| 759 return; |
| 760 } |
| 761 |
| 762 // For default device, read output parameters directly. Nondefault devices |
| 763 // require translation first. |
| 764 if (media::AudioDeviceDescription::IsDefaultDevice(device_id)) { |
| 765 base::PostTaskAndReplyWithResult( |
| 766 audio_manager_->GetTaskRunner(), FROM_HERE, |
| 767 base::Bind(&AudioRendererHost::GetDeviceParametersOnDeviceThread, this, |
| 768 media::AudioDeviceDescription::kDefaultDeviceId), |
| 769 base::Bind(&AudioRendererHost::DeviceParametersReceived, this, |
| 770 stream_id, auth_start_time, true, |
| 771 media::AudioDeviceDescription::kDefaultDeviceId)); |
| 772 } else { |
| 773 MediaDevicesManager::BoolDeviceTypes devices_to_enumerate; |
| 774 devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT] = true; |
| 775 media_stream_manager_->media_devices_manager()->EnumerateDevices( |
| 776 devices_to_enumerate, |
| 777 base::Bind(&AudioRendererHost::TranslateDeviceID, this, device_id, |
| 778 security_origin, stream_id, auth_start_time)); |
| 779 } |
| 831 } | 780 } |
| 832 | 781 |
| 833 void AudioRendererHost::TranslateDeviceID( | 782 void AudioRendererHost::TranslateDeviceID( |
| 834 const std::string& device_id, | 783 const std::string& device_id, |
| 835 const url::Origin& security_origin, | 784 const url::Origin& security_origin, |
| 836 const OutputDeviceInfoCB& callback, | 785 int stream_id, |
| 837 const AudioOutputDeviceEnumeration& enumeration) { | 786 base::TimeTicks auth_start_time, |
| 787 const MediaDeviceEnumeration& enumeration) { |
| 838 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 788 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 839 for (const AudioOutputDeviceInfo& device_info : enumeration.devices) { | 789 DCHECK(!media::AudioDeviceDescription::IsDefaultDevice(device_id)); |
| 840 if (device_id.empty()) { | 790 for (const MediaDeviceInfo& device_info : |
| 841 if (device_info.unique_id == | 791 enumeration[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT]) { |
| 842 media::AudioDeviceDescription::kDefaultDeviceId) { | 792 if (content::DoesMediaDeviceIDMatchHMAC(salt_, security_origin, device_id, |
| 843 callback.Run(true, device_info); | 793 device_info.device_id)) { |
| 844 return; | 794 base::PostTaskAndReplyWithResult( |
| 845 } | 795 audio_manager_->GetTaskRunner(), FROM_HERE, |
| 846 } else if (content::DoesMediaDeviceIDMatchHMAC( | 796 base::Bind(&AudioRendererHost::GetDeviceParametersOnDeviceThread, |
| 847 salt_, security_origin, device_id, device_info.unique_id)) { | 797 this, device_info.device_id), |
| 848 callback.Run(true, device_info); | 798 base::Bind(&AudioRendererHost::DeviceParametersReceived, this, |
| 799 stream_id, auth_start_time, true, device_info.device_id)); |
| 849 return; | 800 return; |
| 850 } | 801 } |
| 851 } | 802 } |
| 852 DCHECK(!device_id.empty()); // Default device must always be found | 803 DeviceParametersReceived(stream_id, auth_start_time, false, std::string(), |
| 853 AudioOutputDeviceInfo device_info = { | 804 media::AudioParameters::UnavailableDeviceParams()); |
| 854 std::string(), std::string(), std::string(), | 805 } |
| 855 media::AudioParameters::UnavailableDeviceParams()}; | 806 |
| 856 callback.Run(false, device_info); | 807 media::AudioParameters AudioRendererHost::GetDeviceParametersOnDeviceThread( |
| 808 const std::string& unique_id) { |
| 809 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); |
| 810 |
| 811 if (media::AudioDeviceDescription::IsDefaultDevice(unique_id)) |
| 812 return audio_manager_->GetDefaultOutputStreamParameters(); |
| 813 |
| 814 return audio_manager_->GetOutputStreamParameters(unique_id); |
| 815 } |
| 816 |
| 817 void AudioRendererHost::DeviceParametersReceived( |
| 818 int stream_id, |
| 819 base::TimeTicks auth_start_time, |
| 820 bool device_found, |
| 821 const std::string& unique_id, |
| 822 const media::AudioParameters& output_params) { |
| 823 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 824 const auto& auth_data = authorizations_.find(stream_id); |
| 825 |
| 826 // A close request was received while translation was in progress |
| 827 if (auth_data == authorizations_.end()) { |
| 828 UMALogDeviceAuthorizationTime(auth_start_time); |
| 829 return; |
| 830 } |
| 831 |
| 832 if (!device_found) { |
| 833 authorizations_.erase(auth_data); |
| 834 UMALogDeviceAuthorizationTime(auth_start_time); |
| 835 Send(new AudioMsg_NotifyDeviceAuthorized( |
| 836 stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, |
| 837 media::AudioParameters::UnavailableDeviceParams(), |
| 838 std::string() /* matched_device_id */)); |
| 839 return; |
| 840 } |
| 841 |
| 842 auth_data->second.first = true; |
| 843 auth_data->second.second = unique_id; |
| 844 |
| 845 media::AudioParameters params = std::move(output_params); |
| 846 MaybeFixAudioParameters(¶ms); |
| 847 UMALogDeviceAuthorizationTime(auth_start_time); |
| 848 Send(new AudioMsg_NotifyDeviceAuthorized( |
| 849 stream_id, media::OUTPUT_DEVICE_STATUS_OK, params, |
| 850 std::string() /* matched_device_id */)); |
| 857 } | 851 } |
| 858 | 852 |
| 859 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { | 853 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { |
| 860 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 854 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 861 const auto& i = authorizations_.find(stream_id); | 855 const auto& i = authorizations_.find(stream_id); |
| 862 return i != authorizations_.end(); | 856 return i != authorizations_.end(); |
| 863 } | 857 } |
| 864 | 858 |
| 865 } // namespace content | 859 } // namespace content |
| OLD | NEW |