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

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

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

Powered by Google App Engine
This is Rietveld 408576698