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"
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/browser_main_loop.h"
14 #include "content/browser/loader/resource_dispatcher_host_impl.h"
15 #include "content/browser/media/audio_stream_monitor.h"
16 #include "content/browser/media/capture/audio_mirroring_manager.h"
17 #include "content/browser/media/media_internals.h"
18 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
19 #include "content/browser/renderer_host/media/audio_sync_reader.h"
20 #include "content/browser/renderer_host/media/media_stream_manager.h"
21 #include "content/browser/renderer_host/render_widget_host_impl.h"
22 #include "content/common/media/audio_messages.h"
23 #include "content/public/browser/content_browser_client.h"
24 #include "content/public/browser/media_observer.h"
25 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/render_view_host.h"
27 #include "content/public/common/content_switches.h"
28 #include "media/audio/audio_manager_base.h"
29 #include "media/base/audio_bus.h"
30 #include "media/base/limits.h"
32 using media::AudioBus
;
33 using media::AudioManager
;
38 // TODO(aiolos): This is a temporary hack until the resource scheduler is
39 // migrated to RenderFrames for the Site Isolation project. It's called in
40 // response to low frequency playback state changes. http://crbug.com/472869
41 int RenderFrameIdToRenderViewId(int render_process_id
, int render_frame_id
) {
42 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
43 RenderFrameHost
* const frame
=
44 RenderFrameHost::FromID(render_process_id
, render_frame_id
);
45 return frame
? frame
->GetRenderViewHost()->GetRoutingID() : MSG_ROUTING_NONE
;
48 void NotifyResourceDispatcherOfAudioStateChange(int render_process_id
,
51 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
52 if (render_view_id
== MSG_ROUTING_NONE
|| !ResourceDispatcherHostImpl::Get())
55 ResourceDispatcherHostImpl::Get()->OnAudioRenderHostStreamStateChanged(
56 render_process_id
, render_view_id
, is_playing
);
61 class AudioRendererHost::AudioEntry
62 : public media::AudioOutputController::EventHandler
{
64 AudioEntry(AudioRendererHost
* host
,
67 const media::AudioParameters
& params
,
68 const std::string
& output_device_id
,
69 scoped_ptr
<base::SharedMemory
> shared_memory
,
70 scoped_ptr
<media::AudioOutputController::SyncReader
> reader
);
71 ~AudioEntry() override
;
73 int stream_id() const {
77 int render_frame_id() const { return render_frame_id_
; }
79 media::AudioOutputController
* controller() const { return controller_
.get(); }
81 base::SharedMemory
* shared_memory() {
82 return shared_memory_
.get();
85 media::AudioOutputController::SyncReader
* reader() const {
89 bool playing() const { return playing_
; }
90 void set_playing(bool playing
) { playing_
= playing
; }
93 // media::AudioOutputController::EventHandler implementation.
94 void OnCreated() override
;
95 void OnPlaying() override
;
96 void OnPaused() override
;
97 void OnError() override
;
99 AudioRendererHost
* const host_
;
100 const int stream_id_
;
102 // The routing ID of the source RenderFrame.
103 const int render_frame_id_
;
105 // Shared memory for transmission of the audio data. Used by |reader_|.
106 const scoped_ptr
<base::SharedMemory
> shared_memory_
;
108 // The synchronous reader to be used by |controller_|.
109 const scoped_ptr
<media::AudioOutputController::SyncReader
> reader_
;
111 // The AudioOutputController that manages the audio stream.
112 const scoped_refptr
<media::AudioOutputController
> controller_
;
117 AudioRendererHost::AudioEntry::AudioEntry(
118 AudioRendererHost
* host
,
121 const media::AudioParameters
& params
,
122 const std::string
& output_device_id
,
123 scoped_ptr
<base::SharedMemory
> shared_memory
,
124 scoped_ptr
<media::AudioOutputController::SyncReader
> reader
)
126 stream_id_(stream_id
),
127 render_frame_id_(render_frame_id
),
128 shared_memory_(shared_memory
.Pass()),
129 reader_(reader
.Pass()),
130 controller_(media::AudioOutputController::Create(host
->audio_manager_
,
136 DCHECK(controller_
.get());
139 AudioRendererHost::AudioEntry::~AudioEntry() {}
141 ///////////////////////////////////////////////////////////////////////////////
142 // AudioRendererHost implementations.
144 AudioRendererHost::AudioRendererHost(
145 int render_process_id
,
146 media::AudioManager
* audio_manager
,
147 AudioMirroringManager
* mirroring_manager
,
148 MediaInternals
* media_internals
,
149 MediaStreamManager
* media_stream_manager
)
150 : BrowserMessageFilter(AudioMsgStart
),
151 render_process_id_(render_process_id
),
152 audio_manager_(audio_manager
),
153 mirroring_manager_(mirroring_manager
),
154 audio_log_(media_internals
->CreateAudioLog(
155 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER
)),
156 media_stream_manager_(media_stream_manager
),
157 num_playing_streams_(0) {
158 DCHECK(audio_manager_
);
159 DCHECK(media_stream_manager_
);
162 AudioRendererHost::~AudioRendererHost() {
163 DCHECK(audio_entries_
.empty());
166 void AudioRendererHost::GetOutputControllers(
167 const RenderProcessHost::GetAudioOutputControllersCallback
&
169 BrowserThread::PostTaskAndReplyWithResult(
170 BrowserThread::IO
, FROM_HERE
,
171 base::Bind(&AudioRendererHost::DoGetOutputControllers
, this), callback
);
174 void AudioRendererHost::OnChannelClosing() {
175 // Since the IPC sender is gone, close all requested audio streams.
176 while (!audio_entries_
.empty()) {
177 // Note: OnCloseStream() removes the entries from audio_entries_.
178 OnCloseStream(audio_entries_
.begin()->first
);
182 void AudioRendererHost::OnDestruct() const {
183 BrowserThread::DeleteOnIOThread::Destruct(this);
186 void AudioRendererHost::AudioEntry::OnCreated() {
187 BrowserThread::PostTask(
190 base::Bind(&AudioRendererHost::DoCompleteCreation
, host_
, stream_id_
));
193 void AudioRendererHost::AudioEntry::OnPlaying() {
194 BrowserThread::PostTask(
197 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged
,
203 void AudioRendererHost::AudioEntry::OnPaused() {
204 BrowserThread::PostTask(
207 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged
,
213 void AudioRendererHost::AudioEntry::OnError() {
214 BrowserThread::PostTask(
217 base::Bind(&AudioRendererHost::ReportErrorAndClose
, host_
, stream_id_
));
220 void AudioRendererHost::DoCompleteCreation(int stream_id
) {
221 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
224 DLOG(WARNING
) << "Renderer process handle is invalid.";
225 ReportErrorAndClose(stream_id
);
229 AudioEntry
* const entry
= LookupById(stream_id
);
231 ReportErrorAndClose(stream_id
);
235 // Once the audio stream is created then complete the creation process by
236 // mapping shared memory and sharing with the renderer process.
237 base::SharedMemoryHandle foreign_memory_handle
;
238 if (!entry
->shared_memory()->ShareToProcess(PeerHandle(),
239 &foreign_memory_handle
)) {
240 // If we failed to map and share the shared memory then close the audio
241 // stream and send an error message.
242 ReportErrorAndClose(entry
->stream_id());
246 AudioSyncReader
* reader
= static_cast<AudioSyncReader
*>(entry
->reader());
248 base::SyncSocket::TransitDescriptor socket_descriptor
;
250 // If we failed to prepare the sync socket for the renderer then we fail
251 // the construction of audio stream.
252 if (!reader
->PrepareForeignSocket(PeerHandle(), &socket_descriptor
)) {
253 ReportErrorAndClose(entry
->stream_id());
257 Send(new AudioMsg_NotifyStreamCreated(
258 entry
->stream_id(), foreign_memory_handle
, socket_descriptor
,
259 entry
->shared_memory()->requested_size()));
262 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id
,
264 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
266 AudioEntry
* const entry
= LookupById(stream_id
);
270 Send(new AudioMsg_NotifyStreamStateChanged(
272 is_playing
? media::AudioOutputIPCDelegate::kPlaying
273 : media::AudioOutputIPCDelegate::kPaused
));
276 AudioStreamMonitor::StartMonitoringStream(
278 entry
->render_frame_id(),
280 base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip
,
281 entry
->controller()));
283 AudioStreamMonitor::StopMonitoringStream(
284 render_process_id_
, entry
->render_frame_id(), entry
->stream_id());
286 UpdateNumPlayingStreams(entry
, is_playing
);
289 RenderProcessHost::AudioOutputControllerList
290 AudioRendererHost::DoGetOutputControllers() const {
291 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
293 RenderProcessHost::AudioOutputControllerList controllers
;
294 for (AudioEntryMap::const_iterator it
= audio_entries_
.begin();
295 it
!= audio_entries_
.end();
297 controllers
.push_back(it
->second
->controller());
303 ///////////////////////////////////////////////////////////////////////////////
304 // IPC Messages handler
305 bool AudioRendererHost::OnMessageReceived(const IPC::Message
& message
) {
307 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost
, message
)
308 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream
, OnCreateStream
)
309 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream
, OnPlayStream
)
310 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream
, OnPauseStream
)
311 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream
, OnCloseStream
)
312 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume
, OnSetVolume
)
313 IPC_MESSAGE_UNHANDLED(handled
= false)
314 IPC_END_MESSAGE_MAP()
319 void AudioRendererHost::OnCreateStream(int stream_id
,
322 const media::AudioParameters
& params
) {
323 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
325 DVLOG(1) << "AudioRendererHost@" << this
326 << "::OnCreateStream(stream_id=" << stream_id
327 << ", render_frame_id=" << render_frame_id
328 << ", session_id=" << session_id
<< ")";
329 DCHECK_GT(render_frame_id
, 0);
331 // media::AudioParameters is validated in the deserializer.
332 if (LookupById(stream_id
) != NULL
) {
333 SendErrorMessage(stream_id
);
337 // Initialize the |output_device_id| to an empty string which indicates that
338 // the default device should be used. If a StreamDeviceInfo instance was found
339 // though, then we use the matched output device.
340 std::string output_device_id
;
341 const StreamDeviceInfo
* info
= media_stream_manager_
->
342 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id
);
344 output_device_id
= info
->device
.matched_output_device_id
;
346 // Create the shared memory and share with the renderer process.
347 uint32 shared_memory_size
= AudioBus::CalculateMemorySize(params
);
348 scoped_ptr
<base::SharedMemory
> shared_memory(new base::SharedMemory());
349 if (!shared_memory
->CreateAndMapAnonymous(shared_memory_size
)) {
350 SendErrorMessage(stream_id
);
354 scoped_ptr
<AudioSyncReader
> reader(
355 new AudioSyncReader(shared_memory
.get(), params
));
356 if (!reader
->Init()) {
357 SendErrorMessage(stream_id
);
361 MediaObserver
* const media_observer
=
362 GetContentClient()->browser()->GetMediaObserver();
364 media_observer
->OnCreatingAudioStream(render_process_id_
, render_frame_id
);
366 scoped_ptr
<AudioEntry
> entry(new AudioEntry(this,
371 shared_memory
.Pass(),
373 if (mirroring_manager_
) {
374 mirroring_manager_
->AddDiverter(
375 render_process_id_
, entry
->render_frame_id(), entry
->controller());
377 audio_entries_
.insert(std::make_pair(stream_id
, entry
.release()));
378 audio_log_
->OnCreated(stream_id
, params
, output_device_id
);
379 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry(
380 stream_id
, render_process_id_
, render_frame_id
, audio_log_
.get());
383 void AudioRendererHost::OnPlayStream(int stream_id
) {
384 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
386 AudioEntry
* entry
= LookupById(stream_id
);
388 SendErrorMessage(stream_id
);
392 entry
->controller()->Play();
393 audio_log_
->OnStarted(stream_id
);
396 void AudioRendererHost::OnPauseStream(int stream_id
) {
397 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
399 AudioEntry
* entry
= LookupById(stream_id
);
401 SendErrorMessage(stream_id
);
405 entry
->controller()->Pause();
406 audio_log_
->OnStopped(stream_id
);
409 void AudioRendererHost::OnSetVolume(int stream_id
, double volume
) {
410 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
412 AudioEntry
* entry
= LookupById(stream_id
);
414 SendErrorMessage(stream_id
);
418 // Make sure the volume is valid.
419 if (volume
< 0 || volume
> 1.0)
421 entry
->controller()->SetVolume(volume
);
422 audio_log_
->OnSetVolume(stream_id
, volume
);
425 void AudioRendererHost::SendErrorMessage(int stream_id
) {
426 Send(new AudioMsg_NotifyStreamStateChanged(
427 stream_id
, media::AudioOutputIPCDelegate::kError
));
430 void AudioRendererHost::OnCloseStream(int stream_id
) {
431 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
433 // Prevent oustanding callbacks from attempting to close/delete the same
435 AudioEntryMap::iterator i
= audio_entries_
.find(stream_id
);
436 if (i
== audio_entries_
.end())
438 scoped_ptr
<AudioEntry
> entry(i
->second
);
439 audio_entries_
.erase(i
);
441 media::AudioOutputController
* const controller
= entry
->controller();
442 if (mirroring_manager_
)
443 mirroring_manager_
->RemoveDiverter(controller
);
445 base::Bind(&AudioRendererHost::DeleteEntry
, this, base::Passed(&entry
)));
446 audio_log_
->OnClosed(stream_id
);
449 void AudioRendererHost::DeleteEntry(scoped_ptr
<AudioEntry
> entry
) {
450 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
451 AudioStreamMonitor::StopMonitoringStream(
452 render_process_id_
, entry
->render_frame_id(), entry
->stream_id());
453 UpdateNumPlayingStreams(entry
.get(), false);
456 void AudioRendererHost::ReportErrorAndClose(int stream_id
) {
457 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
459 // Make sure this isn't a stray callback executing after the stream has been
460 // closed, so error notifications aren't sent after clients believe the stream
462 if (!LookupById(stream_id
))
465 SendErrorMessage(stream_id
);
467 audio_log_
->OnError(stream_id
);
468 OnCloseStream(stream_id
);
471 AudioRendererHost::AudioEntry
* AudioRendererHost::LookupById(int stream_id
) {
472 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
474 AudioEntryMap::const_iterator i
= audio_entries_
.find(stream_id
);
475 return i
!= audio_entries_
.end() ? i
->second
: NULL
;
478 void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry
* entry
,
480 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
481 if (entry
->playing() == is_playing
)
484 bool should_alert_resource_scheduler
;
486 should_alert_resource_scheduler
=
487 !RenderFrameHasActiveAudio(entry
->render_frame_id());
488 entry
->set_playing(true);
489 base::AtomicRefCountInc(&num_playing_streams_
);
491 entry
->set_playing(false);
492 should_alert_resource_scheduler
=
493 !RenderFrameHasActiveAudio(entry
->render_frame_id());
494 base::AtomicRefCountDec(&num_playing_streams_
);
497 if (should_alert_resource_scheduler
&& ResourceDispatcherHostImpl::Get()) {
498 BrowserThread::PostTaskAndReplyWithResult(
499 BrowserThread::UI
, FROM_HERE
,
500 base::Bind(&RenderFrameIdToRenderViewId
, render_process_id_
,
501 entry
->render_frame_id()),
502 base::Bind(&NotifyResourceDispatcherOfAudioStateChange
,
503 render_process_id_
, is_playing
));
507 bool AudioRendererHost::HasActiveAudio() {
508 return !base::AtomicRefCountIsZero(&num_playing_streams_
);
511 bool AudioRendererHost::RenderFrameHasActiveAudio(int render_frame_id
) const {
512 for (AudioEntryMap::const_iterator it
= audio_entries_
.begin();
513 it
!= audio_entries_
.end();
515 AudioEntry
* entry
= it
->second
;
516 if (entry
->render_frame_id() == render_frame_id
&& entry
->playing())
522 } // namespace content