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 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 108 *params = media::AudioParameters::UnavailableDeviceParams(); | 108 *params = media::AudioParameters::UnavailableDeviceParams(); |
| 109 } | 109 } |
| 110 | 110 |
| 111 void UMALogDeviceAuthorizationTime(base::TimeTicks auth_start_time) { | 111 void UMALogDeviceAuthorizationTime(base::TimeTicks auth_start_time) { |
| 112 UMA_HISTOGRAM_CUSTOM_TIMES("Media.Audio.OutputDeviceAuthorizationTime", | 112 UMA_HISTOGRAM_CUSTOM_TIMES("Media.Audio.OutputDeviceAuthorizationTime", |
| 113 base::TimeTicks::Now() - auth_start_time, | 113 base::TimeTicks::Now() - auth_start_time, |
| 114 base::TimeDelta::FromMilliseconds(1), | 114 base::TimeDelta::FromMilliseconds(1), |
| 115 base::TimeDelta::FromMilliseconds(5000), 50); | 115 base::TimeDelta::FromMilliseconds(5000), 50); |
| 116 } | 116 } |
| 117 | 117 |
| 118 #if DCHECK_IS_ON() | |
| 119 // Check that the routing ID references a valid RenderFrameHost, and run | 118 // Check that the routing ID references a valid RenderFrameHost, and run |
| 120 // |callback| on the IO thread with true if the ID is valid. | 119 // |callback| on the IO thread with true if the ID is valid. |
| 121 void ValidateRenderFrameId(int render_process_id, | 120 void ValidateRenderFrameId(int render_process_id, |
| 122 int render_frame_id, | 121 int render_frame_id, |
| 123 const base::Callback<void(bool)>& callback) { | 122 const base::Callback<void(bool)>& callback) { |
| 124 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 123 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 125 const bool frame_exists = | 124 const bool frame_exists = |
| 126 !!RenderFrameHost::FromID(render_process_id, render_frame_id); | 125 !!RenderFrameHost::FromID(render_process_id, render_frame_id); |
| 127 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 126 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 128 base::Bind(callback, frame_exists)); | 127 base::Bind(callback, frame_exists)); |
| 129 } | 128 } |
| 130 #endif // DCHECK_IS_ON() | |
| 131 | 129 |
| 132 } // namespace | 130 } // namespace |
| 133 | 131 |
| 134 class AudioRendererHost::AudioEntry | 132 class AudioRendererHost::AudioEntry |
| 135 : public media::AudioOutputController::EventHandler { | 133 : public media::AudioOutputController::EventHandler { |
| 136 public: | 134 public: |
| 137 AudioEntry(AudioRendererHost* host, | 135 AudioEntry(AudioRendererHost* host, |
| 138 int stream_id, | 136 int stream_id, |
| 139 int render_frame_id, | 137 int render_frame_id, |
| 140 const media::AudioParameters& params, | 138 const media::AudioParameters& params, |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 222 const std::string& salt) | 220 const std::string& salt) |
| 223 : BrowserMessageFilter(AudioMsgStart), | 221 : BrowserMessageFilter(AudioMsgStart), |
| 224 render_process_id_(render_process_id), | 222 render_process_id_(render_process_id), |
| 225 audio_manager_(audio_manager), | 223 audio_manager_(audio_manager), |
| 226 mirroring_manager_(mirroring_manager), | 224 mirroring_manager_(mirroring_manager), |
| 227 audio_log_(media_internals->CreateAudioLog( | 225 audio_log_(media_internals->CreateAudioLog( |
| 228 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), | 226 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), |
| 229 media_stream_manager_(media_stream_manager), | 227 media_stream_manager_(media_stream_manager), |
| 230 num_playing_streams_(0), | 228 num_playing_streams_(0), |
| 231 salt_(salt), | 229 salt_(salt), |
| 232 #if DCHECK_IS_ON() | |
| 233 validate_render_frame_id_function_(&ValidateRenderFrameId), | 230 validate_render_frame_id_function_(&ValidateRenderFrameId), |
| 234 #endif // DCHECK_IS_ON() | |
| 235 max_simultaneous_streams_(0) { | 231 max_simultaneous_streams_(0) { |
| 236 DCHECK(audio_manager_); | 232 DCHECK(audio_manager_); |
| 237 DCHECK(media_stream_manager_); | 233 DCHECK(media_stream_manager_); |
| 238 } | 234 } |
| 239 | 235 |
| 240 AudioRendererHost::~AudioRendererHost() { | 236 AudioRendererHost::~AudioRendererHost() { |
| 241 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 237 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 242 CHECK(audio_entries_.empty()); | 238 CHECK(audio_entries_.empty()); |
| 243 | 239 |
| 244 // If we had any streams, report UMA stats for the maximum number of | 240 // If we had any streams, report UMA stats for the maximum number of |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 348 if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) { | 344 if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) { |
| 349 ReportErrorAndClose(entry->stream_id()); | 345 ReportErrorAndClose(entry->stream_id()); |
| 350 return; | 346 return; |
| 351 } | 347 } |
| 352 | 348 |
| 353 Send(new AudioMsg_NotifyStreamCreated( | 349 Send(new AudioMsg_NotifyStreamCreated( |
| 354 entry->stream_id(), foreign_memory_handle, socket_descriptor, | 350 entry->stream_id(), foreign_memory_handle, socket_descriptor, |
| 355 entry->shared_memory()->requested_size())); | 351 entry->shared_memory()->requested_size())); |
| 356 } | 352 } |
| 357 | 353 |
| 354 void AudioRendererHost::DidValidateRenderFrame(int stream_id, bool is_valid) { | |
| 355 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 356 | |
| 357 if (!is_valid) { | |
| 358 DLOG(WARNING) << "Render frame for stream (id=" << stream_id | |
| 359 << ") no longer exists."; | |
| 360 ReportErrorAndClose(stream_id); | |
|
o1ka
2016/09/05 11:58:38
My concern is that (as far as I understand) this m
DaleCurtis
2016/09/06 19:24:40
If this isn't okay then none of our error handling
| |
| 361 } | |
| 362 } | |
| 363 | |
| 358 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id, | 364 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id, |
| 359 bool is_playing) { | 365 bool is_playing) { |
| 360 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 366 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 361 | 367 |
| 362 AudioEntry* const entry = LookupById(stream_id); | 368 AudioEntry* const entry = LookupById(stream_id); |
| 363 if (!entry) | 369 if (!entry) |
| 364 return; | 370 return; |
| 365 | 371 |
| 366 Send(new AudioMsg_NotifyStreamStateChanged( | 372 Send(new AudioMsg_NotifyStreamStateChanged( |
| 367 stream_id, | 373 stream_id, |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 564 // empty string (i.e., when no previous authorization was requested, assume | 570 // empty string (i.e., when no previous authorization was requested, assume |
| 565 // default device). | 571 // default device). |
| 566 std::string device_unique_id; | 572 std::string device_unique_id; |
| 567 const auto& auth_data = authorizations_.find(stream_id); | 573 const auto& auth_data = authorizations_.find(stream_id); |
| 568 if (auth_data != authorizations_.end()) { | 574 if (auth_data != authorizations_.end()) { |
| 569 CHECK(auth_data->second.first); | 575 CHECK(auth_data->second.first); |
| 570 device_unique_id.swap(auth_data->second.second); | 576 device_unique_id.swap(auth_data->second.second); |
| 571 authorizations_.erase(auth_data); | 577 authorizations_.erase(auth_data); |
| 572 } | 578 } |
| 573 | 579 |
| 574 #if DCHECK_IS_ON() | |
| 575 // When DCHECKs are turned on, hop over to the UI thread to validate the | |
| 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() | |
| 588 } | |
| 589 | |
| 590 void AudioRendererHost::DoCreateStream(int stream_id, | |
| 591 int render_frame_id, | |
| 592 const media::AudioParameters& params, | |
| 593 const std::string& device_unique_id, | |
| 594 bool render_frame_id_is_valid) { | |
| 595 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 596 | |
| 597 // Fail early if either of two sanity-checks fail: | 580 // Fail early if either of two sanity-checks fail: |
| 598 // 1. There should not yet exist an AudioEntry for the given |stream_id| | 581 // 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. | 582 // 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 | 583 // 2. An out-of-range render frame ID was provided. Renderers must *always* |
| 601 // references has shutdown before the request could be fulfilled (race | 584 // specify a valid render frame ID for each audio output they create, as |
| 602 // condition). Renderers must *always* specify a valid render frame ID | 585 // several browser-level features depend on this (e.g., OOM manager, UI |
| 603 // for each audio output they create, as several browser-level features | 586 // audio indicator, muting, audio capture). |
| 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 | 587 // Note: media::AudioParameters is validated in the deserializer, so there is |
| 607 // no need to check that here. | 588 // no need to check that here. |
| 608 if (LookupById(stream_id)) { | 589 if (LookupById(stream_id)) { |
| 609 SendErrorMessage(stream_id); | 590 SendErrorMessage(stream_id); |
| 610 return; | 591 return; |
| 611 } | 592 } |
| 612 if (!render_frame_id_is_valid) { | 593 if (render_frame_id <= 0) { |
| 613 SendErrorMessage(stream_id); | 594 SendErrorMessage(stream_id); |
| 614 return; | 595 return; |
| 615 } | 596 } |
| 616 | 597 |
| 598 // Post a task to the UI thread to check that the |render_frame_id| references | |
| 599 // a valid render frame. This validation is important for all the reasons | |
| 600 // stated in the comments above. This does not block stream creation, but will | |
| 601 // force-close the stream later if validation fails. | |
| 602 BrowserThread::PostTask( | |
| 603 BrowserThread::UI, FROM_HERE, | |
| 604 base::Bind(validate_render_frame_id_function_, render_process_id_, | |
| 605 render_frame_id, | |
| 606 base::Bind(&AudioRendererHost::DidValidateRenderFrame, this, | |
| 607 stream_id))); | |
| 608 | |
| 617 // Create the shared memory and share with the renderer process. | 609 // Create the shared memory and share with the renderer process. |
| 618 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + | 610 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + |
| 619 AudioBus::CalculateMemorySize(params); | 611 AudioBus::CalculateMemorySize(params); |
| 620 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); | 612 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); |
| 621 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { | 613 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { |
| 622 SendErrorMessage(stream_id); | 614 SendErrorMessage(stream_id); |
| 623 return; | 615 return; |
| 624 } | 616 } |
| 625 | 617 |
| 626 std::unique_ptr<AudioSyncReader> reader( | 618 std::unique_ptr<AudioSyncReader> reader( |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 861 callback.Run(false, device_info); | 853 callback.Run(false, device_info); |
| 862 } | 854 } |
| 863 | 855 |
| 864 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { | 856 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { |
| 865 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 857 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 866 const auto& i = authorizations_.find(stream_id); | 858 const auto& i = authorizations_.find(stream_id); |
| 867 return i != authorizations_.end(); | 859 return i != authorizations_.end(); |
| 868 } | 860 } |
| 869 | 861 |
| 870 } // namespace content | 862 } // namespace content |
| OLD | NEW |