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

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

Issue 2424163004: Factor out authorization from AudioRendererHost. (Closed)
Patch Set: const& Created 4 years, 1 month 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..3bc765fdc86ec5611fa73f2a2e0c39320abae5fb
--- /dev/null
+++ b/content/browser/renderer_host/media/audio_output_authorization_handler.cc
@@ -0,0 +1,213 @@
+// 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/bad_message.h"
+#include "content/browser/renderer_host/media/audio_input_device_manager.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/media_device_id.h"
+#include "media/base/limits.h"
+
+namespace {
+
+media::AudioParameters TryToFixAudioParameters(
+ const media::AudioParameters& params) {
+ DCHECK(!params.IsValid());
+ media::AudioParameters params_copy(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) {
+ DCHECK(params.channel_layout() == media::CHANNEL_LAYOUT_DISCRETE);
+ params_copy.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.
+ return params_copy.IsValid()
+ ? params_copy
+ : media::AudioParameters::UnavailableDeviceParams();
+}
+
+media::AudioParameters GetDeviceParametersOnDeviceThread(
+ const std::string& unique_id) {
+ media::AudioManager* audio_manager = media::AudioManager::Get();
+ DCHECK(audio_manager->GetTaskRunner()->BelongsToCurrentThread());
+
+ return media::AudioDeviceDescription::IsDefaultDevice(unique_id)
+ ? audio_manager->GetDefaultOutputStreamParameters()
+ : audio_manager->GetOutputStreamParameters(unique_id);
+}
+
+} // namespace
+
+namespace content {
+
+AudioOutputAuthorizationHandler::AudioOutputAuthorizationHandler(
+ MediaStreamManager* media_stream_manager,
+ int render_process_id,
+ const std::string& salt)
+ : media_stream_manager_(media_stream_manager),
+ permission_checker_(new MediaDevicesPermissionChecker()),
+ render_process_id_(render_process_id),
+ salt_(salt),
+ weak_factory_(this) {
+ DCHECK(media_stream_manager_);
+}
+
+void AudioOutputAuthorizationHandler::OverridePermissionsForTesting(
+ bool override_value) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ permission_checker_.reset(new MediaDevicesPermissionChecker(override_value));
+}
+
+AudioOutputAuthorizationHandler::~AudioOutputAuthorizationHandler() {
+ // |weak_factory| is not thread safe. Make sure it's destructed on the
+ // right thread.
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+}
+
+void AudioOutputAuthorizationHandler::RequestDeviceAuthorization(
+ int render_frame_id,
+ int session_id,
+ const std::string& device_id,
+ const url::Origin& security_origin,
+ AuthorizationCompletedCallback cb) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!IsValidDeviceId(device_id)) {
+ bad_message::ReceivedBadMessage(render_process_id_,
+ bad_message::AOAH_NONSENSE_DEVICE_ID);
+ return;
+ }
+
+ // If |session_id| should be used for output device selection and such an
+ // 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 && !info->device.matched_output_device_id.empty()) {
+ 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);
+
+ // We already have the unhashed id and the parameters, so jump to
+ // DeviceParametersReceived.
+ DeviceParametersReceived(std::move(cb), true,
+ info->device.matched_output_device_id,
+ output_params);
+ return;
+ }
+ // Otherwise, the default device is used.
+ }
+
+ if (media::AudioDeviceDescription::IsDefaultDevice(device_id)) {
+ // Default device doesn't need authorization.
+ AccessChecked(std::move(cb), device_id, security_origin, true);
+ return;
+ }
+
+ // Check security origin if nondefault device is requested.
+ if (!MediaStreamManager::IsOriginAllowed(render_process_id_,
+ security_origin)) {
+ bad_message::ReceivedBadMessage(render_process_id_,
+ bad_message::AOAH_UNAUTHORIZED_URL);
+ return;
+ }
+
+ // Check that MediaStream device permissions have been granted for
+ // nondefault devices.
+ permission_checker_->CheckPermission(
+ MEDIA_DEVICE_TYPE_AUDIO_OUTPUT, render_process_id_, render_frame_id,
+ security_origin,
+ base::Bind(&AudioOutputAuthorizationHandler::AccessChecked,
+ weak_factory_.GetWeakPtr(), std::move(cb), device_id,
+ security_origin));
+}
+
+void AudioOutputAuthorizationHandler::AccessChecked(
+ AuthorizationCompletedCallback cb,
+ const std::string& device_id,
+ const url::Origin& security_origin,
+ bool has_access) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!has_access) {
+ cb.Run(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED, false,
+ media::AudioParameters::UnavailableDeviceParams(), std::string());
+ return;
+ }
+
+ // For default device, read output parameters directly. Nondefault
+ // devices require translation first.
+ if (media::AudioDeviceDescription::IsDefaultDevice(device_id)) {
+ GetDeviceParameters(std::move(cb),
+ 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) const {
+ 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)) {
+ GetDeviceParameters(std::move(cb), device_info.device_id);
+ return;
+ }
+ }
+ cb.Run(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, false,
+ media::AudioParameters::UnavailableDeviceParams(), std::string());
+}
+
+void AudioOutputAuthorizationHandler::GetDeviceParameters(
+ AuthorizationCompletedCallback cb,
+ const std::string& raw_device_id) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!raw_device_id.empty());
+ base::PostTaskAndReplyWithResult(
+ media::AudioManager::Get()->GetTaskRunner(), FROM_HERE,
+ base::Bind(&GetDeviceParametersOnDeviceThread, raw_device_id),
+ base::Bind(&AudioOutputAuthorizationHandler::DeviceParametersReceived,
+ weak_factory_.GetWeakPtr(), std::move(cb), false,
+ raw_device_id));
+}
+
+void AudioOutputAuthorizationHandler::DeviceParametersReceived(
+ AuthorizationCompletedCallback cb,
+ bool should_send_id,
+ const std::string& raw_device_id,
+ const media::AudioParameters& output_params) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!raw_device_id.empty());
+
+ cb.Run(media::OUTPUT_DEVICE_STATUS_OK, should_send_id,
+ output_params.IsValid() ? output_params
+ : TryToFixAudioParameters(output_params),
+ raw_device_id);
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698