Add long running gmail memory benchmark for background tab.
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_renderer_host.cc
blobdddeee21626a31f30aff5b4f749c396fcd5024b8
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
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/media/audio_renderer_host.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/logging.h"
10 #include "base/memory/shared_memory.h"
11 #include "base/metrics/histogram.h"
12 #include "base/process/process.h"
13 #include "content/browser/bad_message.h"
14 #include "content/browser/browser_main_loop.h"
15 #include "content/browser/child_process_security_policy_impl.h"
16 #include "content/browser/loader/resource_dispatcher_host_impl.h"
17 #include "content/browser/media/audio_stream_monitor.h"
18 #include "content/browser/media/capture/audio_mirroring_manager.h"
19 #include "content/browser/media/media_internals.h"
20 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
21 #include "content/browser/renderer_host/media/audio_sync_reader.h"
22 #include "content/browser/renderer_host/media/media_stream_manager.h"
23 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
24 #include "content/browser/renderer_host/render_widget_host_impl.h"
25 #include "content/common/media/audio_messages.h"
26 #include "content/public/browser/content_browser_client.h"
27 #include "content/public/browser/media_device_id.h"
28 #include "content/public/browser/media_observer.h"
29 #include "content/public/browser/render_frame_host.h"
30 #include "content/public/browser/render_view_host.h"
31 #include "content/public/common/content_switches.h"
32 #include "media/audio/audio_device_name.h"
33 #include "media/audio/audio_manager_base.h"
34 #include "media/base/audio_bus.h"
35 #include "media/base/limits.h"
37 using media::AudioBus;
38 using media::AudioManager;
40 namespace content {
42 namespace {
43 // TODO(aiolos): This is a temporary hack until the resource scheduler is
44 // migrated to RenderFrames for the Site Isolation project. It's called in
45 // response to low frequency playback state changes. http://crbug.com/472869
46 int RenderFrameIdToRenderViewId(int render_process_id, int render_frame_id) {
47 DCHECK_CURRENTLY_ON(BrowserThread::UI);
48 RenderFrameHost* const frame =
49 RenderFrameHost::FromID(render_process_id, render_frame_id);
50 return frame ? frame->GetRenderViewHost()->GetRoutingID() : MSG_ROUTING_NONE;
53 void NotifyResourceDispatcherOfAudioStateChange(int render_process_id,
54 bool is_playing,
55 int render_view_id) {
56 DCHECK_CURRENTLY_ON(BrowserThread::IO);
57 if (render_view_id == MSG_ROUTING_NONE || !ResourceDispatcherHostImpl::Get())
58 return;
60 ResourceDispatcherHostImpl::Get()->OnAudioRenderHostStreamStateChanged(
61 render_process_id, render_view_id, is_playing);
64 } // namespace
66 class AudioRendererHost::AudioEntry
67 : public media::AudioOutputController::EventHandler {
68 public:
69 AudioEntry(AudioRendererHost* host,
70 int stream_id,
71 int render_frame_id,
72 const media::AudioParameters& params,
73 const std::string& output_device_id,
74 scoped_ptr<base::SharedMemory> shared_memory,
75 scoped_ptr<media::AudioOutputController::SyncReader> reader);
76 ~AudioEntry() override;
78 int stream_id() const {
79 return stream_id_;
82 int render_frame_id() const { return render_frame_id_; }
84 media::AudioOutputController* controller() const { return controller_.get(); }
86 base::SharedMemory* shared_memory() {
87 return shared_memory_.get();
90 media::AudioOutputController::SyncReader* reader() const {
91 return reader_.get();
94 bool playing() const { return playing_; }
95 void set_playing(bool playing) { playing_ = playing; }
97 private:
98 // media::AudioOutputController::EventHandler implementation.
99 void OnCreated() override;
100 void OnPlaying() override;
101 void OnPaused() override;
102 void OnError() override;
104 AudioRendererHost* const host_;
105 const int stream_id_;
107 // The routing ID of the source RenderFrame.
108 const int render_frame_id_;
110 // Shared memory for transmission of the audio data. Used by |reader_|.
111 const scoped_ptr<base::SharedMemory> shared_memory_;
113 // The synchronous reader to be used by |controller_|.
114 const scoped_ptr<media::AudioOutputController::SyncReader> reader_;
116 // The AudioOutputController that manages the audio stream.
117 const scoped_refptr<media::AudioOutputController> controller_;
119 bool playing_;
122 AudioRendererHost::AudioEntry::AudioEntry(
123 AudioRendererHost* host,
124 int stream_id,
125 int render_frame_id,
126 const media::AudioParameters& params,
127 const std::string& output_device_id,
128 scoped_ptr<base::SharedMemory> shared_memory,
129 scoped_ptr<media::AudioOutputController::SyncReader> reader)
130 : host_(host),
131 stream_id_(stream_id),
132 render_frame_id_(render_frame_id),
133 shared_memory_(shared_memory.Pass()),
134 reader_(reader.Pass()),
135 controller_(media::AudioOutputController::Create(host->audio_manager_,
136 this,
137 params,
138 output_device_id,
139 reader_.get())),
140 playing_(false) {
141 DCHECK(controller_.get());
144 AudioRendererHost::AudioEntry::~AudioEntry() {}
146 ///////////////////////////////////////////////////////////////////////////////
147 // AudioRendererHost implementations.
149 AudioRendererHost::AudioRendererHost(
150 int render_process_id,
151 media::AudioManager* audio_manager,
152 AudioMirroringManager* mirroring_manager,
153 MediaInternals* media_internals,
154 MediaStreamManager* media_stream_manager,
155 const ResourceContext::SaltCallback& salt_callback)
156 : BrowserMessageFilter(AudioMsgStart),
157 render_process_id_(render_process_id),
158 audio_manager_(audio_manager),
159 mirroring_manager_(mirroring_manager),
160 audio_log_(media_internals->CreateAudioLog(
161 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)),
162 media_stream_manager_(media_stream_manager),
163 num_playing_streams_(0),
164 salt_callback_(salt_callback) {
165 DCHECK(audio_manager_);
166 DCHECK(media_stream_manager_);
169 AudioRendererHost::~AudioRendererHost() {
170 DCHECK(audio_entries_.empty());
173 void AudioRendererHost::GetOutputControllers(
174 const RenderProcessHost::GetAudioOutputControllersCallback&
175 callback) const {
176 BrowserThread::PostTaskAndReplyWithResult(
177 BrowserThread::IO, FROM_HERE,
178 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback);
181 void AudioRendererHost::OnChannelClosing() {
182 // Since the IPC sender is gone, close all requested audio streams.
183 while (!audio_entries_.empty()) {
184 // Note: OnCloseStream() removes the entries from audio_entries_.
185 OnCloseStream(audio_entries_.begin()->first);
189 void AudioRendererHost::OnDestruct() const {
190 BrowserThread::DeleteOnIOThread::Destruct(this);
193 void AudioRendererHost::AudioEntry::OnCreated() {
194 BrowserThread::PostTask(
195 BrowserThread::IO,
196 FROM_HERE,
197 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_));
200 void AudioRendererHost::AudioEntry::OnPlaying() {
201 BrowserThread::PostTask(
202 BrowserThread::IO,
203 FROM_HERE,
204 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
205 host_,
206 stream_id_,
207 true));
210 void AudioRendererHost::AudioEntry::OnPaused() {
211 BrowserThread::PostTask(
212 BrowserThread::IO,
213 FROM_HERE,
214 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
215 host_,
216 stream_id_,
217 false));
220 void AudioRendererHost::AudioEntry::OnError() {
221 BrowserThread::PostTask(
222 BrowserThread::IO,
223 FROM_HERE,
224 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_));
227 void AudioRendererHost::DoCompleteCreation(int stream_id) {
228 DCHECK_CURRENTLY_ON(BrowserThread::IO);
230 if (!PeerHandle()) {
231 DLOG(WARNING) << "Renderer process handle is invalid.";
232 ReportErrorAndClose(stream_id);
233 return;
236 AudioEntry* const entry = LookupById(stream_id);
237 if (!entry) {
238 ReportErrorAndClose(stream_id);
239 return;
242 // Once the audio stream is created then complete the creation process by
243 // mapping shared memory and sharing with the renderer process.
244 base::SharedMemoryHandle foreign_memory_handle;
245 if (!entry->shared_memory()->ShareToProcess(PeerHandle(),
246 &foreign_memory_handle)) {
247 // If we failed to map and share the shared memory then close the audio
248 // stream and send an error message.
249 ReportErrorAndClose(entry->stream_id());
250 return;
253 AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader());
255 base::SyncSocket::TransitDescriptor socket_descriptor;
257 // If we failed to prepare the sync socket for the renderer then we fail
258 // the construction of audio stream.
259 if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) {
260 ReportErrorAndClose(entry->stream_id());
261 return;
264 Send(new AudioMsg_NotifyStreamCreated(
265 entry->stream_id(), foreign_memory_handle, socket_descriptor,
266 entry->shared_memory()->requested_size()));
269 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
270 bool is_playing) {
271 DCHECK_CURRENTLY_ON(BrowserThread::IO);
273 AudioEntry* const entry = LookupById(stream_id);
274 if (!entry)
275 return;
277 Send(new AudioMsg_NotifyStreamStateChanged(
278 stream_id,
279 is_playing ? media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING
280 : media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED));
282 if (is_playing) {
283 AudioStreamMonitor::StartMonitoringStream(
284 render_process_id_,
285 entry->render_frame_id(),
286 entry->stream_id(),
287 base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip,
288 entry->controller()));
289 } else {
290 AudioStreamMonitor::StopMonitoringStream(
291 render_process_id_, entry->render_frame_id(), entry->stream_id());
293 UpdateNumPlayingStreams(entry, is_playing);
296 RenderProcessHost::AudioOutputControllerList
297 AudioRendererHost::DoGetOutputControllers() const {
298 DCHECK_CURRENTLY_ON(BrowserThread::IO);
300 RenderProcessHost::AudioOutputControllerList controllers;
301 for (AudioEntryMap::const_iterator it = audio_entries_.begin();
302 it != audio_entries_.end();
303 ++it) {
304 controllers.push_back(it->second->controller());
307 return controllers;
310 ///////////////////////////////////////////////////////////////////////////////
311 // IPC Messages handler
312 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
313 bool handled = true;
314 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message)
315 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
316 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
317 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
318 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
319 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
320 IPC_MESSAGE_HANDLER(AudioHostMsg_SwitchOutputDevice, OnSwitchOutputDevice)
321 IPC_MESSAGE_UNHANDLED(handled = false)
322 IPC_END_MESSAGE_MAP()
324 return handled;
327 void AudioRendererHost::OnCreateStream(int stream_id,
328 int render_frame_id,
329 int session_id,
330 const media::AudioParameters& params) {
331 DCHECK_CURRENTLY_ON(BrowserThread::IO);
333 DVLOG(1) << "AudioRendererHost@" << this
334 << "::OnCreateStream(stream_id=" << stream_id
335 << ", render_frame_id=" << render_frame_id
336 << ", session_id=" << session_id << ")";
337 DCHECK_GT(render_frame_id, 0);
339 // media::AudioParameters is validated in the deserializer.
340 if (LookupById(stream_id) != NULL) {
341 SendErrorMessage(stream_id);
342 return;
345 // Initialize the |output_device_id| to an empty string which indicates that
346 // the default device should be used. If a StreamDeviceInfo instance was found
347 // though, then we use the matched output device.
348 std::string output_device_id;
349 const StreamDeviceInfo* info = media_stream_manager_->
350 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
351 if (info)
352 output_device_id = info->device.matched_output_device_id;
354 // Create the shared memory and share with the renderer process.
355 uint32 shared_memory_size = AudioBus::CalculateMemorySize(params);
356 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
357 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
358 SendErrorMessage(stream_id);
359 return;
362 scoped_ptr<AudioSyncReader> reader(
363 new AudioSyncReader(shared_memory.get(), params));
364 if (!reader->Init()) {
365 SendErrorMessage(stream_id);
366 return;
369 MediaObserver* const media_observer =
370 GetContentClient()->browser()->GetMediaObserver();
371 if (media_observer)
372 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
374 scoped_ptr<AudioEntry> entry(new AudioEntry(this,
375 stream_id,
376 render_frame_id,
377 params,
378 output_device_id,
379 shared_memory.Pass(),
380 reader.Pass()));
381 if (mirroring_manager_) {
382 mirroring_manager_->AddDiverter(
383 render_process_id_, entry->render_frame_id(), entry->controller());
385 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
386 audio_log_->OnCreated(stream_id, params, output_device_id);
387 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry(
388 stream_id, render_process_id_, render_frame_id, audio_log_.get());
391 void AudioRendererHost::OnPlayStream(int stream_id) {
392 DCHECK_CURRENTLY_ON(BrowserThread::IO);
394 AudioEntry* entry = LookupById(stream_id);
395 if (!entry) {
396 SendErrorMessage(stream_id);
397 return;
400 entry->controller()->Play();
401 audio_log_->OnStarted(stream_id);
404 void AudioRendererHost::OnPauseStream(int stream_id) {
405 DCHECK_CURRENTLY_ON(BrowserThread::IO);
407 AudioEntry* entry = LookupById(stream_id);
408 if (!entry) {
409 SendErrorMessage(stream_id);
410 return;
413 entry->controller()->Pause();
414 audio_log_->OnStopped(stream_id);
417 void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
418 DCHECK_CURRENTLY_ON(BrowserThread::IO);
420 AudioEntry* entry = LookupById(stream_id);
421 if (!entry) {
422 SendErrorMessage(stream_id);
423 return;
426 // Make sure the volume is valid.
427 if (volume < 0 || volume > 1.0)
428 return;
429 entry->controller()->SetVolume(volume);
430 audio_log_->OnSetVolume(stream_id, volume);
433 void AudioRendererHost::OnSwitchOutputDevice(int stream_id,
434 int render_frame_id,
435 const std::string& device_id,
436 const GURL& security_origin,
437 int request_id) {
438 DCHECK_CURRENTLY_ON(BrowserThread::IO);
439 DVLOG(1) << "AudioRendererHost@" << this
440 << "::OnSwitchOutputDevice(stream_id=" << stream_id
441 << ", render_frame_id=" << render_frame_id
442 << ", device_id=" << device_id
443 << ", security_origin=" << security_origin
444 << ", request_id=" << request_id << ")";
445 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
446 render_process_id_, security_origin)) {
447 content::bad_message::ReceivedBadMessage(this,
448 bad_message::ARH_UNAUTHORIZED_URL);
449 return;
452 if (device_id.empty()) {
453 DVLOG(1) << __FUNCTION__ << ": default output device requested. "
454 << "No permissions check or device translation/validation needed.";
455 DoSwitchOutputDevice(stream_id, device_id, request_id);
456 } else {
457 // Check that MediaStream device permissions have been granted,
458 // hence the use of a MediaStreamUIProxy.
459 scoped_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create();
461 // Use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT
462 // because MediaStreamUIProxy::CheckAccess does not currently support
463 // MEDIA_DEVICE_AUDIO_OUTPUT.
464 // TODO(guidou): Change to MEDIA_DEVICE_AUDIO_OUTPUT when support becomes
465 // available. http://crbug.com/498675
466 ui_proxy->CheckAccess(
467 security_origin, MEDIA_DEVICE_AUDIO_CAPTURE,
468 render_process_id_, render_frame_id,
469 base::Bind(&AudioRendererHost::OutputDeviceAccessChecked, this,
470 base::Passed(&ui_proxy), stream_id, device_id,
471 security_origin, render_frame_id, request_id));
475 void AudioRendererHost::OutputDeviceAccessChecked(
476 scoped_ptr<MediaStreamUIProxy> ui_proxy,
477 int stream_id,
478 const std::string& device_id,
479 const GURL& security_origin,
480 int render_frame_id,
481 int request_id,
482 bool have_access) {
483 DCHECK_CURRENTLY_ON(BrowserThread::IO);
484 DVLOG(1) << __FUNCTION__;
485 if (!have_access) {
486 DVLOG(0) << __FUNCTION__
487 << ": Have no access to media devices. Not switching device.";
488 Send(new AudioMsg_NotifyOutputDeviceSwitched(
489 stream_id, request_id,
490 media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_AUTHORIZED));
491 return;
494 scoped_refptr<base::SingleThreadTaskRunner> audio_worker_runner =
495 AudioManager::Get()->GetWorkerTaskRunner();
496 audio_worker_runner->PostTask(
497 FROM_HERE,
498 base::Bind(&AudioRendererHost::StartTranslateOutputDeviceName, this,
499 stream_id, device_id, security_origin, request_id));
502 void AudioRendererHost::StartTranslateOutputDeviceName(
503 int stream_id,
504 const std::string& device_id,
505 const GURL& security_origin,
506 int request_id) {
507 DCHECK(AudioManager::Get()->GetWorkerTaskRunner()->BelongsToCurrentThread());
508 DCHECK(!device_id.empty());
509 DVLOG(1) << __FUNCTION__;
511 media::AudioDeviceNames* device_names(new media::AudioDeviceNames);
512 AudioManager::Get()->GetAudioOutputDeviceNames(device_names);
514 BrowserThread::PostTask(
515 BrowserThread::IO, FROM_HERE,
516 base::Bind(&AudioRendererHost::FinishTranslateOutputDeviceName, this,
517 stream_id, device_id, security_origin, request_id,
518 base::Owned(device_names)));
521 void AudioRendererHost::FinishTranslateOutputDeviceName(
522 int stream_id,
523 const std::string& device_id,
524 const GURL& security_origin,
525 int request_id,
526 media::AudioDeviceNames* device_names) {
527 DCHECK_CURRENTLY_ON(BrowserThread::IO);
528 DCHECK(!device_id.empty());
529 DVLOG(1) << __FUNCTION__;
531 std::string raw_device_id;
532 // Process the enumeration here because |salt_callback_| can run
533 // only on the IO thread
534 for (const auto& device_name : *device_names) {
535 const std::string candidate_device_id = content::GetHMACForMediaDeviceID(
536 salt_callback_, security_origin, device_name.unique_id);
537 if (candidate_device_id == device_id) {
538 DVLOG(1) << "Requested device " << device_name.unique_id << " - "
539 << device_name.device_name;
540 raw_device_id = device_name.unique_id;
544 if (raw_device_id.empty()) {
545 DVLOG(1) << "Requested device " << device_id << " could not be found.";
546 Send(new AudioMsg_NotifyOutputDeviceSwitched(
547 stream_id, request_id,
548 media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_FOUND));
549 return;
552 DoSwitchOutputDevice(stream_id, raw_device_id, request_id);
555 void AudioRendererHost::DoSwitchOutputDevice(int stream_id,
556 const std::string& raw_device_id,
557 int request_id) {
558 DCHECK_CURRENTLY_ON(BrowserThread::IO);
559 DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << raw_device_id << ", "
560 << request_id << ")";
561 AudioEntry* entry = LookupById(stream_id);
562 if (!entry) {
563 Send(new AudioMsg_NotifyOutputDeviceSwitched(
564 stream_id, request_id,
565 media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_OBSOLETE));
566 return;
569 entry->controller()->SwitchOutputDevice(
570 raw_device_id, base::Bind(&AudioRendererHost::DoOutputDeviceSwitched,
571 this, stream_id, request_id));
572 audio_log_->OnSwitchOutputDevice(entry->stream_id(), raw_device_id);
575 void AudioRendererHost::DoOutputDeviceSwitched(int stream_id, int request_id) {
576 DCHECK_CURRENTLY_ON(BrowserThread::IO);
577 DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << request_id << ")";
578 Send(new AudioMsg_NotifyOutputDeviceSwitched(
579 stream_id, request_id, media::SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS));
582 void AudioRendererHost::SendErrorMessage(int stream_id) {
583 Send(new AudioMsg_NotifyStreamStateChanged(
584 stream_id, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR));
587 void AudioRendererHost::OnCloseStream(int stream_id) {
588 DCHECK_CURRENTLY_ON(BrowserThread::IO);
590 // Prevent oustanding callbacks from attempting to close/delete the same
591 // AudioEntry twice.
592 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
593 if (i == audio_entries_.end())
594 return;
595 scoped_ptr<AudioEntry> entry(i->second);
596 audio_entries_.erase(i);
598 media::AudioOutputController* const controller = entry->controller();
599 controller->Close(
600 base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry)));
601 audio_log_->OnClosed(stream_id);
604 void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
605 DCHECK_CURRENTLY_ON(BrowserThread::IO);
607 // De-register the controller from the AudioMirroringManager now that the
608 // controller has closed the AudioOutputStream and shut itself down. This
609 // ensures that calling RemoveDiverter() here won't trigger the controller to
610 // re-start the default AudioOutputStream and cause a brief audio blip to come
611 // out the user's speakers. http://crbug.com/474432
612 if (mirroring_manager_)
613 mirroring_manager_->RemoveDiverter(entry->controller());
615 AudioStreamMonitor::StopMonitoringStream(
616 render_process_id_, entry->render_frame_id(), entry->stream_id());
617 UpdateNumPlayingStreams(entry.get(), false);
620 void AudioRendererHost::ReportErrorAndClose(int stream_id) {
621 DCHECK_CURRENTLY_ON(BrowserThread::IO);
623 // Make sure this isn't a stray callback executing after the stream has been
624 // closed, so error notifications aren't sent after clients believe the stream
625 // is closed.
626 if (!LookupById(stream_id))
627 return;
629 SendErrorMessage(stream_id);
631 audio_log_->OnError(stream_id);
632 OnCloseStream(stream_id);
635 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
636 DCHECK_CURRENTLY_ON(BrowserThread::IO);
638 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id);
639 return i != audio_entries_.end() ? i->second : NULL;
642 void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry,
643 bool is_playing) {
644 DCHECK_CURRENTLY_ON(BrowserThread::IO);
645 if (entry->playing() == is_playing)
646 return;
648 bool should_alert_resource_scheduler;
649 if (is_playing) {
650 should_alert_resource_scheduler =
651 !RenderFrameHasActiveAudio(entry->render_frame_id());
652 entry->set_playing(true);
653 base::AtomicRefCountInc(&num_playing_streams_);
654 } else {
655 entry->set_playing(false);
656 should_alert_resource_scheduler =
657 !RenderFrameHasActiveAudio(entry->render_frame_id());
658 base::AtomicRefCountDec(&num_playing_streams_);
661 if (should_alert_resource_scheduler && ResourceDispatcherHostImpl::Get()) {
662 BrowserThread::PostTaskAndReplyWithResult(
663 BrowserThread::UI, FROM_HERE,
664 base::Bind(&RenderFrameIdToRenderViewId, render_process_id_,
665 entry->render_frame_id()),
666 base::Bind(&NotifyResourceDispatcherOfAudioStateChange,
667 render_process_id_, is_playing));
671 bool AudioRendererHost::HasActiveAudio() {
672 return !base::AtomicRefCountIsZero(&num_playing_streams_);
675 bool AudioRendererHost::RenderFrameHasActiveAudio(int render_frame_id) const {
676 for (AudioEntryMap::const_iterator it = audio_entries_.begin();
677 it != audio_entries_.end();
678 ++it) {
679 AudioEntry* entry = it->second;
680 if (entry->render_frame_id() == render_frame_id && entry->playing())
681 return true;
683 return false;
686 } // namespace content