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

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

Issue 2424163004: Factor out authorization from AudioRendererHost. (Closed)
Patch Set: . 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/renderer_host/media/audio_output_authorization_handler .h"
6
7 #include "base/task_runner_util.h"
8 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
9 #include "content/public/browser/media_device_id.h"
10 #include "media/base/limits.h"
11
12 namespace {
13
14 bool IsValidDeviceId(const std::string& device_id) {
15 static const std::string::size_type kValidLength = 64;
16
17 if (media::AudioDeviceDescription::IsDefaultDevice(device_id) ||
18 device_id == media::AudioDeviceDescription::kCommunicationsDeviceId) {
19 return true;
20 }
21
22 if (device_id.length() != kValidLength)
23 return false;
24
25 for (const char& c : device_id) {
26 if ((c < 'a' || c > 'f') && (c < '0' || c > '9'))
27 return false;
28 }
29
30 return true;
31 }
32
33 void MaybeFixAudioParameters(media::AudioParameters* params) {
34 // If the number of output channels is greater than the maximum, use the
35 // maximum allowed value. Hardware channels are ignored upstream, so it is
36 // better to report a valid value if this is the only problem.
37 if (params->channels() > media::limits::kMaxChannels)
38 params->set_channels_for_discrete(media::limits::kMaxChannels);
39
40 // If hardware parameters are still invalid, use dummy parameters with
41 // fake audio path and let the client handle the error.
42 if (!params->IsValid())
43 *params = media::AudioParameters::UnavailableDeviceParams();
44 }
45
46 media::AudioParameters GetDeviceParametersOnDeviceThread(
47 const std::string& unique_id) {
48 media::AudioManager* audio_manager = media::AudioManager::Get();
49 DCHECK(audio_manager->GetTaskRunner()->BelongsToCurrentThread());
50
51 if (media::AudioDeviceDescription::IsDefaultDevice(unique_id))
52 return audio_manager->GetDefaultOutputStreamParameters();
53 return audio_manager->GetOutputStreamParameters(unique_id);
54 }
55
56 } // namespace
57
58 namespace content {
59
60 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.
61 MediaStreamManager* media_stream_manager,
62 int render_process_id,
63 const std::string& salt)
64 : media_stream_manager_(media_stream_manager),
65 render_process_id_(render_process_id),
66 salt_(salt),
67 bad_message_handler_(),
68 weak_factory(this) {
69 DCHECK(media_stream_manager_);
70 }
71
72 AudioOutputAuthorizationHandler::~AudioOutputAuthorizationHandler() = default;
73
74 void AudioOutputAuthorizationHandler::RequestDeviceAuthorization(
75 int render_frame_id,
76 int session_id,
77 const std::string& device_id,
78 const url::Origin& security_origin,
79 AuthorizationCompletedCallback cb) {
80 DCHECK_CURRENTLY_ON(BrowserThread::IO);
81
82 if (!IsValidDeviceId(device_id)) {
83 cb.Run(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND,
84 media::AudioParameters::UnavailableDeviceParams(), std::string());
85 return;
86 }
87
88 // If |session_id| should be used for output device selection and such output
89 // device is found, reuse the input device permissions.
90 if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id,
91 device_id)) {
92 const StreamDeviceInfo* info =
93 media_stream_manager_->audio_input_device_manager()
94 ->GetOpenedDeviceInfoById(session_id);
95 if (info) {
96 media::AudioParameters output_params(
97 media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
98 static_cast<media::ChannelLayout>(
99 info->device.matched_output.channel_layout),
100 info->device.matched_output.sample_rate, 16,
101 info->device.matched_output.frames_per_buffer);
102 output_params.set_effects(info->device.matched_output.effects);
103 MaybeFixAudioParameters(&output_params);
104
105 cb.Run(media::OUTPUT_DEVICE_STATUS_OK, output_params,
106 GetHMACForMediaDeviceID(salt_, security_origin,
107 info->device.matched_output_device_id));
108 return;
109 }
110 }
111
112 CheckOutputDeviceAccess(std::move(cb), render_frame_id, device_id,
113 security_origin);
114 }
115
116 void AudioOutputAuthorizationHandler::CheckOutputDeviceAccess(
117 AuthorizationCompletedCallback cb,
118 int render_frame_id,
119 const std::string& device_id,
120 const url::Origin& security_origin) {
121 DCHECK_CURRENTLY_ON(BrowserThread::IO);
122
123 // Check security origin if nondefault device is requested.
124 // Ignore check for default device, which is always authorized.
125 if (!media::AudioDeviceDescription::IsDefaultDevice(device_id) &&
126 !MediaStreamManager::IsOriginAllowed(render_process_id_,
127 security_origin)) {
128 if (!bad_message_handler_.is_null())
129 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
130 return;
131 }
132
133 if (media::AudioDeviceDescription::IsDefaultDevice(device_id)) {
134 AccessChecked(std::move(cb), nullptr, device_id, security_origin, true);
135 } else {
136 // Check that MediaStream device permissions have been granted,
137 // hence the use of a MediaStreamUIProxy.
138 std::unique_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create();
139
140 // Use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT
141 // because MediaStreamUIProxy::CheckAccess does not currently support
142 // MEDIA_DEVICE_AUDIO_OUTPUT.
143 // TODO(guidou): Change to MEDIA_DEVICE_AUDIO_OUTPUT when support becomes
144 // available. http://crbug.com/498675
145 ui_proxy->CheckAccess(
146 security_origin, MEDIA_DEVICE_AUDIO_CAPTURE, render_process_id_,
147 render_frame_id,
148 base::Bind(&AudioOutputAuthorizationHandler::AccessChecked,
149 weak_factory.GetWeakPtr(), std::move(cb),
150 base::Passed(&ui_proxy), device_id, security_origin));
151 }
152 }
153
154 void AudioOutputAuthorizationHandler::AccessChecked(
155 AuthorizationCompletedCallback cb,
156 std::unique_ptr<MediaStreamUIProxy> ui_proxy,
157 const std::string& device_id,
158 const url::Origin& security_origin,
159 bool have_access) {
160 DCHECK_CURRENTLY_ON(BrowserThread::IO);
161
162 if (!have_access) {
163 cb.Run(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
164 media::AudioParameters::UnavailableDeviceParams(), std::string());
165 return;
166 }
167
168 // For default device, read output parameters directly. Nondefault devices
169 // require translation first.
170 if (media::AudioDeviceDescription::IsDefaultDevice(device_id)) {
171 base::PostTaskAndReplyWithResult(
172 media::AudioManager::Get()->GetTaskRunner(), FROM_HERE,
173 base::Bind(&GetDeviceParametersOnDeviceThread,
174 media::AudioDeviceDescription::kDefaultDeviceId),
175 base::Bind(&AudioOutputAuthorizationHandler::DeviceParametersReceived,
176 weak_factory.GetWeakPtr(), std::move(cb), true,
177 media::AudioDeviceDescription::kDefaultDeviceId));
178 } else {
179 MediaDevicesManager::BoolDeviceTypes devices_to_enumerate;
180 devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT] = true;
181 media_stream_manager_->media_devices_manager()->EnumerateDevices(
182 devices_to_enumerate,
183 base::Bind(&AudioOutputAuthorizationHandler::TranslateDeviceID,
184 weak_factory.GetWeakPtr(), std::move(cb), device_id,
185 security_origin));
186 }
187 }
188
189 void AudioOutputAuthorizationHandler::TranslateDeviceID(
190 AuthorizationCompletedCallback cb,
191 const std::string& device_id,
192 const url::Origin& security_origin,
193 const MediaDeviceEnumeration& enumeration) {
194 DCHECK_CURRENTLY_ON(BrowserThread::IO);
195 DCHECK(!media::AudioDeviceDescription::IsDefaultDevice(device_id));
196 for (const MediaDeviceInfo& device_info :
197 enumeration[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT]) {
198 if (content::DoesMediaDeviceIDMatchHMAC(salt_, security_origin, device_id,
199 device_info.device_id)) {
200 base::PostTaskAndReplyWithResult(
201 media::AudioManager::Get()->GetTaskRunner(), FROM_HERE,
202 base::Bind(&GetDeviceParametersOnDeviceThread, device_info.device_id),
203 base::Bind(&AudioOutputAuthorizationHandler::DeviceParametersReceived,
204 weak_factory.GetWeakPtr(), std::move(cb), true,
205 device_info.device_id));
206 return;
207 }
208 }
209 DeviceParametersReceived(std::move(cb), false, std::string(),
210 media::AudioParameters::UnavailableDeviceParams());
211 }
212
213 void AudioOutputAuthorizationHandler::DeviceParametersReceived(
214 AuthorizationCompletedCallback cb,
215 bool device_found,
216 const std::string& unique_id,
217 media::AudioParameters output_params) {
218 DCHECK_CURRENTLY_ON(BrowserThread::IO);
219
220 if (!device_found) {
221 cb.Run(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND,
222 media::AudioParameters::UnavailableDeviceParams(), "");
223 return;
224 }
225
226 MaybeFixAudioParameters(&output_params);
227 cb.Run(media::OUTPUT_DEVICE_STATUS_OK, output_params, unique_id);
228 }
229
230 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698