Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 <stdint.h> | 7 #include <stdint.h> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 102 // better to report a valid value if this is the only problem. | 102 // better to report a valid value if this is the only problem. |
| 103 if (params->channels() > media::limits::kMaxChannels) | 103 if (params->channels() > media::limits::kMaxChannels) |
| 104 params->set_channels_for_discrete(media::limits::kMaxChannels); | 104 params->set_channels_for_discrete(media::limits::kMaxChannels); |
| 105 | 105 |
| 106 // If hardware parameters are still invalid, use dummy parameters with | 106 // If hardware parameters are still invalid, use dummy parameters with |
| 107 // fake audio path and let the client handle the error. | 107 // fake audio path and let the client handle the error. |
| 108 if (!params->IsValid()) | 108 if (!params->IsValid()) |
| 109 *params = media::AudioParameters::UnavailableDeviceParams(); | 109 *params = media::AudioParameters::UnavailableDeviceParams(); |
| 110 } | 110 } |
| 111 | 111 |
| 112 // Check that the routing ID references a valid RenderFrameHost, and run | |
| 113 // |callback| on the IO thread with true if the ID is valid. | |
| 114 void ValidateRenderFrameId(int render_process_id, | |
| 115 int render_frame_id, | |
| 116 const base::Callback<void(bool)>& callback) { | |
| 117 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 118 const bool frame_exists = | |
| 119 !!RenderFrameHost::FromID(render_process_id, render_frame_id); | |
| 120 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
| 121 base::Bind(callback, frame_exists)); | |
| 122 } | |
| 123 | |
| 112 } // namespace | 124 } // namespace |
| 113 | 125 |
| 114 class AudioRendererHost::AudioEntry | 126 class AudioRendererHost::AudioEntry |
| 115 : public media::AudioOutputController::EventHandler { | 127 : public media::AudioOutputController::EventHandler { |
| 116 public: | 128 public: |
| 117 AudioEntry(AudioRendererHost* host, | 129 AudioEntry(AudioRendererHost* host, |
| 118 int stream_id, | 130 int stream_id, |
| 119 int render_frame_id, | 131 int render_frame_id, |
| 120 const media::AudioParameters& params, | 132 const media::AudioParameters& params, |
| 121 const std::string& output_device_id, | 133 const std::string& output_device_id, |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 202 const std::string& salt) | 214 const std::string& salt) |
| 203 : BrowserMessageFilter(AudioMsgStart), | 215 : BrowserMessageFilter(AudioMsgStart), |
| 204 render_process_id_(render_process_id), | 216 render_process_id_(render_process_id), |
| 205 audio_manager_(audio_manager), | 217 audio_manager_(audio_manager), |
| 206 mirroring_manager_(mirroring_manager), | 218 mirroring_manager_(mirroring_manager), |
| 207 audio_log_(media_internals->CreateAudioLog( | 219 audio_log_(media_internals->CreateAudioLog( |
| 208 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), | 220 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), |
| 209 media_stream_manager_(media_stream_manager), | 221 media_stream_manager_(media_stream_manager), |
| 210 num_playing_streams_(0), | 222 num_playing_streams_(0), |
| 211 salt_(salt), | 223 salt_(salt), |
| 212 max_simultaneous_streams_(0) { | 224 max_simultaneous_streams_(0), |
| 225 validate_render_frame_id_function_(&ValidateRenderFrameId) { | |
| 213 DCHECK(audio_manager_); | 226 DCHECK(audio_manager_); |
| 214 DCHECK(media_stream_manager_); | 227 DCHECK(media_stream_manager_); |
| 215 } | 228 } |
| 216 | 229 |
| 217 AudioRendererHost::~AudioRendererHost() { | 230 AudioRendererHost::~AudioRendererHost() { |
| 218 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 231 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 219 CHECK(audio_entries_.empty()); | 232 CHECK(audio_entries_.empty()); |
| 220 | 233 |
| 221 // If we had any streams, report UMA stats for the maximum number of | 234 // If we had any streams, report UMA stats for the maximum number of |
| 222 // simultaneous streams for this render process and for the whole browser | 235 // simultaneous streams for this render process and for the whole browser |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 517 stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, std::string())); | 530 stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, std::string())); |
| 518 } | 531 } |
| 519 | 532 |
| 520 void AudioRendererHost::OnCreateStream(int stream_id, | 533 void AudioRendererHost::OnCreateStream(int stream_id, |
| 521 int render_frame_id, | 534 int render_frame_id, |
| 522 const media::AudioParameters& params) { | 535 const media::AudioParameters& params) { |
| 523 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 536 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 524 DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream" | 537 DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream" |
| 525 << "(stream_id=" << stream_id << ")"; | 538 << "(stream_id=" << stream_id << ")"; |
| 526 | 539 |
| 540 // Determine whether to use the device_unique_id from an authorization, or an | |
| 541 // empty string (i.e., when no previous authorization was requested, assume | |
| 542 // default device). | |
| 543 std::string device_unique_id; | |
| 527 const auto& auth_data = authorizations_.find(stream_id); | 544 const auto& auth_data = authorizations_.find(stream_id); |
| 545 if (auth_data != authorizations_.end()) { | |
| 546 CHECK(auth_data->second.first); | |
| 547 device_unique_id.swap(auth_data->second.second); | |
| 548 authorizations_.erase(auth_data); | |
| 549 } | |
| 528 | 550 |
| 529 // If no previous authorization requested, assume default device | 551 // When DCHECKs are turned on, hop over to the UI thread to validate the |
| 530 if (auth_data == authorizations_.end()) { | 552 // |render_frame_id|, then continue stream creation on the IO thread. See |
| 531 DoCreateStream(stream_id, render_frame_id, params, std::string()); | 553 // comment at top of DoCreateStream() for further details. |
| 554 if (DCHECK_IS_ON()) { | |
|
o1ka
2016/07/08 14:09:38
#if DCHECK_IS_ON() ?
DaleCurtis
2016/07/08 18:44:33
Hmm, I think we want #if syntax here instead, ther
miu
2016/07/08 21:21:37
Done.
miu
2016/07/08 21:21:37
Done.
| |
| 555 BrowserThread::PostTask( | |
| 556 BrowserThread::UI, FROM_HERE, | |
| 557 base::Bind( | |
| 558 validate_render_frame_id_function_, render_process_id_, | |
|
o1ka
2016/07/08 14:09:38
What if validate_render_frame_id_function_ is null
miu
2016/07/08 21:21:37
It can't be. The ARH ctor sets it, so a test would
o1ka
2016/07/11 10:35:50
I would say it's still more human-friendly to add
miu
2016/07/14 21:36:12
Yep. The DCHECK() is already being done here:
http
| |
| 559 render_frame_id, | |
| 560 base::Bind(&AudioRendererHost::DoCreateStream, this, stream_id, | |
| 561 render_frame_id, params, device_unique_id))); | |
| 532 return; | 562 return; |
| 533 } | 563 } |
| 534 | 564 DoCreateStream(stream_id, render_frame_id, params, device_unique_id, |
| 535 CHECK(auth_data->second.first); | 565 render_frame_id > 0); |
| 536 DoCreateStream(stream_id, render_frame_id, params, auth_data->second.second); | |
| 537 authorizations_.erase(auth_data); | |
| 538 } | 566 } |
| 539 | 567 |
| 540 void AudioRendererHost::DoCreateStream(int stream_id, | 568 void AudioRendererHost::DoCreateStream(int stream_id, |
| 541 int render_frame_id, | 569 int render_frame_id, |
| 542 const media::AudioParameters& params, | 570 const media::AudioParameters& params, |
| 543 const std::string& device_unique_id) { | 571 const std::string& device_unique_id, |
| 572 bool render_frame_is_valid) { | |
| 544 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 573 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 545 | 574 |
| 546 // media::AudioParameters is validated in the deserializer. | 575 // Fail early if either of two sanity-checks fail: |
| 547 if (LookupById(stream_id) != NULL) { | 576 // 1. There should not yet exist an AudioEntry for the given |stream_id| |
| 577 // since the renderer may not create two streams with the same ID. | |
| 578 // 2. The render frame ID was either invalid or the render frame host it | |
| 579 // references has shutdown before the request could be fulfilled (race | |
| 580 // condition). Renderers must *always* specify a valid render frame ID | |
| 581 // for each audio output they create, as several browser-level features | |
| 582 // depend on this (e.g., OOM manager, UI audio indicator, muting, audio | |
| 583 // capture). | |
| 584 // Note: media::AudioParameters is validated in the deserializer, so there is | |
| 585 // no need to check that here. | |
| 586 if (LookupById(stream_id)) { | |
| 548 SendErrorMessage(stream_id); | 587 SendErrorMessage(stream_id); |
| 549 return; | 588 return; |
| 550 } | 589 } |
| 590 if (!render_frame_is_valid) { | |
| 591 // If this DCHECK triggers for your audio feature, please read the comment | |
| 592 // above. Stubbing/faking this value is not an acceptable solution. | |
| 593 DCHECK_GT(render_frame_id, 0) | |
|
o1ka
2016/07/08 14:09:38
Do not quite understand why this DCHECK? why not D
miu
2016/07/08 21:21:37
My point was to further check whether the ID was i
o1ka
2016/07/11 10:35:50
Acknowledged.
| |
| 594 << "BUG: Invalid render frame ID provided by renderer."; | |
| 595 SendErrorMessage(stream_id); | |
| 596 return; | |
| 597 } | |
| 551 | 598 |
| 552 // Create the shared memory and share with the renderer process. | 599 // Create the shared memory and share with the renderer process. |
| 553 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + | 600 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + |
| 554 AudioBus::CalculateMemorySize(params); | 601 AudioBus::CalculateMemorySize(params); |
| 555 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); | 602 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); |
| 556 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { | 603 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { |
| 557 SendErrorMessage(stream_id); | 604 SendErrorMessage(stream_id); |
| 558 return; | 605 return; |
| 559 } | 606 } |
| 560 | 607 |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 807 callback.Run(false, device_info); | 854 callback.Run(false, device_info); |
| 808 } | 855 } |
| 809 | 856 |
| 810 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { | 857 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { |
| 811 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 858 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 812 const auto& i = authorizations_.find(stream_id); | 859 const auto& i = authorizations_.find(stream_id); |
| 813 return i != authorizations_.end(); | 860 return i != authorizations_.end(); |
| 814 } | 861 } |
| 815 | 862 |
| 816 } // namespace content | 863 } // namespace content |
| OLD | NEW |