| 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" |
| 11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
| 12 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
| 13 #include "base/logging.h" | |
| 14 #include "base/memory/shared_memory.h" | 13 #include "base/memory/shared_memory.h" |
| 15 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 16 #include "base/process/process.h" | 15 #include "base/process/process.h" |
| 17 #include "content/browser/bad_message.h" | 16 #include "content/browser/bad_message.h" |
| 18 #include "content/browser/browser_main_loop.h" | 17 #include "content/browser/browser_main_loop.h" |
| 19 #include "content/browser/media/audio_stream_monitor.h" | 18 #include "content/browser/media/audio_stream_monitor.h" |
| 20 #include "content/browser/media/capture/audio_mirroring_manager.h" | 19 #include "content/browser/media/capture/audio_mirroring_manager.h" |
| 21 #include "content/browser/media/media_internals.h" | 20 #include "content/browser/media/media_internals.h" |
| 22 #include "content/browser/renderer_host/media/audio_input_device_manager.h" | 21 #include "content/browser/renderer_host/media/audio_input_device_manager.h" |
| 23 #include "content/browser/renderer_host/media/audio_sync_reader.h" | 22 #include "content/browser/renderer_host/media/audio_sync_reader.h" |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 // better to report a valid value if this is the only problem. | 101 // better to report a valid value if this is the only problem. |
| 103 if (params->channels() > media::limits::kMaxChannels) | 102 if (params->channels() > media::limits::kMaxChannels) |
| 104 params->set_channels_for_discrete(media::limits::kMaxChannels); | 103 params->set_channels_for_discrete(media::limits::kMaxChannels); |
| 105 | 104 |
| 106 // If hardware parameters are still invalid, use dummy parameters with | 105 // If hardware parameters are still invalid, use dummy parameters with |
| 107 // fake audio path and let the client handle the error. | 106 // fake audio path and let the client handle the error. |
| 108 if (!params->IsValid()) | 107 if (!params->IsValid()) |
| 109 *params = media::AudioParameters::UnavailableDeviceParams(); | 108 *params = media::AudioParameters::UnavailableDeviceParams(); |
| 110 } | 109 } |
| 111 | 110 |
| 111 #if DCHECK_IS_ON() |
| 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 #endif // DCHECK_IS_ON() |
| 124 |
| 112 } // namespace | 125 } // namespace |
| 113 | 126 |
| 114 class AudioRendererHost::AudioEntry | 127 class AudioRendererHost::AudioEntry |
| 115 : public media::AudioOutputController::EventHandler { | 128 : public media::AudioOutputController::EventHandler { |
| 116 public: | 129 public: |
| 117 AudioEntry(AudioRendererHost* host, | 130 AudioEntry(AudioRendererHost* host, |
| 118 int stream_id, | 131 int stream_id, |
| 119 int render_frame_id, | 132 int render_frame_id, |
| 120 const media::AudioParameters& params, | 133 const media::AudioParameters& params, |
| 121 const std::string& output_device_id, | 134 const std::string& output_device_id, |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 const std::string& salt) | 215 const std::string& salt) |
| 203 : BrowserMessageFilter(AudioMsgStart), | 216 : BrowserMessageFilter(AudioMsgStart), |
| 204 render_process_id_(render_process_id), | 217 render_process_id_(render_process_id), |
| 205 audio_manager_(audio_manager), | 218 audio_manager_(audio_manager), |
| 206 mirroring_manager_(mirroring_manager), | 219 mirroring_manager_(mirroring_manager), |
| 207 audio_log_(media_internals->CreateAudioLog( | 220 audio_log_(media_internals->CreateAudioLog( |
| 208 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), | 221 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), |
| 209 media_stream_manager_(media_stream_manager), | 222 media_stream_manager_(media_stream_manager), |
| 210 num_playing_streams_(0), | 223 num_playing_streams_(0), |
| 211 salt_(salt), | 224 salt_(salt), |
| 225 #if DCHECK_IS_ON() |
| 226 validate_render_frame_id_function_(&ValidateRenderFrameId), |
| 227 #endif // DCHECK_IS_ON() |
| 212 max_simultaneous_streams_(0) { | 228 max_simultaneous_streams_(0) { |
| 213 DCHECK(audio_manager_); | 229 DCHECK(audio_manager_); |
| 214 DCHECK(media_stream_manager_); | 230 DCHECK(media_stream_manager_); |
| 215 } | 231 } |
| 216 | 232 |
| 217 AudioRendererHost::~AudioRendererHost() { | 233 AudioRendererHost::~AudioRendererHost() { |
| 218 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 234 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 219 CHECK(audio_entries_.empty()); | 235 CHECK(audio_entries_.empty()); |
| 220 | 236 |
| 221 // If we had any streams, report UMA stats for the maximum number of | 237 // If we had any streams, report UMA stats for the maximum number of |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, std::string())); | 533 stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, std::string())); |
| 518 } | 534 } |
| 519 | 535 |
| 520 void AudioRendererHost::OnCreateStream(int stream_id, | 536 void AudioRendererHost::OnCreateStream(int stream_id, |
| 521 int render_frame_id, | 537 int render_frame_id, |
| 522 const media::AudioParameters& params) { | 538 const media::AudioParameters& params) { |
| 523 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 539 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 524 DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream" | 540 DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream" |
| 525 << "(stream_id=" << stream_id << ")"; | 541 << "(stream_id=" << stream_id << ")"; |
| 526 | 542 |
| 543 // Determine whether to use the device_unique_id from an authorization, or an |
| 544 // empty string (i.e., when no previous authorization was requested, assume |
| 545 // default device). |
| 546 std::string device_unique_id; |
| 527 const auto& auth_data = authorizations_.find(stream_id); | 547 const auto& auth_data = authorizations_.find(stream_id); |
| 528 | 548 if (auth_data != authorizations_.end()) { |
| 529 // If no previous authorization requested, assume default device | 549 CHECK(auth_data->second.first); |
| 530 if (auth_data == authorizations_.end()) { | 550 device_unique_id.swap(auth_data->second.second); |
| 531 DoCreateStream(stream_id, render_frame_id, params, std::string()); | 551 authorizations_.erase(auth_data); |
| 532 return; | |
| 533 } | 552 } |
| 534 | 553 |
| 535 CHECK(auth_data->second.first); | 554 #if DCHECK_IS_ON() |
| 536 DoCreateStream(stream_id, render_frame_id, params, auth_data->second.second); | 555 // When DCHECKs are turned on, hop over to the UI thread to validate the |
| 537 authorizations_.erase(auth_data); | 556 // |render_frame_id|, then continue stream creation on the IO thread. See |
| 557 // comment at top of DoCreateStream() for further details. |
| 558 BrowserThread::PostTask( |
| 559 BrowserThread::UI, FROM_HERE, |
| 560 base::Bind(validate_render_frame_id_function_, render_process_id_, |
| 561 render_frame_id, |
| 562 base::Bind(&AudioRendererHost::DoCreateStream, this, stream_id, |
| 563 render_frame_id, params, device_unique_id))); |
| 564 #else |
| 565 DoCreateStream(stream_id, render_frame_id, params, device_unique_id, |
| 566 render_frame_id > 0); |
| 567 #endif // DCHECK_IS_ON() |
| 538 } | 568 } |
| 539 | 569 |
| 540 void AudioRendererHost::DoCreateStream(int stream_id, | 570 void AudioRendererHost::DoCreateStream(int stream_id, |
| 541 int render_frame_id, | 571 int render_frame_id, |
| 542 const media::AudioParameters& params, | 572 const media::AudioParameters& params, |
| 543 const std::string& device_unique_id) { | 573 const std::string& device_unique_id, |
| 574 bool render_frame_id_is_valid) { |
| 544 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 575 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 545 | 576 |
| 546 // media::AudioParameters is validated in the deserializer. | 577 // Fail early if either of two sanity-checks fail: |
| 547 if (LookupById(stream_id) != NULL) { | 578 // 1. There should not yet exist an AudioEntry for the given |stream_id| |
| 579 // since the renderer may not create two streams with the same ID. |
| 580 // 2. The render frame ID was either invalid or the render frame host it |
| 581 // references has shutdown before the request could be fulfilled (race |
| 582 // condition). Renderers must *always* specify a valid render frame ID |
| 583 // for each audio output they create, as several browser-level features |
| 584 // depend on this (e.g., OOM manager, UI audio indicator, muting, audio |
| 585 // capture). |
| 586 // Note: media::AudioParameters is validated in the deserializer, so there is |
| 587 // no need to check that here. |
| 588 if (LookupById(stream_id)) { |
| 548 SendErrorMessage(stream_id); | 589 SendErrorMessage(stream_id); |
| 549 return; | 590 return; |
| 550 } | 591 } |
| 592 if (!render_frame_id_is_valid) { |
| 593 SendErrorMessage(stream_id); |
| 594 return; |
| 595 } |
| 551 | 596 |
| 552 // Create the shared memory and share with the renderer process. | 597 // Create the shared memory and share with the renderer process. |
| 553 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + | 598 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + |
| 554 AudioBus::CalculateMemorySize(params); | 599 AudioBus::CalculateMemorySize(params); |
| 555 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); | 600 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); |
| 556 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { | 601 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { |
| 557 SendErrorMessage(stream_id); | 602 SendErrorMessage(stream_id); |
| 558 return; | 603 return; |
| 559 } | 604 } |
| 560 | 605 |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 807 callback.Run(false, device_info); | 852 callback.Run(false, device_info); |
| 808 } | 853 } |
| 809 | 854 |
| 810 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { | 855 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { |
| 811 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 856 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 812 const auto& i = authorizations_.find(stream_id); | 857 const auto& i = authorizations_.find(stream_id); |
| 813 return i != authorizations_.end(); | 858 return i != authorizations_.end(); |
| 814 } | 859 } |
| 815 | 860 |
| 816 } // namespace content | 861 } // namespace content |
| OLD | NEW |