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

Unified Diff: content/browser/renderer_host/media/audio_output_authorization_handler.cc

Issue 2424163004: Factor out authorization from AudioRendererHost. (Closed)
Patch Set: . Created 4 years, 2 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/renderer_host/media/audio_output_authorization_handler.cc
diff --git a/content/browser/renderer_host/media/audio_output_authorization_handler.cc b/content/browser/renderer_host/media/audio_output_authorization_handler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..269ea171ae9b6d8163e35fa41bc4548b5e2885f3
--- /dev/null
+++ b/content/browser/renderer_host/media/audio_output_authorization_handler.cc
@@ -0,0 +1,230 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/media/audio_output_authorization_handler.h"
+
+#include "base/task_runner_util.h"
+#include "content/browser/renderer_host/media/audio_input_device_manager.h"
+#include "content/public/browser/media_device_id.h"
+#include "media/base/limits.h"
+
+namespace {
+
+bool IsValidDeviceId(const std::string& device_id) {
+ static const std::string::size_type kValidLength = 64;
+
+ if (media::AudioDeviceDescription::IsDefaultDevice(device_id) ||
+ device_id == media::AudioDeviceDescription::kCommunicationsDeviceId) {
+ return true;
+ }
+
+ if (device_id.length() != kValidLength)
+ return false;
+
+ for (const char& c : device_id) {
+ if ((c < 'a' || c > 'f') && (c < '0' || c > '9'))
+ return false;
+ }
+
+ return true;
+}
+
+void MaybeFixAudioParameters(media::AudioParameters* params) {
+ // If the number of output channels is greater than the maximum, use the
+ // maximum allowed value. Hardware channels are ignored upstream, so it is
+ // better to report a valid value if this is the only problem.
+ if (params->channels() > media::limits::kMaxChannels)
+ params->set_channels_for_discrete(media::limits::kMaxChannels);
+
+ // If hardware parameters are still invalid, use dummy parameters with
+ // fake audio path and let the client handle the error.
+ if (!params->IsValid())
+ *params = media::AudioParameters::UnavailableDeviceParams();
+}
+
+media::AudioParameters GetDeviceParametersOnDeviceThread(
+ const std::string& unique_id) {
+ media::AudioManager* audio_manager = media::AudioManager::Get();
+ DCHECK(audio_manager->GetTaskRunner()->BelongsToCurrentThread());
+
+ if (media::AudioDeviceDescription::IsDefaultDevice(unique_id))
+ return audio_manager->GetDefaultOutputStreamParameters();
+ return audio_manager->GetOutputStreamParameters(unique_id);
+}
+
+} // namespace
+
+namespace content {
+
+AudioOutputAuthorizationHandler::AudioOutputAuthorizationHandler(
o1ka 2016/10/28 13:18:40 I guess we need some unit tests for it?
Max Morin 2016/11/01 11:26:20 Done.
+ MediaStreamManager* media_stream_manager,
+ int render_process_id,
+ const std::string& salt)
+ : media_stream_manager_(media_stream_manager),
+ render_process_id_(render_process_id),
+ salt_(salt),
+ bad_message_handler_(),
+ weak_factory(this) {
+ DCHECK(media_stream_manager_);
+}
+
+AudioOutputAuthorizationHandler::~AudioOutputAuthorizationHandler() = default;
+
+void AudioOutputAuthorizationHandler::RequestDeviceAuthorization(
+ int render_frame_id,
+ int session_id,
+ const std::string& device_id,
+ const url::Origin& security_origin,
+ AuthorizationCompletedCallback cb) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!IsValidDeviceId(device_id)) {
+ cb.Run(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND,
+ media::AudioParameters::UnavailableDeviceParams(), std::string());
+ return;
+ }
+
+ // If |session_id| should be used for output device selection and such output
+ // device is found, reuse the input device permissions.
+ if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id,
+ device_id)) {
+ const StreamDeviceInfo* info =
+ media_stream_manager_->audio_input_device_manager()
+ ->GetOpenedDeviceInfoById(session_id);
+ if (info) {
+ media::AudioParameters output_params(
+ media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ static_cast<media::ChannelLayout>(
+ info->device.matched_output.channel_layout),
+ info->device.matched_output.sample_rate, 16,
+ info->device.matched_output.frames_per_buffer);
+ output_params.set_effects(info->device.matched_output.effects);
+ MaybeFixAudioParameters(&output_params);
+
+ cb.Run(media::OUTPUT_DEVICE_STATUS_OK, output_params,
+ GetHMACForMediaDeviceID(salt_, security_origin,
+ info->device.matched_output_device_id));
+ return;
+ }
+ }
+
+ CheckOutputDeviceAccess(std::move(cb), render_frame_id, device_id,
+ security_origin);
+}
+
+void AudioOutputAuthorizationHandler::CheckOutputDeviceAccess(
+ AuthorizationCompletedCallback cb,
+ int render_frame_id,
+ const std::string& device_id,
+ const url::Origin& security_origin) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // Check security origin if nondefault device is requested.
+ // Ignore check for default device, which is always authorized.
+ if (!media::AudioDeviceDescription::IsDefaultDevice(device_id) &&
+ !MediaStreamManager::IsOriginAllowed(render_process_id_,
+ security_origin)) {
+ if (!bad_message_handler_.is_null())
+ bad_message_handler_.Run(bad_message::ARH_UNAUTHORIZED_URL);
Guido Urdaneta 2016/10/28 15:17:28 why not kill the renderer process immediately here
Max Morin 2016/11/01 11:26:20 Sure, I'll just get rid of the bad message handler
+ return;
+ }
+
+ if (media::AudioDeviceDescription::IsDefaultDevice(device_id)) {
+ AccessChecked(std::move(cb), nullptr, device_id, security_origin, true);
+ } else {
+ // Check that MediaStream device permissions have been granted,
+ // hence the use of a MediaStreamUIProxy.
+ std::unique_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create();
+
+ // Use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT
+ // because MediaStreamUIProxy::CheckAccess does not currently support
+ // MEDIA_DEVICE_AUDIO_OUTPUT.
+ // TODO(guidou): Change to MEDIA_DEVICE_AUDIO_OUTPUT when support becomes
+ // available. http://crbug.com/498675
+ ui_proxy->CheckAccess(
+ security_origin, MEDIA_DEVICE_AUDIO_CAPTURE, render_process_id_,
+ render_frame_id,
+ base::Bind(&AudioOutputAuthorizationHandler::AccessChecked,
+ weak_factory.GetWeakPtr(), std::move(cb),
+ base::Passed(&ui_proxy), device_id, security_origin));
+ }
+}
+
+void AudioOutputAuthorizationHandler::AccessChecked(
+ AuthorizationCompletedCallback cb,
+ std::unique_ptr<MediaStreamUIProxy> ui_proxy,
+ const std::string& device_id,
+ const url::Origin& security_origin,
+ bool have_access) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!have_access) {
+ cb.Run(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
+ media::AudioParameters::UnavailableDeviceParams(), std::string());
+ return;
+ }
+
+ // For default device, read output parameters directly. Nondefault devices
+ // require translation first.
+ if (media::AudioDeviceDescription::IsDefaultDevice(device_id)) {
+ base::PostTaskAndReplyWithResult(
+ media::AudioManager::Get()->GetTaskRunner(), FROM_HERE,
+ base::Bind(&GetDeviceParametersOnDeviceThread,
+ media::AudioDeviceDescription::kDefaultDeviceId),
+ base::Bind(&AudioOutputAuthorizationHandler::DeviceParametersReceived,
+ weak_factory.GetWeakPtr(), std::move(cb), true,
+ media::AudioDeviceDescription::kDefaultDeviceId));
+ } else {
+ MediaDevicesManager::BoolDeviceTypes devices_to_enumerate;
+ devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT] = true;
+ media_stream_manager_->media_devices_manager()->EnumerateDevices(
+ devices_to_enumerate,
+ base::Bind(&AudioOutputAuthorizationHandler::TranslateDeviceID,
+ weak_factory.GetWeakPtr(), std::move(cb), device_id,
+ security_origin));
+ }
+}
+
+void AudioOutputAuthorizationHandler::TranslateDeviceID(
+ AuthorizationCompletedCallback cb,
+ const std::string& device_id,
+ const url::Origin& security_origin,
+ const MediaDeviceEnumeration& enumeration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!media::AudioDeviceDescription::IsDefaultDevice(device_id));
+ for (const MediaDeviceInfo& device_info :
+ enumeration[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT]) {
+ if (content::DoesMediaDeviceIDMatchHMAC(salt_, security_origin, device_id,
+ device_info.device_id)) {
+ base::PostTaskAndReplyWithResult(
+ media::AudioManager::Get()->GetTaskRunner(), FROM_HERE,
+ base::Bind(&GetDeviceParametersOnDeviceThread, device_info.device_id),
+ base::Bind(&AudioOutputAuthorizationHandler::DeviceParametersReceived,
+ weak_factory.GetWeakPtr(), std::move(cb), true,
+ device_info.device_id));
+ return;
+ }
+ }
+ DeviceParametersReceived(std::move(cb), false, std::string(),
+ media::AudioParameters::UnavailableDeviceParams());
+}
+
+void AudioOutputAuthorizationHandler::DeviceParametersReceived(
+ AuthorizationCompletedCallback cb,
+ bool device_found,
+ const std::string& unique_id,
+ media::AudioParameters output_params) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!device_found) {
+ cb.Run(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND,
+ media::AudioParameters::UnavailableDeviceParams(), "");
+ return;
+ }
+
+ MaybeFixAudioParameters(&output_params);
+ cb.Run(media::OUTPUT_DEVICE_STATUS_OK, output_params, unique_id);
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698