| 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 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 *params = media::AudioParameters::UnavailableDeviceParams(); | 108 *params = media::AudioParameters::UnavailableDeviceParams(); |
| 110 } | 109 } |
| 111 | 110 |
| 112 void UMALogDeviceAuthorizationTime(base::TimeTicks auth_start_time) { | 111 void UMALogDeviceAuthorizationTime(base::TimeTicks auth_start_time) { |
| 113 UMA_HISTOGRAM_CUSTOM_TIMES("Media.Audio.OutputDeviceAuthorizationTime", | 112 UMA_HISTOGRAM_CUSTOM_TIMES("Media.Audio.OutputDeviceAuthorizationTime", |
| 114 base::TimeTicks::Now() - auth_start_time, | 113 base::TimeTicks::Now() - auth_start_time, |
| 115 base::TimeDelta::FromMilliseconds(1), | 114 base::TimeDelta::FromMilliseconds(1), |
| 116 base::TimeDelta::FromMilliseconds(5000), 50); | 115 base::TimeDelta::FromMilliseconds(5000), 50); |
| 117 } | 116 } |
| 118 | 117 |
| 118 #if DCHECK_IS_ON() |
| 119 // Check that the routing ID references a valid RenderFrameHost, and run |
| 120 // |callback| on the IO thread with true if the ID is valid. |
| 121 void ValidateRenderFrameId(int render_process_id, |
| 122 int render_frame_id, |
| 123 const base::Callback<void(bool)>& callback) { |
| 124 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 125 const bool frame_exists = |
| 126 !!RenderFrameHost::FromID(render_process_id, render_frame_id); |
| 127 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 128 base::Bind(callback, frame_exists)); |
| 129 } |
| 130 #endif // DCHECK_IS_ON() |
| 131 |
| 119 } // namespace | 132 } // namespace |
| 120 | 133 |
| 121 class AudioRendererHost::AudioEntry | 134 class AudioRendererHost::AudioEntry |
| 122 : public media::AudioOutputController::EventHandler { | 135 : public media::AudioOutputController::EventHandler { |
| 123 public: | 136 public: |
| 124 AudioEntry(AudioRendererHost* host, | 137 AudioEntry(AudioRendererHost* host, |
| 125 int stream_id, | 138 int stream_id, |
| 126 int render_frame_id, | 139 int render_frame_id, |
| 127 const media::AudioParameters& params, | 140 const media::AudioParameters& params, |
| 128 const std::string& output_device_id, | 141 const std::string& output_device_id, |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 const std::string& salt) | 222 const std::string& salt) |
| 210 : BrowserMessageFilter(AudioMsgStart), | 223 : BrowserMessageFilter(AudioMsgStart), |
| 211 render_process_id_(render_process_id), | 224 render_process_id_(render_process_id), |
| 212 audio_manager_(audio_manager), | 225 audio_manager_(audio_manager), |
| 213 mirroring_manager_(mirroring_manager), | 226 mirroring_manager_(mirroring_manager), |
| 214 audio_log_(media_internals->CreateAudioLog( | 227 audio_log_(media_internals->CreateAudioLog( |
| 215 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), | 228 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), |
| 216 media_stream_manager_(media_stream_manager), | 229 media_stream_manager_(media_stream_manager), |
| 217 num_playing_streams_(0), | 230 num_playing_streams_(0), |
| 218 salt_(salt), | 231 salt_(salt), |
| 232 #if DCHECK_IS_ON() |
| 233 validate_render_frame_id_function_(&ValidateRenderFrameId), |
| 234 #endif // DCHECK_IS_ON() |
| 219 max_simultaneous_streams_(0) { | 235 max_simultaneous_streams_(0) { |
| 220 DCHECK(audio_manager_); | 236 DCHECK(audio_manager_); |
| 221 DCHECK(media_stream_manager_); | 237 DCHECK(media_stream_manager_); |
| 222 } | 238 } |
| 223 | 239 |
| 224 AudioRendererHost::~AudioRendererHost() { | 240 AudioRendererHost::~AudioRendererHost() { |
| 225 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 241 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 226 CHECK(audio_entries_.empty()); | 242 CHECK(audio_entries_.empty()); |
| 227 | 243 |
| 228 // If we had any streams, report UMA stats for the maximum number of | 244 // If we had any streams, report UMA stats for the maximum number of |
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 537 stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, std::string())); | 553 stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, std::string())); |
| 538 } | 554 } |
| 539 | 555 |
| 540 void AudioRendererHost::OnCreateStream(int stream_id, | 556 void AudioRendererHost::OnCreateStream(int stream_id, |
| 541 int render_frame_id, | 557 int render_frame_id, |
| 542 const media::AudioParameters& params) { | 558 const media::AudioParameters& params) { |
| 543 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 559 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 544 DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream" | 560 DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream" |
| 545 << "(stream_id=" << stream_id << ")"; | 561 << "(stream_id=" << stream_id << ")"; |
| 546 | 562 |
| 563 // Determine whether to use the device_unique_id from an authorization, or an |
| 564 // empty string (i.e., when no previous authorization was requested, assume |
| 565 // default device). |
| 566 std::string device_unique_id; |
| 547 const auto& auth_data = authorizations_.find(stream_id); | 567 const auto& auth_data = authorizations_.find(stream_id); |
| 548 | 568 if (auth_data != authorizations_.end()) { |
| 549 // If no previous authorization requested, assume default device | 569 CHECK(auth_data->second.first); |
| 550 if (auth_data == authorizations_.end()) { | 570 device_unique_id.swap(auth_data->second.second); |
| 551 DoCreateStream(stream_id, render_frame_id, params, std::string()); | 571 authorizations_.erase(auth_data); |
| 552 return; | |
| 553 } | 572 } |
| 554 | 573 |
| 555 CHECK(auth_data->second.first); | 574 #if DCHECK_IS_ON() |
| 556 DoCreateStream(stream_id, render_frame_id, params, auth_data->second.second); | 575 // When DCHECKs are turned on, hop over to the UI thread to validate the |
| 557 authorizations_.erase(auth_data); | 576 // |render_frame_id|, then continue stream creation on the IO thread. See |
| 577 // comment at top of DoCreateStream() for further details. |
| 578 BrowserThread::PostTask( |
| 579 BrowserThread::UI, FROM_HERE, |
| 580 base::Bind(validate_render_frame_id_function_, render_process_id_, |
| 581 render_frame_id, |
| 582 base::Bind(&AudioRendererHost::DoCreateStream, this, stream_id, |
| 583 render_frame_id, params, device_unique_id))); |
| 584 #else |
| 585 DoCreateStream(stream_id, render_frame_id, params, device_unique_id, |
| 586 render_frame_id > 0); |
| 587 #endif // DCHECK_IS_ON() |
| 558 } | 588 } |
| 559 | 589 |
| 560 void AudioRendererHost::DoCreateStream(int stream_id, | 590 void AudioRendererHost::DoCreateStream(int stream_id, |
| 561 int render_frame_id, | 591 int render_frame_id, |
| 562 const media::AudioParameters& params, | 592 const media::AudioParameters& params, |
| 563 const std::string& device_unique_id) { | 593 const std::string& device_unique_id, |
| 594 bool render_frame_id_is_valid) { |
| 564 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 595 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 565 | 596 |
| 566 // media::AudioParameters is validated in the deserializer. | 597 // Fail early if either of two sanity-checks fail: |
| 567 if (LookupById(stream_id) != NULL) { | 598 // 1. There should not yet exist an AudioEntry for the given |stream_id| |
| 599 // since the renderer may not create two streams with the same ID. |
| 600 // 2. The render frame ID was either invalid or the render frame host it |
| 601 // references has shutdown before the request could be fulfilled (race |
| 602 // condition). Renderers must *always* specify a valid render frame ID |
| 603 // for each audio output they create, as several browser-level features |
| 604 // depend on this (e.g., OOM manager, UI audio indicator, muting, audio |
| 605 // capture). |
| 606 // Note: media::AudioParameters is validated in the deserializer, so there is |
| 607 // no need to check that here. |
| 608 if (LookupById(stream_id)) { |
| 568 SendErrorMessage(stream_id); | 609 SendErrorMessage(stream_id); |
| 569 return; | 610 return; |
| 570 } | 611 } |
| 612 if (!render_frame_id_is_valid) { |
| 613 SendErrorMessage(stream_id); |
| 614 return; |
| 615 } |
| 571 | 616 |
| 572 // Create the shared memory and share with the renderer process. | 617 // Create the shared memory and share with the renderer process. |
| 573 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + | 618 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + |
| 574 AudioBus::CalculateMemorySize(params); | 619 AudioBus::CalculateMemorySize(params); |
| 575 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); | 620 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); |
| 576 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { | 621 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { |
| 577 SendErrorMessage(stream_id); | 622 SendErrorMessage(stream_id); |
| 578 return; | 623 return; |
| 579 } | 624 } |
| 580 | 625 |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 827 callback.Run(false, device_info); | 872 callback.Run(false, device_info); |
| 828 } | 873 } |
| 829 | 874 |
| 830 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { | 875 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { |
| 831 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 876 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 832 const auto& i = authorizations_.find(stream_id); | 877 const auto& i = authorizations_.find(stream_id); |
| 833 return i != authorizations_.end(); | 878 return i != authorizations_.end(); |
| 834 } | 879 } |
| 835 | 880 |
| 836 } // namespace content | 881 } // namespace content |
| OLD | NEW |