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