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

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

Issue 1323403005: Allow AudioOutputDevice objects to be initialized with a specific hardware output device and store … (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Split permissions check and device-ID translation for clarity Created 5 years, 3 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
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 <utility>
8
7 #include "base/bind.h" 9 #include "base/bind.h"
8 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
9 #include "base/logging.h" 11 #include "base/logging.h"
10 #include "base/memory/shared_memory.h" 12 #include "base/memory/shared_memory.h"
11 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
12 #include "base/process/process.h" 14 #include "base/process/process.h"
13 #include "content/browser/bad_message.h" 15 #include "content/browser/bad_message.h"
14 #include "content/browser/browser_main_loop.h" 16 #include "content/browser/browser_main_loop.h"
15 #include "content/browser/child_process_security_policy_impl.h" 17 #include "content/browser/child_process_security_policy_impl.h"
16 #include "content/browser/loader/resource_dispatcher_host_impl.h" 18 #include "content/browser/loader/resource_dispatcher_host_impl.h"
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 bool is_playing, 56 bool is_playing,
55 int render_view_id) { 57 int render_view_id) {
56 DCHECK_CURRENTLY_ON(BrowserThread::IO); 58 DCHECK_CURRENTLY_ON(BrowserThread::IO);
57 if (render_view_id == MSG_ROUTING_NONE || !ResourceDispatcherHostImpl::Get()) 59 if (render_view_id == MSG_ROUTING_NONE || !ResourceDispatcherHostImpl::Get())
58 return; 60 return;
59 61
60 ResourceDispatcherHostImpl::Get()->OnAudioRenderHostStreamStateChanged( 62 ResourceDispatcherHostImpl::Get()->OnAudioRenderHostStreamStateChanged(
61 render_process_id, render_view_id, is_playing); 63 render_process_id, render_view_id, is_playing);
62 } 64 }
63 65
66 media::AudioParameters DummyParams() {
67 return media::AudioParameters(media::AudioParameters::AUDIO_PCM_LINEAR,
68 media::CHANNEL_LAYOUT_STEREO,
69 media::limits::kMinSampleRate, 1, 1);
70 }
71
64 } // namespace 72 } // namespace
65 73
66 class AudioRendererHost::AudioEntry 74 class AudioRendererHost::AudioEntry
67 : public media::AudioOutputController::EventHandler { 75 : public media::AudioOutputController::EventHandler {
68 public: 76 public:
69 AudioEntry(AudioRendererHost* host, 77 AudioEntry(AudioRendererHost* host,
70 int stream_id, 78 int stream_id,
71 int render_frame_id, 79 int render_frame_id,
72 const media::AudioParameters& params, 80 const media::AudioParameters& params,
73 const std::string& output_device_id, 81 const std::string& output_device_id,
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 this, 144 this,
137 params, 145 params,
138 output_device_id, 146 output_device_id,
139 reader_.get())), 147 reader_.get())),
140 playing_(false) { 148 playing_(false) {
141 DCHECK(controller_.get()); 149 DCHECK(controller_.get());
142 } 150 }
143 151
144 AudioRendererHost::AudioEntry::~AudioEntry() {} 152 AudioRendererHost::AudioEntry::~AudioEntry() {}
145 153
154 class AudioRendererHost::AuthorizationData {
DaleCurtis 2015/09/09 01:31:57 Hmm, this is a lot of data and complexity added to
Guido Urdaneta 2015/09/09 16:22:23 I removed this class altogether and replaced it wi
155 public:
156 explicit AuthorizationData(int render_frame_id);
157 AuthorizationData(int render_frame_id,
158 const std::string& unique_id,
159 const media::AudioParameters& output_params);
160 ~AuthorizationData() = default;
161 bool is_authorized() const { return is_authorized_; }
162 int render_frame_id() const { return render_frame_id_; }
163 bool is_creation_requested() const { return is_creation_requested_; }
164 media::AudioParameters creation_params() const { return creation_params_; }
165 std::string device_unique_id() const { return device_unique_id_; }
166 media::AudioParameters device_output_params() const {
167 return device_output_params_;
168 }
169
170 void Authorize(const std::string& unique_id,
171 const media::AudioParameters& output_params);
172 void RequestCreation(const media::AudioParameters& params);
173
174 private:
175 bool is_authorized_;
176 int render_frame_id_;
177 bool is_creation_requested_;
178 media::AudioParameters creation_params_;
179 std::string device_unique_id_;
180 media::AudioParameters device_output_params_;
181 };
182
183 AudioRendererHost::AuthorizationData::AuthorizationData(int render_frame_id)
184 : is_authorized_(false),
185 render_frame_id_(render_frame_id),
186 is_creation_requested_(false) {}
187
188 AudioRendererHost::AuthorizationData::AuthorizationData(
189 int render_frame_id,
190 const std::string& device_unique_id,
191 const media::AudioParameters& device_output_params)
192 : is_authorized_(true),
193 render_frame_id_(render_frame_id),
194 is_creation_requested_(false),
195 device_unique_id_(device_unique_id),
196 device_output_params_(device_output_params) {}
197
198 void AudioRendererHost::AuthorizationData::Authorize(
199 const std::string& device_unique_id,
200 const media::AudioParameters& device_output_params) {
201 is_authorized_ = true;
202 device_unique_id_ = device_unique_id;
203 device_output_params_ = device_output_params;
204 }
205
206 void AudioRendererHost::AuthorizationData::RequestCreation(
207 const media::AudioParameters& params) {
208 is_creation_requested_ = true;
209 creation_params_ = params;
210 }
211
146 /////////////////////////////////////////////////////////////////////////////// 212 ///////////////////////////////////////////////////////////////////////////////
147 // AudioRendererHost implementations. 213 // AudioRendererHost implementations.
148 214
149 AudioRendererHost::AudioRendererHost( 215 AudioRendererHost::AudioRendererHost(
150 int render_process_id, 216 int render_process_id,
151 media::AudioManager* audio_manager, 217 media::AudioManager* audio_manager,
152 AudioMirroringManager* mirroring_manager, 218 AudioMirroringManager* mirroring_manager,
153 MediaInternals* media_internals, 219 MediaInternals* media_internals,
154 MediaStreamManager* media_stream_manager, 220 MediaStreamManager* media_stream_manager,
155 const ResourceContext::SaltCallback& salt_callback) 221 const ResourceContext::SaltCallback& salt_callback)
(...skipping 21 matching lines...) Expand all
177 BrowserThread::IO, FROM_HERE, 243 BrowserThread::IO, FROM_HERE,
178 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback); 244 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback);
179 } 245 }
180 246
181 void AudioRendererHost::OnChannelClosing() { 247 void AudioRendererHost::OnChannelClosing() {
182 // Since the IPC sender is gone, close all requested audio streams. 248 // Since the IPC sender is gone, close all requested audio streams.
183 while (!audio_entries_.empty()) { 249 while (!audio_entries_.empty()) {
184 // Note: OnCloseStream() removes the entries from audio_entries_. 250 // Note: OnCloseStream() removes the entries from audio_entries_.
185 OnCloseStream(audio_entries_.begin()->first); 251 OnCloseStream(audio_entries_.begin()->first);
186 } 252 }
253
254 // Remove any authorizations for streams that were not yet created
255 authorizations_.clear();
187 } 256 }
188 257
189 void AudioRendererHost::OnDestruct() const { 258 void AudioRendererHost::OnDestruct() const {
190 BrowserThread::DeleteOnIOThread::Destruct(this); 259 BrowserThread::DeleteOnIOThread::Destruct(this);
191 } 260 }
192 261
193 void AudioRendererHost::AudioEntry::OnCreated() { 262 void AudioRendererHost::AudioEntry::OnCreated() {
194 BrowserThread::PostTask( 263 BrowserThread::PostTask(
195 BrowserThread::IO, 264 BrowserThread::IO,
196 FROM_HERE, 265 FROM_HERE,
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 } 374 }
306 375
307 return controllers; 376 return controllers;
308 } 377 }
309 378
310 /////////////////////////////////////////////////////////////////////////////// 379 ///////////////////////////////////////////////////////////////////////////////
311 // IPC Messages handler 380 // IPC Messages handler
312 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) { 381 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
313 bool handled = true; 382 bool handled = true;
314 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message) 383 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message)
384 IPC_MESSAGE_HANDLER(AudioHostMsg_RequestDeviceAuthorization,
385 OnRequestDeviceAuthorization)
315 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream) 386 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
316 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream) 387 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
317 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) 388 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
318 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) 389 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
319 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) 390 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
320 IPC_MESSAGE_HANDLER(AudioHostMsg_SwitchOutputDevice, OnSwitchOutputDevice) 391 IPC_MESSAGE_HANDLER(AudioHostMsg_SwitchOutputDevice, OnSwitchOutputDevice)
321 IPC_MESSAGE_UNHANDLED(handled = false) 392 IPC_MESSAGE_UNHANDLED(handled = false)
322 IPC_END_MESSAGE_MAP() 393 IPC_END_MESSAGE_MAP()
323 394
324 return handled; 395 return handled;
325 } 396 }
326 397
398 void AudioRendererHost::OnRequestDeviceAuthorization(
399 int stream_id,
400 int render_frame_id,
401 int session_id,
402 const std::string& device_id,
403 const GURL& security_origin) {
404 DCHECK_CURRENTLY_ON(BrowserThread::IO);
405 DVLOG(1) << "AudioRendererHost@" << this << "::OnRequestDeviceAuthorization"
406 << "(stream_id=" << stream_id
407 << ", render_frame_id=" << render_frame_id
408 << ", session_id=" << session_id << ", device_id=" << device_id
409 << ", security_origin=" << security_origin << ")";
410
411 if (LookupById(stream_id) || IsAuthorizationStarted(stream_id))
412 return;
413
414 // If attempting to use the output device associated to an opened input
415 // device and the output device is found, reuse the input device
416 // permissions.
417 if (session_id != 0) {
418 const StreamDeviceInfo* info =
419 media_stream_manager_->audio_input_device_manager()
420 ->GetOpenedDeviceInfoById(session_id);
421 if (info) {
422 media::AudioParameters output_params(
423 media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
424 static_cast<media::ChannelLayout>(
425 info->device.matched_output.channel_layout),
426 info->device.matched_output.sample_rate, 16,
427 info->device.matched_output.frames_per_buffer,
428 info->device.matched_output.effects);
429 authorizations_.insert(std::pair<int, AuthorizationData>(
430 stream_id, AuthorizationData(render_frame_id,
431 info->device.matched_output_device_id,
432 output_params)));
433 Send(new AudioMsg_NotifyDeviceAuthorized(stream_id, true, output_params));
434 return;
435 }
436 }
437
438 authorizations_.insert(std::pair<int, AuthorizationData>(
439 stream_id, AuthorizationData(render_frame_id)));
440 CheckOutputDeviceAccess(
441 render_frame_id, device_id, security_origin,
442 base::Bind(&AudioRendererHost::RequestDeviceAuthorizationAccessChecked,
443 this, stream_id, device_id, security_origin));
444 }
445
446 void AudioRendererHost::RequestDeviceAuthorizationAccessChecked(
447 int stream_id,
448 const std::string& device_id,
449 const GURL& security_origin,
450 bool have_access) {
451 DCHECK_CURRENTLY_ON(BrowserThread::IO);
452 const auto& auth_data = authorizations_.find(stream_id);
453
454 // A close request was received while access check was in progress.
455 if (auth_data == authorizations_.end())
456 return;
457
458 if (!have_access) {
459 authorizations_.erase(auth_data);
460 Send(new AudioMsg_NotifyDeviceAuthorized(stream_id, false, DummyParams()));
461 return;
462 }
463
464 TranslateDeviceID(
465 device_id, security_origin,
466 base::Bind(&AudioRendererHost::RequestDeviceAuthorizationTranslated, this,
467 stream_id));
468 }
469
470 void AudioRendererHost::RequestDeviceAuthorizationTranslated(
471 int stream_id,
472 bool device_found,
473 const AudioOutputDeviceInfo& device_info) {
474 DCHECK_CURRENTLY_ON(BrowserThread::IO);
475 const auto& auth_data = authorizations_.find(stream_id);
476
477 // A close request was received while access check was in progress
DaleCurtis 2015/09/09 01:31:57 translate was in progress?
Guido Urdaneta 2015/09/09 16:22:23 Done.
478 if (auth_data == authorizations_.end())
479 return;
480
481 if (!device_found) {
482 authorizations_.erase(auth_data);
483 Send(new AudioMsg_NotifyDeviceAuthorized(stream_id, false, DummyParams()));
484 return;
485 }
486
487 auth_data->second.Authorize(device_info.unique_id, device_info.output_params);
488 Send(new AudioMsg_NotifyDeviceAuthorized(stream_id, true,
489 device_info.output_params));
490
491 if (auth_data->second.is_creation_requested()) {
492 DoCreateStream(stream_id, auth_data->second.render_frame_id(),
493 auth_data->second.creation_params(), device_info.unique_id);
494 authorizations_.erase(auth_data);
495 }
496 }
497
327 void AudioRendererHost::OnCreateStream(int stream_id, 498 void AudioRendererHost::OnCreateStream(int stream_id,
328 int render_frame_id, 499 int render_frame_id,
329 int session_id,
330 const media::AudioParameters& params) { 500 const media::AudioParameters& params) {
331 DCHECK_CURRENTLY_ON(BrowserThread::IO); 501 DCHECK_CURRENTLY_ON(BrowserThread::IO);
332 502
333 DVLOG(1) << "AudioRendererHost@" << this 503 DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream"
334 << "::OnCreateStream(stream_id=" << stream_id 504 << "(stream_id=" << stream_id << ")";
335 << ", render_frame_id=" << render_frame_id 505
336 << ", session_id=" << session_id << ")"; 506 const auto& auth_data = authorizations_.find(stream_id);
337 DCHECK_GT(render_frame_id, 0); 507
508 // If no previous authorization requested, assume default device
509 if (auth_data == authorizations_.end()) {
510 DoCreateStream(stream_id, render_frame_id, params, std::string());
511 return;
512 }
513
514 DCHECK_EQ(render_frame_id, auth_data->second.render_frame_id());
515 // If authorization is ongoing, defer creation.
DaleCurtis 2015/09/09 01:31:57 This ends up adding substantial complexity. Can we
Guido Urdaneta 2015/09/09 16:22:23 Done. See comment above.
516 if (!auth_data->second.is_authorized()) {
517 auth_data->second.RequestCreation(params);
518 return;
519 }
520
521 // If already authorized, create stream and remove authorization
522 DoCreateStream(stream_id, render_frame_id, params,
523 auth_data->second.device_unique_id());
524 authorizations_.erase(auth_data);
525 }
526
527 void AudioRendererHost::DoCreateStream(int stream_id,
528 int render_frame_id,
529 const media::AudioParameters& params,
530 const std::string& device_unique_id) {
531 DCHECK_CURRENTLY_ON(BrowserThread::IO);
338 532
339 // media::AudioParameters is validated in the deserializer. 533 // media::AudioParameters is validated in the deserializer.
340 if (LookupById(stream_id) != NULL) { 534 if (LookupById(stream_id) != NULL) {
341 SendErrorMessage(stream_id); 535 SendErrorMessage(stream_id);
342 return; 536 return;
343 } 537 }
344 538
345 // Initialize the |output_device_id| to an empty string which indicates that
346 // the default device should be used. If a StreamDeviceInfo instance was found
347 // though, then we use the matched output device.
348 std::string output_device_id;
349 const StreamDeviceInfo* info = media_stream_manager_->
350 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
351 if (info)
352 output_device_id = info->device.matched_output_device_id;
353
354 // Create the shared memory and share with the renderer process. 539 // Create the shared memory and share with the renderer process.
355 uint32 shared_memory_size = AudioBus::CalculateMemorySize(params); 540 uint32 shared_memory_size = AudioBus::CalculateMemorySize(params);
356 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); 541 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
357 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { 542 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
358 SendErrorMessage(stream_id); 543 SendErrorMessage(stream_id);
359 return; 544 return;
360 } 545 }
361 546
362 scoped_ptr<AudioSyncReader> reader( 547 scoped_ptr<AudioSyncReader> reader(
363 new AudioSyncReader(shared_memory.get(), params)); 548 new AudioSyncReader(shared_memory.get(), params));
364 if (!reader->Init()) { 549 if (!reader->Init()) {
365 SendErrorMessage(stream_id); 550 SendErrorMessage(stream_id);
366 return; 551 return;
367 } 552 }
368 553
369 MediaObserver* const media_observer = 554 MediaObserver* const media_observer =
370 GetContentClient()->browser()->GetMediaObserver(); 555 GetContentClient()->browser()->GetMediaObserver();
371 if (media_observer) 556 if (media_observer)
372 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id); 557 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
373 558
374 scoped_ptr<AudioEntry> entry(new AudioEntry(this, 559 scoped_ptr<AudioEntry> entry(
375 stream_id, 560 new AudioEntry(this, stream_id, render_frame_id, params, device_unique_id,
376 render_frame_id, 561 shared_memory.Pass(), reader.Pass()));
377 params,
378 output_device_id,
379 shared_memory.Pass(),
380 reader.Pass()));
381 if (mirroring_manager_) { 562 if (mirroring_manager_) {
382 mirroring_manager_->AddDiverter( 563 mirroring_manager_->AddDiverter(
383 render_process_id_, entry->render_frame_id(), entry->controller()); 564 render_process_id_, entry->render_frame_id(), entry->controller());
384 } 565 }
385 audio_entries_.insert(std::make_pair(stream_id, entry.release())); 566 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
386 audio_log_->OnCreated(stream_id, params, output_device_id); 567
568 audio_log_->OnCreated(stream_id, params, device_unique_id);
387 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry( 569 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry(
388 stream_id, render_process_id_, render_frame_id, audio_log_.get()); 570 stream_id, render_process_id_, render_frame_id, audio_log_.get());
389 } 571 }
390 572
391 void AudioRendererHost::OnPlayStream(int stream_id) { 573 void AudioRendererHost::OnPlayStream(int stream_id) {
392 DCHECK_CURRENTLY_ON(BrowserThread::IO); 574 DCHECK_CURRENTLY_ON(BrowserThread::IO);
393 575
394 AudioEntry* entry = LookupById(stream_id); 576 AudioEntry* entry = LookupById(stream_id);
395 if (!entry) { 577 if (!entry) {
396 SendErrorMessage(stream_id); 578 SendErrorMessage(stream_id);
(...skipping 26 matching lines...) Expand all
423 return; 605 return;
424 } 606 }
425 607
426 // Make sure the volume is valid. 608 // Make sure the volume is valid.
427 if (volume < 0 || volume > 1.0) 609 if (volume < 0 || volume > 1.0)
428 return; 610 return;
429 entry->controller()->SetVolume(volume); 611 entry->controller()->SetVolume(volume);
430 audio_log_->OnSetVolume(stream_id, volume); 612 audio_log_->OnSetVolume(stream_id, volume);
431 } 613 }
432 614
433 void AudioRendererHost::OnSwitchOutputDevice(int stream_id, 615 void AudioRendererHost::OnSwitchOutputDevice(int stream_id,
DaleCurtis 2015/09/09 01:31:57 As mentioned in the AOD class, after this CL lands
Guido Urdaneta 2015/09/09 16:22:23 That is the goal. A possible road map after this
DaleCurtis 2015/09/12 01:17:19 sgtm!
434 int render_frame_id, 616 int render_frame_id,
435 const std::string& device_id, 617 const std::string& device_id,
436 const GURL& security_origin, 618 const GURL& security_origin) {
437 int request_id) {
438 DCHECK_CURRENTLY_ON(BrowserThread::IO); 619 DCHECK_CURRENTLY_ON(BrowserThread::IO);
439 DVLOG(1) << "AudioRendererHost@" << this 620 DVLOG(1) << "AudioRendererHost@" << this
440 << "::OnSwitchOutputDevice(stream_id=" << stream_id 621 << "::OnSwitchOutputDevice(stream_id=" << stream_id
441 << ", render_frame_id=" << render_frame_id 622 << ", render_frame_id=" << render_frame_id
442 << ", device_id=" << device_id 623 << ", device_id=" << device_id
443 << ", security_origin=" << security_origin 624 << ", security_origin=" << security_origin << ")";
444 << ", request_id=" << request_id << ")"; 625 CheckOutputDeviceAccess(
445 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL( 626 render_frame_id, device_id, security_origin,
446 render_process_id_, security_origin)) { 627 base::Bind(&AudioRendererHost::SwitchOutputDeviceAccessChecked, this,
447 content::bad_message::ReceivedBadMessage(this, 628 stream_id, device_id, security_origin));
448 bad_message::ARH_UNAUTHORIZED_URL); 629 }
630
631 void AudioRendererHost::SwitchOutputDeviceAccessChecked(
632 int stream_id,
633 const std::string& device_id,
634 const GURL& security_origin,
635 bool have_access) {
636 DCHECK_CURRENTLY_ON(BrowserThread::IO);
637 if (!have_access) {
638 Send(new AudioMsg_NotifyOutputDeviceSwitched(
639 stream_id, media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_AUTHORIZED,
640 DummyParams()));
449 return; 641 return;
450 } 642 }
451 643
452 if (device_id.empty()) { 644 TranslateDeviceID(device_id, security_origin,
453 DVLOG(1) << __FUNCTION__ << ": default output device requested. " 645 base::Bind(&AudioRendererHost::SwitchOutputDeviceTranslated,
454 << "No permissions check or device translation/validation needed."; 646 this, stream_id));
455 DoSwitchOutputDevice(stream_id, device_id, request_id);
456 } else {
457 // Check that MediaStream device permissions have been granted,
458 // hence the use of a MediaStreamUIProxy.
459 scoped_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create();
460
461 // Use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT
462 // because MediaStreamUIProxy::CheckAccess does not currently support
463 // MEDIA_DEVICE_AUDIO_OUTPUT.
464 // TODO(guidou): Change to MEDIA_DEVICE_AUDIO_OUTPUT when support becomes
465 // available. http://crbug.com/498675
466 ui_proxy->CheckAccess(
467 security_origin, MEDIA_DEVICE_AUDIO_CAPTURE,
468 render_process_id_, render_frame_id,
469 base::Bind(&AudioRendererHost::OutputDeviceAccessChecked, this,
470 base::Passed(&ui_proxy), stream_id, device_id,
471 security_origin, render_frame_id, request_id));
472 }
473 } 647 }
474 648
475 void AudioRendererHost::OutputDeviceAccessChecked( 649 void AudioRendererHost::SwitchOutputDeviceTranslated(
476 scoped_ptr<MediaStreamUIProxy> ui_proxy,
477 int stream_id, 650 int stream_id,
478 const std::string& device_id, 651 bool device_found,
479 const GURL& security_origin, 652 const AudioOutputDeviceInfo& device_info) {
480 int render_frame_id,
481 int request_id,
482 bool have_access) {
483 DCHECK_CURRENTLY_ON(BrowserThread::IO); 653 DCHECK_CURRENTLY_ON(BrowserThread::IO);
484 DVLOG(1) << __FUNCTION__; 654 if (!device_found) {
485 if (!have_access) {
486 DVLOG(0) << __FUNCTION__
487 << ": Have no access to media devices. Not switching device.";
488 Send(new AudioMsg_NotifyOutputDeviceSwitched( 655 Send(new AudioMsg_NotifyOutputDeviceSwitched(
489 stream_id, request_id, 656 stream_id, media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_FOUND,
490 media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_AUTHORIZED)); 657 DummyParams()));
491 return; 658 return;
492 } 659 }
493 660
494 scoped_refptr<base::SingleThreadTaskRunner> audio_worker_runner =
495 AudioManager::Get()->GetWorkerTaskRunner();
496 audio_worker_runner->PostTask(
497 FROM_HERE,
498 base::Bind(&AudioRendererHost::StartTranslateOutputDeviceName, this,
499 stream_id, device_id, security_origin, request_id));
500 }
501
502 void AudioRendererHost::StartTranslateOutputDeviceName(
503 int stream_id,
504 const std::string& device_id,
505 const GURL& security_origin,
506 int request_id) {
507 DCHECK(AudioManager::Get()->GetWorkerTaskRunner()->BelongsToCurrentThread());
508 DCHECK(!device_id.empty());
509 DVLOG(1) << __FUNCTION__;
510
511 media::AudioDeviceNames* device_names(new media::AudioDeviceNames);
512 AudioManager::Get()->GetAudioOutputDeviceNames(device_names);
513
514 BrowserThread::PostTask(
515 BrowserThread::IO, FROM_HERE,
516 base::Bind(&AudioRendererHost::FinishTranslateOutputDeviceName, this,
517 stream_id, device_id, security_origin, request_id,
518 base::Owned(device_names)));
519 }
520
521 void AudioRendererHost::FinishTranslateOutputDeviceName(
522 int stream_id,
523 const std::string& device_id,
524 const GURL& security_origin,
525 int request_id,
526 media::AudioDeviceNames* device_names) {
527 DCHECK_CURRENTLY_ON(BrowserThread::IO);
528 DCHECK(!device_id.empty());
529 DVLOG(1) << __FUNCTION__;
530
531 std::string raw_device_id;
532 // Process the enumeration here because |salt_callback_| can run
533 // only on the IO thread
534 for (const auto& device_name : *device_names) {
535 const std::string candidate_device_id = content::GetHMACForMediaDeviceID(
536 salt_callback_, security_origin, device_name.unique_id);
537 if (candidate_device_id == device_id) {
538 DVLOG(1) << "Requested device " << device_name.unique_id << " - "
539 << device_name.device_name;
540 raw_device_id = device_name.unique_id;
541 }
542 }
543
544 if (raw_device_id.empty()) {
545 DVLOG(1) << "Requested device " << device_id << " could not be found.";
546 Send(new AudioMsg_NotifyOutputDeviceSwitched(
547 stream_id, request_id,
548 media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_FOUND));
549 return;
550 }
551
552 DoSwitchOutputDevice(stream_id, raw_device_id, request_id);
553 }
554
555 void AudioRendererHost::DoSwitchOutputDevice(int stream_id,
556 const std::string& raw_device_id,
557 int request_id) {
558 DCHECK_CURRENTLY_ON(BrowserThread::IO);
559 DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << raw_device_id << ", "
560 << request_id << ")";
561 AudioEntry* entry = LookupById(stream_id); 661 AudioEntry* entry = LookupById(stream_id);
562 if (!entry) { 662 if (!entry) {
563 Send(new AudioMsg_NotifyOutputDeviceSwitched( 663 Send(new AudioMsg_NotifyOutputDeviceSwitched(
564 stream_id, request_id, 664 stream_id, media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_INTERNAL,
565 media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_OBSOLETE)); 665 DummyParams()));
566 return; 666 return;
567 } 667 }
568 668
569 entry->controller()->SwitchOutputDevice( 669 entry->controller()->SwitchOutputDevice(
570 raw_device_id, base::Bind(&AudioRendererHost::DoOutputDeviceSwitched, 670 device_info.unique_id,
571 this, stream_id, request_id)); 671 base::Bind(&AudioRendererHost::OutputDeviceSwitched, this, stream_id,
572 audio_log_->OnSwitchOutputDevice(entry->stream_id(), raw_device_id); 672 device_info.output_params));
673 audio_log_->OnSwitchOutputDevice(entry->stream_id(), device_info.unique_id);
573 } 674 }
574 675
575 void AudioRendererHost::DoOutputDeviceSwitched(int stream_id, int request_id) { 676 void AudioRendererHost::OutputDeviceSwitched(
677 int stream_id,
678 const media::AudioParameters& output_params) {
576 DCHECK_CURRENTLY_ON(BrowserThread::IO); 679 DCHECK_CURRENTLY_ON(BrowserThread::IO);
577 DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << request_id << ")";
578 Send(new AudioMsg_NotifyOutputDeviceSwitched( 680 Send(new AudioMsg_NotifyOutputDeviceSwitched(
579 stream_id, request_id, media::SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS)); 681 stream_id, media::SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS, output_params));
580 } 682 }
581 683
582 void AudioRendererHost::SendErrorMessage(int stream_id) { 684 void AudioRendererHost::SendErrorMessage(int stream_id) {
583 Send(new AudioMsg_NotifyStreamStateChanged( 685 Send(new AudioMsg_NotifyStreamStateChanged(
584 stream_id, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)); 686 stream_id, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR));
585 } 687 }
586 688
587 void AudioRendererHost::OnCloseStream(int stream_id) { 689 void AudioRendererHost::OnCloseStream(int stream_id) {
588 DCHECK_CURRENTLY_ON(BrowserThread::IO); 690 DCHECK_CURRENTLY_ON(BrowserThread::IO);
691 authorizations_.erase(stream_id);
589 692
590 // Prevent oustanding callbacks from attempting to close/delete the same 693 // Prevent oustanding callbacks from attempting to close/delete the same
591 // AudioEntry twice. 694 // AudioEntry twice.
592 AudioEntryMap::iterator i = audio_entries_.find(stream_id); 695 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
593 if (i == audio_entries_.end()) 696 if (i == audio_entries_.end())
594 return; 697 return;
595 scoped_ptr<AudioEntry> entry(i->second); 698 scoped_ptr<AudioEntry> entry(i->second);
596 audio_entries_.erase(i); 699 audio_entries_.erase(i);
597 700
598 media::AudioOutputController* const controller = entry->controller(); 701 media::AudioOutputController* const controller = entry->controller();
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
676 for (AudioEntryMap::const_iterator it = audio_entries_.begin(); 779 for (AudioEntryMap::const_iterator it = audio_entries_.begin();
677 it != audio_entries_.end(); 780 it != audio_entries_.end();
678 ++it) { 781 ++it) {
679 AudioEntry* entry = it->second; 782 AudioEntry* entry = it->second;
680 if (entry->render_frame_id() == render_frame_id && entry->playing()) 783 if (entry->render_frame_id() == render_frame_id && entry->playing())
681 return true; 784 return true;
682 } 785 }
683 return false; 786 return false;
684 } 787 }
685 788
789 void AudioRendererHost::CheckOutputDeviceAccess(
790 int render_frame_id,
791 const std::string& device_id,
792 const GURL& security_origin,
793 const OutputDeviceAccessCB& callback) {
794 DCHECK_CURRENTLY_ON(BrowserThread::IO);
795
796 // Skip origin check in requests for the default device with an empty
797 // security origin.
798 bool skip_origin_check = security_origin.is_empty() && device_id.empty();
799 if (!skip_origin_check &&
800 !ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
801 render_process_id_, security_origin)) {
802 content::bad_message::ReceivedBadMessage(this,
803 bad_message::ARH_UNAUTHORIZED_URL);
804 return;
805 }
806
807 if (device_id.empty()) {
808 callback.Run(true);
809 } else {
810 // Check that MediaStream device permissions have been granted,
811 // hence the use of a MediaStreamUIProxy.
812 scoped_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create();
813
814 // Use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT
815 // because MediaStreamUIProxy::CheckAccess does not currently support
816 // MEDIA_DEVICE_AUDIO_OUTPUT.
817 // TODO(guidou): Change to MEDIA_DEVICE_AUDIO_OUTPUT when support becomes
818 // available. http://crbug.com/498675
819 ui_proxy->CheckAccess(security_origin, MEDIA_DEVICE_AUDIO_CAPTURE,
820 render_process_id_, render_frame_id,
821 base::Bind(&AudioRendererHost::AccessChecked, this,
822 base::Passed(&ui_proxy), callback));
823 }
824 }
825
826 void AudioRendererHost::AccessChecked(scoped_ptr<MediaStreamUIProxy> ui_proxy,
827 const OutputDeviceAccessCB& callback,
828 bool have_access) {
829 DCHECK_CURRENTLY_ON(BrowserThread::IO);
830 callback.Run(have_access);
831 }
832
833 void AudioRendererHost::TranslateDeviceID(const std::string& device_id,
834 const GURL& security_origin,
835 const OutputDeviceInfoCB& callback) {
836 DCHECK_CURRENTLY_ON(BrowserThread::IO);
837 AudioOutputDeviceEnumerator* enumerator =
838 media_stream_manager_->audio_output_device_enumerator();
839 enumerator->Enumerate(base::Bind(&AudioRendererHost::FinishTranslateDeviceID,
840 this, device_id, security_origin, callback));
841 }
842
843 void AudioRendererHost::FinishTranslateDeviceID(
844 const std::string& device_id,
845 const GURL& security_origin,
846 const OutputDeviceInfoCB& callback,
847 const AudioOutputDeviceEnumeration& device_infos) {
848 DCHECK_CURRENTLY_ON(BrowserThread::IO);
849 bool use_default_device = device_id.empty();
850 for (const AudioOutputDeviceInfo& device_info : device_infos) {
851 if (use_default_device) {
852 if (device_info.unique_id == media::AudioManagerBase::kDefaultDeviceId) {
853 callback.Run(true, device_info);
854 return;
855 }
856 } else {
857 const std::string candidate_device_id = content::GetHMACForMediaDeviceID(
858 salt_callback_, security_origin, device_info.unique_id);
859 if (candidate_device_id == device_id) {
860 callback.Run(true, device_info);
861 return;
862 }
863 }
864 }
865 DCHECK(!use_default_device); // Default device must always be found
866 callback.Run(false, {std::string(), std::string(), DummyParams()});
DaleCurtis 2015/09/09 01:31:57 Is this initialization syntax allowed? http://chro
Guido Urdaneta 2015/09/09 16:22:23 Structs are allowed to be initialized this way, bu
867 }
868
869 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) {
870 DCHECK_CURRENTLY_ON(BrowserThread::IO);
871 const auto& i = authorizations_.find(stream_id);
872 return i != authorizations_.end();
873 }
874
686 } // namespace content 875 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698