| 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> | |
| 9 | 8 |
| 10 #include "base/bind.h" | 9 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| 12 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
| 13 #include "base/memory/ptr_util.h" | |
| 14 #include "base/memory/shared_memory.h" | |
| 15 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
| 16 #include "content/browser/bad_message.h" | 13 #include "content/browser/bad_message.h" |
| 17 #include "content/browser/browser_main_loop.h" | 14 #include "content/browser/browser_main_loop.h" |
| 18 #include "content/browser/media/audio_stream_monitor.h" | 15 #include "content/browser/media/audio_stream_monitor.h" |
| 19 #include "content/browser/media/capture/audio_mirroring_manager.h" | 16 #include "content/browser/media/capture/audio_mirroring_manager.h" |
| 20 #include "content/browser/media/media_internals.h" | 17 #include "content/browser/media/media_internals.h" |
| 21 #include "content/browser/renderer_host/media/audio_input_device_manager.h" | 18 #include "content/browser/renderer_host/media/audio_input_device_manager.h" |
| 22 #include "content/browser/renderer_host/media/audio_sync_reader.h" | 19 #include "content/browser/renderer_host/media/audio_sync_reader.h" |
| 23 #include "content/browser/renderer_host/media/media_stream_manager.h" | 20 #include "content/browser/renderer_host/media/media_stream_manager.h" |
| 24 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" | |
| 25 #include "content/common/media/audio_messages.h" | 21 #include "content/common/media/audio_messages.h" |
| 26 #include "content/public/browser/content_browser_client.h" | 22 #include "content/public/browser/content_browser_client.h" |
| 27 #include "content/public/browser/media_device_id.h" | 23 #include "content/public/browser/media_device_id.h" |
| 28 #include "content/public/browser/media_observer.h" | 24 #include "content/public/browser/media_observer.h" |
| 29 #include "content/public/browser/render_frame_host.h" | 25 #include "content/public/browser/render_frame_host.h" |
| 30 #include "media/audio/audio_device_description.h" | 26 #include "media/audio/audio_device_description.h" |
| 31 #include "media/audio/audio_streams_tracker.h" | 27 #include "media/audio/audio_streams_tracker.h" |
| 32 #include "media/base/audio_bus.h" | 28 #include "media/base/audio_bus.h" |
| 33 #include "media/base/limits.h" | 29 #include "media/base/limits.h" |
| 34 | 30 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 const base::Callback<void(bool)>& callback) { | 64 const base::Callback<void(bool)>& callback) { |
| 69 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 65 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 70 const bool frame_exists = | 66 const bool frame_exists = |
| 71 !!RenderFrameHost::FromID(render_process_id, render_frame_id); | 67 !!RenderFrameHost::FromID(render_process_id, render_frame_id); |
| 72 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 68 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 73 base::Bind(callback, frame_exists)); | 69 base::Bind(callback, frame_exists)); |
| 74 } | 70 } |
| 75 | 71 |
| 76 } // namespace | 72 } // namespace |
| 77 | 73 |
| 78 class AudioRendererHost::AudioEntry | |
| 79 : public media::AudioOutputController::EventHandler { | |
| 80 public: | |
| 81 ~AudioEntry() override; | |
| 82 | |
| 83 // Returns nullptr on failure. | |
| 84 static std::unique_ptr<AudioRendererHost::AudioEntry> Create( | |
| 85 AudioRendererHost* host, | |
| 86 int stream_id, | |
| 87 int render_frame_id, | |
| 88 const media::AudioParameters& params, | |
| 89 const std::string& output_device_id); | |
| 90 | |
| 91 int stream_id() const { | |
| 92 return stream_id_; | |
| 93 } | |
| 94 | |
| 95 int render_frame_id() const { return render_frame_id_; } | |
| 96 | |
| 97 media::AudioOutputController* controller() const { return controller_.get(); } | |
| 98 | |
| 99 AudioSyncReader* reader() const { return reader_.get(); } | |
| 100 | |
| 101 // Used by ARH to track the number of active streams for UMA stats. | |
| 102 bool playing() const { return playing_; } | |
| 103 void set_playing(bool playing) { playing_ = playing; } | |
| 104 | |
| 105 private: | |
| 106 AudioEntry(AudioRendererHost* host, | |
| 107 int stream_id, | |
| 108 int render_frame_id, | |
| 109 const media::AudioParameters& params, | |
| 110 const std::string& output_device_id, | |
| 111 std::unique_ptr<AudioSyncReader> reader); | |
| 112 | |
| 113 // media::AudioOutputController::EventHandler implementation. | |
| 114 void OnCreated() override; | |
| 115 void OnPlaying() override; | |
| 116 void OnPaused() override; | |
| 117 void OnError() override; | |
| 118 | |
| 119 AudioRendererHost* const host_; | |
| 120 const int stream_id_; | |
| 121 | |
| 122 // The routing ID of the source RenderFrame. | |
| 123 const int render_frame_id_; | |
| 124 | |
| 125 // The synchronous reader to be used by |controller_|. | |
| 126 const std::unique_ptr<AudioSyncReader> reader_; | |
| 127 | |
| 128 // The AudioOutputController that manages the audio stream. | |
| 129 const scoped_refptr<media::AudioOutputController> controller_; | |
| 130 | |
| 131 bool playing_; | |
| 132 | |
| 133 DISALLOW_COPY_AND_ASSIGN(AudioEntry); | |
| 134 }; | |
| 135 | |
| 136 AudioRendererHost::AudioEntry::AudioEntry( | |
| 137 AudioRendererHost* host, | |
| 138 int stream_id, | |
| 139 int render_frame_id, | |
| 140 const media::AudioParameters& params, | |
| 141 const std::string& output_device_id, | |
| 142 std::unique_ptr<AudioSyncReader> reader) | |
| 143 : host_(host), | |
| 144 stream_id_(stream_id), | |
| 145 render_frame_id_(render_frame_id), | |
| 146 reader_(std::move(reader)), | |
| 147 controller_(media::AudioOutputController::Create(host->audio_manager_, | |
| 148 this, | |
| 149 params, | |
| 150 output_device_id, | |
| 151 reader_.get())), | |
| 152 playing_(false) { | |
| 153 DCHECK(controller_); | |
| 154 } | |
| 155 | |
| 156 AudioRendererHost::AudioEntry::~AudioEntry() {} | |
| 157 | |
| 158 // static | |
| 159 std::unique_ptr<AudioRendererHost::AudioEntry> | |
| 160 AudioRendererHost::AudioEntry::Create(AudioRendererHost* host, | |
| 161 int stream_id, | |
| 162 int render_frame_id, | |
| 163 const media::AudioParameters& params, | |
| 164 const std::string& output_device_id) { | |
| 165 std::unique_ptr<AudioSyncReader> reader(AudioSyncReader::Create(params)); | |
| 166 if (!reader) { | |
| 167 return nullptr; | |
| 168 } | |
| 169 return base::WrapUnique(new AudioEntry(host, stream_id, render_frame_id, | |
| 170 params, output_device_id, | |
| 171 std::move(reader))); | |
| 172 } | |
| 173 | |
| 174 /////////////////////////////////////////////////////////////////////////////// | 74 /////////////////////////////////////////////////////////////////////////////// |
| 175 // AudioRendererHost implementations. | 75 // AudioRendererHost implementations. |
| 176 | 76 |
| 177 AudioRendererHost::AudioRendererHost(int render_process_id, | 77 AudioRendererHost::AudioRendererHost(int render_process_id, |
| 178 media::AudioManager* audio_manager, | 78 media::AudioManager* audio_manager, |
| 179 AudioMirroringManager* mirroring_manager, | 79 AudioMirroringManager* mirroring_manager, |
| 180 MediaInternals* media_internals, | |
| 181 MediaStreamManager* media_stream_manager, | 80 MediaStreamManager* media_stream_manager, |
| 182 const std::string& salt) | 81 const std::string& salt) |
| 183 : BrowserMessageFilter(AudioMsgStart), | 82 : BrowserMessageFilter(AudioMsgStart), |
| 184 render_process_id_(render_process_id), | 83 render_process_id_(render_process_id), |
| 185 audio_manager_(audio_manager), | 84 audio_manager_(audio_manager), |
| 186 mirroring_manager_(mirroring_manager), | 85 mirroring_manager_(mirroring_manager), |
| 187 audio_log_(media_internals->CreateAudioLog( | 86 media_stream_manager_(media_stream_manager), |
| 188 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), | |
| 189 num_playing_streams_(0), | 87 num_playing_streams_(0), |
| 190 salt_(salt), | 88 salt_(salt), |
| 191 validate_render_frame_id_function_(&ValidateRenderFrameId), | 89 validate_render_frame_id_function_(&ValidateRenderFrameId), |
| 192 max_simultaneous_streams_(0), | 90 max_simultaneous_streams_(0), |
| 193 authorization_handler_(audio_manager_, | 91 authorization_handler_(audio_manager_, |
| 194 media_stream_manager, | 92 media_stream_manager, |
| 195 render_process_id_, | 93 render_process_id_, |
| 196 salt) { | 94 salt) { |
| 197 DCHECK(audio_manager_); | 95 DCHECK(audio_manager_); |
| 198 } | 96 } |
| 199 | 97 |
| 200 AudioRendererHost::~AudioRendererHost() { | 98 AudioRendererHost::~AudioRendererHost() { |
| 201 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 99 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 202 CHECK(audio_entries_.empty()); | 100 DCHECK(delegates_.empty()); |
| 203 | 101 |
| 204 // If we had any streams, report UMA stats for the maximum number of | 102 // If we had any streams, report UMA stats for the maximum number of |
| 205 // simultaneous streams for this render process and for the whole browser | 103 // simultaneous streams for this render process and for the whole browser |
| 206 // process since last reported. | 104 // process since last reported. |
| 207 if (max_simultaneous_streams_ > 0) { | 105 if (max_simultaneous_streams_ > 0) { |
| 208 UMA_HISTOGRAM_CUSTOM_COUNTS("Media.AudioRendererIpcStreams", | 106 UMA_HISTOGRAM_CUSTOM_COUNTS("Media.AudioRendererIpcStreams", |
| 209 max_simultaneous_streams_, 1, 50, 51); | 107 max_simultaneous_streams_, 1, 50, 51); |
| 210 UMA_HISTOGRAM_CUSTOM_COUNTS( | 108 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 211 "Media.AudioRendererIpcStreamsTotal", | 109 "Media.AudioRendererIpcStreamsTotal", |
| 212 g_audio_streams_tracker.Get().max_stream_count(), | 110 g_audio_streams_tracker.Get().max_stream_count(), |
| 213 1, 100, 101); | 111 1, 100, 101); |
| 214 g_audio_streams_tracker.Get().ResetMaxStreamCount(); | 112 g_audio_streams_tracker.Get().ResetMaxStreamCount(); |
| 215 } | 113 } |
| 216 } | 114 } |
| 217 | 115 |
| 218 void AudioRendererHost::GetOutputControllers( | 116 void AudioRendererHost::GetOutputControllers( |
| 219 const RenderProcessHost::GetAudioOutputControllersCallback& | 117 const RenderProcessHost::GetAudioOutputControllersCallback& |
| 220 callback) const { | 118 callback) const { |
| 221 BrowserThread::PostTaskAndReplyWithResult( | 119 BrowserThread::PostTaskAndReplyWithResult( |
| 222 BrowserThread::IO, FROM_HERE, | 120 BrowserThread::IO, FROM_HERE, |
| 223 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback); | 121 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback); |
| 224 } | 122 } |
| 225 | 123 |
| 226 void AudioRendererHost::OnChannelClosing() { | 124 void AudioRendererHost::OnChannelClosing() { |
| 227 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 125 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 228 // Since the IPC sender is gone, close all requested audio streams. | 126 // Since the IPC sender is gone, close all requested audio streams. |
| 229 while (!audio_entries_.empty()) { | 127 // The audio streams tracker isn't automatically decremented since the |
| 230 // Note: OnCloseStream() removes the entries from audio_entries_. | 128 // removal isn't done through OnCloseStream. |
| 231 OnCloseStream(audio_entries_.begin()->first); | 129 g_audio_streams_tracker.Get().DecreaseStreamCount(delegates_.size()); |
| 232 } | 130 delegates_.clear(); |
| 233 | 131 |
| 234 // Remove any authorizations for streams that were not yet created | 132 // Remove any authorizations for streams that were not yet created |
| 235 authorizations_.clear(); | 133 authorizations_.clear(); |
| 236 } | 134 } |
| 237 | 135 |
| 238 void AudioRendererHost::OnDestruct() const { | 136 void AudioRendererHost::OnDestruct() const { |
| 239 BrowserThread::DeleteOnIOThread::Destruct(this); | 137 BrowserThread::DeleteOnIOThread::Destruct(this); |
| 240 } | 138 } |
| 241 | 139 |
| 242 void AudioRendererHost::AudioEntry::OnCreated() { | 140 void AudioRendererHost::OnStreamCreated( |
| 243 BrowserThread::PostTask( | 141 int stream_id, |
| 244 BrowserThread::IO, | 142 base::SharedMemory* shared_memory, |
| 245 FROM_HERE, | 143 base::CancelableSyncSocket* foreign_socket) { |
| 246 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_)); | |
| 247 } | |
| 248 | |
| 249 void AudioRendererHost::AudioEntry::OnPlaying() { | |
| 250 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
| 251 base::Bind(&AudioRendererHost::StreamStateChanged, | |
| 252 host_, stream_id_, true)); | |
| 253 } | |
| 254 | |
| 255 void AudioRendererHost::AudioEntry::OnPaused() { | |
| 256 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
| 257 base::Bind(&AudioRendererHost::StreamStateChanged, | |
| 258 host_, stream_id_, false)); | |
| 259 } | |
| 260 | |
| 261 void AudioRendererHost::AudioEntry::OnError() { | |
| 262 BrowserThread::PostTask( | |
| 263 BrowserThread::IO, | |
| 264 FROM_HERE, | |
| 265 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_)); | |
| 266 } | |
| 267 | |
| 268 void AudioRendererHost::DoCompleteCreation(int stream_id) { | |
| 269 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 144 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 270 | 145 |
| 271 if (!PeerHandle()) { | 146 if (!PeerHandle()) { |
| 272 DLOG(WARNING) << "Renderer process handle is invalid."; | 147 DLOG(WARNING) << "Renderer process handle is invalid."; |
| 273 ReportErrorAndClose(stream_id); | 148 OnStreamError(stream_id); |
| 274 return; | 149 return; |
| 275 } | 150 } |
| 276 | 151 |
| 277 AudioEntry* const entry = LookupById(stream_id); | 152 if (!LookupById(stream_id)) { |
| 278 if (!entry) { | 153 OnStreamError(stream_id); |
| 279 ReportErrorAndClose(stream_id); | |
| 280 return; | 154 return; |
| 281 } | 155 } |
| 282 | 156 |
| 283 // Now construction is done and we are ready to send the shared memory and the | |
| 284 // sync socket to the renderer. | |
| 285 base::SharedMemory* shared_memory = entry->reader()->shared_memory(); | |
| 286 base::CancelableSyncSocket* foreign_socket = | |
| 287 entry->reader()->foreign_socket(); | |
| 288 | |
| 289 base::SharedMemoryHandle foreign_memory_handle; | 157 base::SharedMemoryHandle foreign_memory_handle; |
| 290 base::SyncSocket::TransitDescriptor socket_descriptor; | 158 base::SyncSocket::TransitDescriptor socket_descriptor; |
| 291 size_t shared_memory_size = shared_memory->requested_size(); | 159 size_t shared_memory_size = shared_memory->requested_size(); |
| 292 | 160 |
| 293 if (!(shared_memory->ShareToProcess(PeerHandle(), &foreign_memory_handle) && | 161 if (!(shared_memory->ShareToProcess(PeerHandle(), &foreign_memory_handle) && |
| 294 foreign_socket->PrepareTransitDescriptor(PeerHandle(), | 162 foreign_socket->PrepareTransitDescriptor(PeerHandle(), |
| 295 &socket_descriptor))) { | 163 &socket_descriptor))) { |
| 296 // Something went wrong in preparing the IPC handles. | 164 // Something went wrong in preparing the IPC handles. |
| 297 ReportErrorAndClose(entry->stream_id()); | 165 OnStreamError(stream_id); |
| 298 return; | 166 return; |
| 299 } | 167 } |
| 300 | 168 |
| 301 Send(new AudioMsg_NotifyStreamCreated( | 169 Send(new AudioMsg_NotifyStreamCreated( |
| 302 stream_id, foreign_memory_handle, socket_descriptor, | 170 stream_id, foreign_memory_handle, socket_descriptor, |
| 303 base::checked_cast<uint32_t>(shared_memory_size))); | 171 base::checked_cast<uint32_t>(shared_memory_size))); |
| 304 } | 172 } |
| 305 | 173 |
| 174 void AudioRendererHost::OnStreamError(int stream_id) { |
| 175 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 176 |
| 177 SendErrorMessage(stream_id); |
| 178 OnCloseStream(stream_id); |
| 179 } |
| 180 |
| 306 void AudioRendererHost::DidValidateRenderFrame(int stream_id, bool is_valid) { | 181 void AudioRendererHost::DidValidateRenderFrame(int stream_id, bool is_valid) { |
| 307 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 182 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 308 | 183 |
| 309 if (!is_valid) { | 184 if (is_valid) |
| 310 DLOG(WARNING) << "Render frame for stream (id=" << stream_id | |
| 311 << ") no longer exists."; | |
| 312 ReportErrorAndClose(stream_id); | |
| 313 } | |
| 314 } | |
| 315 | |
| 316 void AudioRendererHost::StreamStateChanged(int stream_id, bool is_playing) { | |
| 317 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 318 | |
| 319 AudioEntry* const entry = LookupById(stream_id); | |
| 320 if (!entry) | |
| 321 return; | 185 return; |
| 322 | 186 |
| 323 if (is_playing) { | 187 DLOG(WARNING) << "Render frame for stream (id=" << stream_id |
| 324 AudioStreamMonitor::StartMonitoringStream( | 188 << ") no longer exists."; |
| 325 render_process_id_, | 189 OnStreamError(stream_id); |
| 326 entry->render_frame_id(), | |
| 327 entry->stream_id(), | |
| 328 base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip, | |
| 329 entry->controller())); | |
| 330 } else { | |
| 331 AudioStreamMonitor::StopMonitoringStream( | |
| 332 render_process_id_, entry->render_frame_id(), entry->stream_id()); | |
| 333 } | |
| 334 UpdateNumPlayingStreams(entry, is_playing); | |
| 335 } | 190 } |
| 336 | 191 |
| 337 RenderProcessHost::AudioOutputControllerList | 192 RenderProcessHost::AudioOutputControllerList |
| 338 AudioRendererHost::DoGetOutputControllers() const { | 193 AudioRendererHost::DoGetOutputControllers() const { |
| 339 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 194 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 340 | 195 |
| 341 RenderProcessHost::AudioOutputControllerList controllers; | 196 RenderProcessHost::AudioOutputControllerList controllers; |
| 342 for (AudioEntryMap::const_iterator it = audio_entries_.begin(); | 197 for (const auto& delegate : delegates_) |
| 343 it != audio_entries_.end(); | 198 controllers.push_back(delegate->controller()); |
| 344 ++it) { | |
| 345 controllers.push_back(it->second->controller()); | |
| 346 } | |
| 347 | 199 |
| 348 return controllers; | 200 return controllers; |
| 349 } | 201 } |
| 350 | 202 |
| 351 /////////////////////////////////////////////////////////////////////////////// | 203 /////////////////////////////////////////////////////////////////////////////// |
| 352 // IPC Messages handler | 204 // IPC Messages handler |
| 353 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) { | 205 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) { |
| 354 bool handled = true; | 206 bool handled = true; |
| 355 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message) | 207 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message) |
| 356 IPC_MESSAGE_HANDLER(AudioHostMsg_RequestDeviceAuthorization, | 208 IPC_MESSAGE_HANDLER(AudioHostMsg_RequestDeviceAuthorization, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 372 int session_id, | 224 int session_id, |
| 373 const std::string& device_id, | 225 const std::string& device_id, |
| 374 const url::Origin& security_origin) { | 226 const url::Origin& security_origin) { |
| 375 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 227 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 376 const base::TimeTicks auth_start_time = base::TimeTicks::Now(); | 228 const base::TimeTicks auth_start_time = base::TimeTicks::Now(); |
| 377 DVLOG(1) << "AudioRendererHost@" << this << "::OnRequestDeviceAuthorization" | 229 DVLOG(1) << "AudioRendererHost@" << this << "::OnRequestDeviceAuthorization" |
| 378 << "(stream_id=" << stream_id | 230 << "(stream_id=" << stream_id |
| 379 << ", render_frame_id=" << render_frame_id | 231 << ", render_frame_id=" << render_frame_id |
| 380 << ", session_id=" << session_id << ", device_id=" << device_id | 232 << ", session_id=" << session_id << ", device_id=" << device_id |
| 381 << ", security_origin=" << security_origin << ")"; | 233 << ", security_origin=" << security_origin << ")"; |
| 234 |
| 382 if (LookupById(stream_id) || IsAuthorizationStarted(stream_id)) | 235 if (LookupById(stream_id) || IsAuthorizationStarted(stream_id)) |
| 383 return; | 236 return; |
| 384 | 237 |
| 385 authorizations_.insert( | 238 authorizations_.insert( |
| 386 std::make_pair(stream_id, std::make_pair(false, std::string()))); | 239 std::make_pair(stream_id, std::make_pair(false, std::string()))); |
| 387 | 240 |
| 388 // Unretained is ok here since |this| owns |authorization_handler_| and | 241 // Unretained is ok here since |this| owns |authorization_handler_| and |
| 389 // |authorization_handler_| owns the callback. | 242 // |authorization_handler_| owns the callback. |
| 390 authorization_handler_.RequestDeviceAuthorization( | 243 authorization_handler_.RequestDeviceAuthorization( |
| 391 render_frame_id, session_id, device_id, security_origin, | 244 render_frame_id, session_id, device_id, security_origin, |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 446 // to create it now. | 299 // to create it now. |
| 447 content::bad_message::ReceivedBadMessage( | 300 content::bad_message::ReceivedBadMessage( |
| 448 this, bad_message::ARH_CREATED_STREAM_WITHOUT_AUTHORIZATION); | 301 this, bad_message::ARH_CREATED_STREAM_WITHOUT_AUTHORIZATION); |
| 449 return; | 302 return; |
| 450 } | 303 } |
| 451 device_unique_id.swap(auth_data->second.second); | 304 device_unique_id.swap(auth_data->second.second); |
| 452 authorizations_.erase(auth_data); | 305 authorizations_.erase(auth_data); |
| 453 } | 306 } |
| 454 | 307 |
| 455 // Fail early if either of two sanity-checks fail: | 308 // Fail early if either of two sanity-checks fail: |
| 456 // 1. There should not yet exist an AudioEntry for the given |stream_id| | 309 // 1. There should not yet exist an AudioOutputDelegate for the given |
| 457 // since the renderer may not create two streams with the same ID. | 310 // |stream_id| since the renderer may not create two streams with the |
| 311 // same ID. |
| 458 // 2. An out-of-range render frame ID was provided. Renderers must *always* | 312 // 2. An out-of-range render frame ID was provided. Renderers must *always* |
| 459 // specify a valid render frame ID for each audio output they create, as | 313 // specify a valid render frame ID for each audio output they create, as |
| 460 // several browser-level features depend on this (e.g., OOM manager, UI | 314 // several browser-level features depend on this (e.g., OOM manager, UI |
| 461 // audio indicator, muting, audio capture). | 315 // audio indicator, muting, audio capture). |
| 462 // Note: media::AudioParameters is validated in the deserializer, so there is | 316 // Note: media::AudioParameters is validated in the deserializer, so there is |
| 463 // no need to check that here. | 317 // no need to check that here. |
| 464 if (LookupById(stream_id)) { | 318 if (LookupById(stream_id)) { |
| 465 SendErrorMessage(stream_id); | 319 SendErrorMessage(stream_id); |
| 466 return; | 320 return; |
| 467 } | 321 } |
| 468 if (render_frame_id <= 0) { | 322 if (render_frame_id <= 0) { |
| 469 SendErrorMessage(stream_id); | 323 SendErrorMessage(stream_id); |
| 470 return; | 324 return; |
| 471 } | 325 } |
| 472 | 326 |
| 473 // Post a task to the UI thread to check that the |render_frame_id| references | 327 // Post a task to the UI thread to check that the |render_frame_id| references |
| 474 // a valid render frame. This validation is important for all the reasons | 328 // a valid render frame. This validation is important for all the reasons |
| 475 // stated in the comments above. This does not block stream creation, but will | 329 // stated in the comments above. This does not block stream creation, but will |
| 476 // force-close the stream later if validation fails. | 330 // force-close the stream later if validation fails. |
| 477 BrowserThread::PostTask( | 331 BrowserThread::PostTask( |
| 478 BrowserThread::UI, FROM_HERE, | 332 BrowserThread::UI, FROM_HERE, |
| 479 base::Bind(validate_render_frame_id_function_, render_process_id_, | 333 base::Bind(validate_render_frame_id_function_, render_process_id_, |
| 480 render_frame_id, | 334 render_frame_id, |
| 481 base::Bind(&AudioRendererHost::DidValidateRenderFrame, this, | 335 base::Bind(&AudioRendererHost::DidValidateRenderFrame, this, |
| 482 stream_id))); | 336 stream_id))); |
| 483 | 337 |
| 484 std::unique_ptr<AudioEntry> entry = AudioEntry::Create( | |
| 485 this, stream_id, render_frame_id, params, device_unique_id); | |
| 486 if (!entry) { | |
| 487 SendErrorMessage(stream_id); | |
| 488 return; | |
| 489 } | |
| 490 | |
| 491 MediaObserver* const media_observer = | 338 MediaObserver* const media_observer = |
| 492 GetContentClient()->browser()->GetMediaObserver(); | 339 GetContentClient()->browser()->GetMediaObserver(); |
| 493 if (media_observer) | |
| 494 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id); | |
| 495 | 340 |
| 496 if (mirroring_manager_) { | 341 MediaInternals* const media_internals = MediaInternals::GetInstance(); |
| 497 mirroring_manager_->AddDiverter( | 342 std::unique_ptr<media::AudioLog> audio_log = media_internals->CreateAudioLog( |
| 498 render_process_id_, entry->render_frame_id(), entry->controller()); | 343 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER); |
| 499 } | 344 media_internals->SetWebContentsTitleForAudioLogEntry( |
| 500 audio_entries_.insert(std::make_pair(stream_id, entry.release())); | 345 stream_id, render_process_id_, render_frame_id, audio_log.get()); |
| 346 delegates_.push_back(AudioOutputDelegate::Create( |
| 347 this, audio_manager_, std::move(audio_log), mirroring_manager_, |
| 348 media_observer, stream_id, render_frame_id, render_process_id_, params, |
| 349 device_unique_id)); |
| 350 |
| 501 g_audio_streams_tracker.Get().IncreaseStreamCount(); | 351 g_audio_streams_tracker.Get().IncreaseStreamCount(); |
| 502 | 352 |
| 503 audio_log_->OnCreated(stream_id, params, device_unique_id); | 353 if (delegates_.size() > max_simultaneous_streams_) |
| 504 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry( | 354 max_simultaneous_streams_ = delegates_.size(); |
| 505 stream_id, render_process_id_, render_frame_id, audio_log_.get()); | |
| 506 | |
| 507 if (audio_entries_.size() > max_simultaneous_streams_) | |
| 508 max_simultaneous_streams_ = audio_entries_.size(); | |
| 509 } | 355 } |
| 510 | 356 |
| 511 void AudioRendererHost::OnPlayStream(int stream_id) { | 357 void AudioRendererHost::OnPlayStream(int stream_id) { |
| 512 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 358 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 513 | 359 |
| 514 AudioEntry* entry = LookupById(stream_id); | 360 AudioOutputDelegate* delegate = LookupById(stream_id); |
| 515 if (!entry) { | 361 if (!delegate) { |
| 516 SendErrorMessage(stream_id); | 362 SendErrorMessage(stream_id); |
| 517 return; | 363 return; |
| 518 } | 364 } |
| 519 | 365 |
| 520 entry->controller()->Play(); | 366 delegate->OnPlayStream(); |
| 521 audio_log_->OnStarted(stream_id); | |
| 522 } | 367 } |
| 523 | 368 |
| 524 void AudioRendererHost::OnPauseStream(int stream_id) { | 369 void AudioRendererHost::OnPauseStream(int stream_id) { |
| 525 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 370 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 526 | 371 |
| 527 AudioEntry* entry = LookupById(stream_id); | 372 AudioOutputDelegate* delegate = LookupById(stream_id); |
| 528 if (!entry) { | 373 if (!delegate) { |
| 529 SendErrorMessage(stream_id); | 374 SendErrorMessage(stream_id); |
| 530 return; | 375 return; |
| 531 } | 376 } |
| 532 | 377 |
| 533 entry->controller()->Pause(); | 378 delegate->OnPauseStream(); |
| 534 audio_log_->OnStopped(stream_id); | |
| 535 } | 379 } |
| 536 | 380 |
| 537 void AudioRendererHost::OnSetVolume(int stream_id, double volume) { | 381 void AudioRendererHost::OnSetVolume(int stream_id, double volume) { |
| 538 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 382 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 539 | 383 |
| 540 AudioEntry* entry = LookupById(stream_id); | 384 AudioOutputDelegate* delegate = LookupById(stream_id); |
| 541 if (!entry) { | 385 if (!delegate) { |
| 542 SendErrorMessage(stream_id); | 386 SendErrorMessage(stream_id); |
| 543 return; | 387 return; |
| 544 } | 388 } |
| 545 | 389 |
| 546 // Make sure the volume is valid. | 390 // Make sure the volume is valid. |
| 547 if (volume < 0 || volume > 1.0) | 391 if (volume < 0 || volume > 1.0) |
| 548 return; | 392 return; |
| 549 entry->controller()->SetVolume(volume); | 393 delegate->OnSetVolume(volume); |
| 550 audio_log_->OnSetVolume(stream_id, volume); | |
| 551 } | 394 } |
| 552 | 395 |
| 553 void AudioRendererHost::SendErrorMessage(int stream_id) { | 396 void AudioRendererHost::SendErrorMessage(int stream_id) { |
| 554 Send(new AudioMsg_NotifyStreamError(stream_id)); | 397 Send(new AudioMsg_NotifyStreamError(stream_id)); |
| 555 } | 398 } |
| 556 | 399 |
| 557 void AudioRendererHost::OnCloseStream(int stream_id) { | 400 void AudioRendererHost::OnCloseStream(int stream_id) { |
| 558 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 401 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 559 authorizations_.erase(stream_id); | 402 authorizations_.erase(stream_id); |
| 560 | 403 |
| 404 auto i = LookupIteratorById(stream_id); |
| 405 |
| 561 // Prevent oustanding callbacks from attempting to close/delete the same | 406 // Prevent oustanding callbacks from attempting to close/delete the same |
| 562 // AudioEntry twice. | 407 // AudioOutputDelegate twice. |
| 563 AudioEntryMap::iterator i = audio_entries_.find(stream_id); | 408 if (i == delegates_.end()) |
| 564 if (i == audio_entries_.end()) | |
| 565 return; | 409 return; |
| 566 std::unique_ptr<AudioEntry> entry(i->second); | 410 |
| 567 audio_entries_.erase(i); | 411 std::swap(*i, delegates_.back()); |
| 412 delegates_.pop_back(); |
| 413 |
| 568 g_audio_streams_tracker.Get().DecreaseStreamCount(); | 414 g_audio_streams_tracker.Get().DecreaseStreamCount(); |
| 569 | |
| 570 media::AudioOutputController* const controller = entry->controller(); | |
| 571 controller->Close( | |
| 572 base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry))); | |
| 573 audio_log_->OnClosed(stream_id); | |
| 574 } | 415 } |
| 575 | 416 |
| 576 void AudioRendererHost::DeleteEntry(std::unique_ptr<AudioEntry> entry) { | 417 AudioRendererHost::AudioOutputDelegateList::iterator |
| 418 AudioRendererHost::LookupIteratorById(int stream_id) { |
| 577 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 419 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 578 | 420 |
| 579 // De-register the controller from the AudioMirroringManager now that the | 421 return std::find_if(delegates_.begin(), delegates_.end(), |
| 580 // controller has closed the AudioOutputStream and shut itself down. This | 422 [stream_id](const AudioOutputDelegate::UniquePtr& d) { |
| 581 // ensures that calling RemoveDiverter() here won't trigger the controller to | 423 return d->stream_id() == stream_id; |
| 582 // re-start the default AudioOutputStream and cause a brief audio blip to come | 424 }); |
| 583 // out the user's speakers. http://crbug.com/474432 | |
| 584 if (mirroring_manager_) | |
| 585 mirroring_manager_->RemoveDiverter(entry->controller()); | |
| 586 | |
| 587 AudioStreamMonitor::StopMonitoringStream( | |
| 588 render_process_id_, entry->render_frame_id(), entry->stream_id()); | |
| 589 UpdateNumPlayingStreams(entry.get(), false); | |
| 590 } | 425 } |
| 591 | 426 |
| 592 void AudioRendererHost::ReportErrorAndClose(int stream_id) { | 427 AudioOutputDelegate* AudioRendererHost::LookupById(int stream_id) { |
| 593 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 428 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 594 | 429 |
| 595 // Make sure this isn't a stray callback executing after the stream has been | 430 auto i = LookupIteratorById(stream_id); |
| 596 // closed, so error notifications aren't sent after clients believe the stream | 431 return i != delegates_.end() ? i->get() : nullptr; |
| 597 // is closed. | |
| 598 if (!LookupById(stream_id)) | |
| 599 return; | |
| 600 | |
| 601 SendErrorMessage(stream_id); | |
| 602 | |
| 603 audio_log_->OnError(stream_id); | |
| 604 OnCloseStream(stream_id); | |
| 605 } | 432 } |
| 606 | 433 |
| 607 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { | 434 void AudioRendererHost::OnStreamStateChanged(bool is_playing) { |
| 608 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 435 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 609 | |
| 610 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id); | |
| 611 return i != audio_entries_.end() ? i->second : NULL; | |
| 612 } | |
| 613 | |
| 614 void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry, | |
| 615 bool is_playing) { | |
| 616 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 617 if (entry->playing() == is_playing) | |
| 618 return; | |
| 619 | |
| 620 if (is_playing) { | 436 if (is_playing) { |
| 621 entry->set_playing(true); | |
| 622 base::AtomicRefCountInc(&num_playing_streams_); | 437 base::AtomicRefCountInc(&num_playing_streams_); |
| 623 | 438 |
| 624 // Inform the RenderProcessHost when audio starts playing for the first | 439 // Inform the RenderProcessHost when audio starts playing for the first |
| 625 // time. | 440 // time. The nonatomic increment-and-read is ok since this is the only |
| 441 // thread that |num_plaing_streams_| may be updated on. |
| 626 if (base::AtomicRefCountIsOne(&num_playing_streams_)) { | 442 if (base::AtomicRefCountIsOne(&num_playing_streams_)) { |
| 627 BrowserThread::PostTask( | 443 BrowserThread::PostTask( |
| 628 BrowserThread::UI, FROM_HERE, | 444 BrowserThread::UI, FROM_HERE, |
| 629 base::Bind(&NotifyRenderProcessHostThatAudioStateChanged, | 445 base::Bind(&NotifyRenderProcessHostThatAudioStateChanged, |
| 630 render_process_id_)); | 446 render_process_id_)); |
| 631 } | 447 } |
| 632 } else { | 448 } else { |
| 633 entry->set_playing(false); | |
| 634 // Inform the RenderProcessHost when there is no more audio playing. | 449 // Inform the RenderProcessHost when there is no more audio playing. |
| 635 if (!base::AtomicRefCountDec(&num_playing_streams_)) { | 450 if (!base::AtomicRefCountDec(&num_playing_streams_)) { |
| 636 BrowserThread::PostTask( | 451 BrowserThread::PostTask( |
| 637 BrowserThread::UI, FROM_HERE, | 452 BrowserThread::UI, FROM_HERE, |
| 638 base::Bind(&NotifyRenderProcessHostThatAudioStateChanged, | 453 base::Bind(&NotifyRenderProcessHostThatAudioStateChanged, |
| 639 render_process_id_)); | 454 render_process_id_)); |
| 640 } | 455 } |
| 641 } | 456 } |
| 642 } | 457 } |
| 643 | 458 |
| 644 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { | 459 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { |
| 645 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 460 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 646 return authorizations_.find(stream_id) != authorizations_.end(); | 461 return authorizations_.find(stream_id) != authorizations_.end(); |
| 647 } | 462 } |
| 648 | 463 |
| 649 bool AudioRendererHost::HasActiveAudio() { | 464 bool AudioRendererHost::HasActiveAudio() { |
| 650 return !base::AtomicRefCountIsZero(&num_playing_streams_); | 465 return !base::AtomicRefCountIsZero(&num_playing_streams_); |
| 651 } | 466 } |
| 652 | 467 |
| 653 void AudioRendererHost::OverrideDevicePermissionsForTesting(bool has_access) { | 468 void AudioRendererHost::OverrideDevicePermissionsForTesting(bool has_access) { |
| 654 authorization_handler_.OverridePermissionsForTesting(has_access); | 469 authorization_handler_.OverridePermissionsForTesting(has_access); |
| 655 } | 470 } |
| 656 } // namespace content | 471 } // namespace content |
| OLD | NEW |