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/memory/shared_memory.h"
10 #include "base/metrics/histogram.h"
11 #include "base/process/process.h"
12 #include "content/browser/browser_main_loop.h"
13 #include "content/browser/media/capture/audio_mirroring_manager.h"
14 #include "content/browser/media/media_internals.h"
15 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
16 #include "content/browser/renderer_host/media/audio_sync_reader.h"
17 #include "content/browser/renderer_host/media/media_stream_manager.h"
18 #include "content/common/media/audio_messages.h"
19 #include "content/public/browser/content_browser_client.h"
20 #include "content/public/browser/media_observer.h"
21 #include "content/public/common/content_switches.h"
22 #include "media/audio/audio_manager_base.h"
23 #include "media/base/audio_bus.h"
24 #include "media/base/limits.h"
26 using media::AudioBus
;
27 using media::AudioManager
;
31 class AudioRendererHost::AudioEntry
32 : public media::AudioOutputController::EventHandler
{
34 AudioEntry(AudioRendererHost
* host
,
38 const media::AudioParameters
& params
,
39 const std::string
& output_device_id
,
40 scoped_ptr
<base::SharedMemory
> shared_memory
,
41 scoped_ptr
<media::AudioOutputController::SyncReader
> reader
);
42 virtual ~AudioEntry();
44 int stream_id() const {
48 int render_view_id() const {
49 return render_view_id_
;
52 int render_frame_id() const { return render_frame_id_
; }
54 media::AudioOutputController
* controller() const { return controller_
.get(); }
56 base::SharedMemory
* shared_memory() {
57 return shared_memory_
.get();
60 media::AudioOutputController::SyncReader
* reader() const {
64 bool playing() const { return playing_
; }
65 void set_playing(bool playing
) { playing_
= playing
; }
68 // media::AudioOutputController::EventHandler implementation.
69 virtual void OnCreated() OVERRIDE
;
70 virtual void OnPlaying() OVERRIDE
;
71 virtual void OnPaused() OVERRIDE
;
72 virtual void OnError() OVERRIDE
;
73 virtual void OnDeviceChange(int new_buffer_size
, int new_sample_rate
)
76 AudioRendererHost
* const host_
;
79 // The routing ID of the source render view/frame.
80 const int render_view_id_
;
81 const int render_frame_id_
;
83 // Shared memory for transmission of the audio data. Used by |reader_|.
84 const scoped_ptr
<base::SharedMemory
> shared_memory_
;
86 // The synchronous reader to be used by |controller_|.
87 const scoped_ptr
<media::AudioOutputController::SyncReader
> reader_
;
89 // The AudioOutputController that manages the audio stream.
90 const scoped_refptr
<media::AudioOutputController
> controller_
;
95 AudioRendererHost::AudioEntry::AudioEntry(
96 AudioRendererHost
* host
,
100 const media::AudioParameters
& params
,
101 const std::string
& output_device_id
,
102 scoped_ptr
<base::SharedMemory
> shared_memory
,
103 scoped_ptr
<media::AudioOutputController::SyncReader
> reader
)
105 stream_id_(stream_id
),
106 render_view_id_(render_view_id
),
107 render_frame_id_(render_frame_id
),
108 shared_memory_(shared_memory
.Pass()),
109 reader_(reader
.Pass()),
110 controller_(media::AudioOutputController::Create(host
->audio_manager_
,
116 DCHECK(controller_
.get());
119 AudioRendererHost::AudioEntry::~AudioEntry() {}
121 ///////////////////////////////////////////////////////////////////////////////
122 // AudioRendererHost implementations.
124 AudioRendererHost::AudioRendererHost(
125 int render_process_id
,
126 media::AudioManager
* audio_manager
,
127 AudioMirroringManager
* mirroring_manager
,
128 MediaInternals
* media_internals
,
129 MediaStreamManager
* media_stream_manager
)
130 : BrowserMessageFilter(AudioMsgStart
),
131 render_process_id_(render_process_id
),
132 audio_manager_(audio_manager
),
133 mirroring_manager_(mirroring_manager
),
134 audio_log_(media_internals
->CreateAudioLog(
135 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER
)),
136 media_stream_manager_(media_stream_manager
),
137 num_playing_streams_(0) {
138 DCHECK(audio_manager_
);
139 DCHECK(media_stream_manager_
);
142 AudioRendererHost::~AudioRendererHost() {
143 DCHECK(audio_entries_
.empty());
146 void AudioRendererHost::GetOutputControllers(
148 const RenderViewHost::GetAudioOutputControllersCallback
& callback
) const {
149 BrowserThread::PostTaskAndReplyWithResult(
152 base::Bind(&AudioRendererHost::DoGetOutputControllers
, this,
157 void AudioRendererHost::OnChannelClosing() {
158 // Since the IPC sender is gone, close all requested audio streams.
159 while (!audio_entries_
.empty()) {
160 // Note: OnCloseStream() removes the entries from audio_entries_.
161 OnCloseStream(audio_entries_
.begin()->first
);
165 void AudioRendererHost::OnDestruct() const {
166 BrowserThread::DeleteOnIOThread::Destruct(this);
169 void AudioRendererHost::AudioEntry::OnCreated() {
170 BrowserThread::PostTask(
173 base::Bind(&AudioRendererHost::DoCompleteCreation
, host_
, stream_id_
));
176 void AudioRendererHost::AudioEntry::OnPlaying() {
177 BrowserThread::PostTask(
180 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged
,
186 void AudioRendererHost::AudioEntry::OnPaused() {
187 BrowserThread::PostTask(
190 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged
,
196 void AudioRendererHost::AudioEntry::OnError() {
197 BrowserThread::PostTask(
200 base::Bind(&AudioRendererHost::ReportErrorAndClose
, host_
, stream_id_
));
203 void AudioRendererHost::AudioEntry::OnDeviceChange(int new_buffer_size
,
204 int new_sample_rate
) {
205 BrowserThread::PostTask(
208 base::Bind(base::IgnoreResult(&AudioRendererHost::Send
), host_
,
209 new AudioMsg_NotifyDeviceChanged(
210 stream_id_
, new_buffer_size
, new_sample_rate
)));
213 void AudioRendererHost::DoCompleteCreation(int stream_id
) {
214 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
217 DLOG(WARNING
) << "Renderer process handle is invalid.";
218 ReportErrorAndClose(stream_id
);
222 AudioEntry
* const entry
= LookupById(stream_id
);
224 ReportErrorAndClose(stream_id
);
228 // Once the audio stream is created then complete the creation process by
229 // mapping shared memory and sharing with the renderer process.
230 base::SharedMemoryHandle foreign_memory_handle
;
231 if (!entry
->shared_memory()->ShareToProcess(PeerHandle(),
232 &foreign_memory_handle
)) {
233 // If we failed to map and share the shared memory then close the audio
234 // stream and send an error message.
235 ReportErrorAndClose(entry
->stream_id());
239 AudioSyncReader
* reader
= static_cast<AudioSyncReader
*>(entry
->reader());
242 base::SyncSocket::Handle foreign_socket_handle
;
244 base::FileDescriptor foreign_socket_handle
;
247 // If we failed to prepare the sync socket for the renderer then we fail
248 // the construction of audio stream.
249 if (!reader
->PrepareForeignSocketHandle(PeerHandle(),
250 &foreign_socket_handle
)) {
251 ReportErrorAndClose(entry
->stream_id());
255 Send(new AudioMsg_NotifyStreamCreated(
257 foreign_memory_handle
,
258 foreign_socket_handle
,
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
));
275 MediaObserver
* const media_observer
=
276 GetContentClient()->browser()->GetMediaObserver();
277 if (media_observer
) {
279 media_observer
->OnAudioStreamPlaying(
281 entry
->render_frame_id(),
283 base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip
,
284 entry
->controller()));
285 if (!entry
->playing()) {
286 entry
->set_playing(true);
287 base::AtomicRefCountInc(&num_playing_streams_
);
290 media_observer
->OnAudioStreamStopped(render_process_id_
,
291 entry
->render_frame_id(),
293 if (entry
->playing()) {
294 entry
->set_playing(false);
295 base::AtomicRefCountDec(&num_playing_streams_
);
301 RenderViewHost::AudioOutputControllerList
302 AudioRendererHost::DoGetOutputControllers(int render_view_id
) const {
303 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
305 RenderViewHost::AudioOutputControllerList controllers
;
306 AudioEntryMap::const_iterator it
= audio_entries_
.begin();
307 for (; it
!= audio_entries_
.end(); ++it
) {
308 AudioEntry
* entry
= it
->second
;
309 if (entry
->render_view_id() == render_view_id
)
310 controllers
.push_back(entry
->controller());
316 ///////////////////////////////////////////////////////////////////////////////
317 // IPC Messages handler
318 bool AudioRendererHost::OnMessageReceived(const IPC::Message
& message
) {
320 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost
, message
)
321 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream
, OnCreateStream
)
322 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream
, OnPlayStream
)
323 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream
, OnPauseStream
)
324 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream
, OnCloseStream
)
325 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume
, OnSetVolume
)
326 IPC_MESSAGE_UNHANDLED(handled
= false)
327 IPC_END_MESSAGE_MAP()
332 void AudioRendererHost::OnCreateStream(
333 int stream_id
, int render_view_id
, int render_frame_id
, int session_id
,
334 const media::AudioParameters
& params
) {
335 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
337 DVLOG(1) << "AudioRendererHost@" << this
338 << "::OnCreateStream(stream_id=" << stream_id
339 << ", render_view_id=" << render_view_id
340 << ", session_id=" << session_id
<< ")";
341 DCHECK_GT(render_view_id
, 0);
342 DCHECK_GT(render_frame_id
, 0);
344 // media::AudioParameters is validated in the deserializer.
345 if (LookupById(stream_id
) != NULL
) {
346 SendErrorMessage(stream_id
);
350 // Initialize the |output_device_id| to an empty string which indicates that
351 // the default device should be used. If a StreamDeviceInfo instance was found
352 // though, then we use the matched output device.
353 std::string output_device_id
;
354 const StreamDeviceInfo
* info
= media_stream_manager_
->
355 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id
);
357 output_device_id
= info
->device
.matched_output_device_id
;
359 // Create the shared memory and share with the renderer process.
360 // For synchronized I/O (if input_channels > 0) then we allocate
361 // extra memory after the output data for the input data.
362 uint32 shared_memory_size
= AudioBus::CalculateMemorySize(params
);
363 scoped_ptr
<base::SharedMemory
> shared_memory(new base::SharedMemory());
364 if (!shared_memory
->CreateAndMapAnonymous(shared_memory_size
)) {
365 SendErrorMessage(stream_id
);
369 scoped_ptr
<AudioSyncReader
> reader(
370 new AudioSyncReader(shared_memory
.get(), params
));
371 if (!reader
->Init()) {
372 SendErrorMessage(stream_id
);
376 MediaObserver
* const media_observer
=
377 GetContentClient()->browser()->GetMediaObserver();
379 media_observer
->OnCreatingAudioStream(render_process_id_
, render_frame_id
);
381 scoped_ptr
<AudioEntry
> entry(new AudioEntry(
388 shared_memory
.Pass(),
389 reader
.PassAs
<media::AudioOutputController::SyncReader
>()));
390 if (mirroring_manager_
) {
391 mirroring_manager_
->AddDiverter(
392 render_process_id_
, entry
->render_view_id(), entry
->controller());
394 audio_entries_
.insert(std::make_pair(stream_id
, entry
.release()));
395 audio_log_
->OnCreated(stream_id
, params
, output_device_id
);
398 void AudioRendererHost::OnPlayStream(int stream_id
) {
399 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
401 AudioEntry
* entry
= LookupById(stream_id
);
403 SendErrorMessage(stream_id
);
407 entry
->controller()->Play();
408 audio_log_
->OnStarted(stream_id
);
411 void AudioRendererHost::OnPauseStream(int stream_id
) {
412 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
414 AudioEntry
* entry
= LookupById(stream_id
);
416 SendErrorMessage(stream_id
);
420 entry
->controller()->Pause();
421 audio_log_
->OnStopped(stream_id
);
424 void AudioRendererHost::OnSetVolume(int stream_id
, double volume
) {
425 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
427 AudioEntry
* entry
= LookupById(stream_id
);
429 SendErrorMessage(stream_id
);
433 // Make sure the volume is valid.
434 if (volume
< 0 || volume
> 1.0)
436 entry
->controller()->SetVolume(volume
);
437 audio_log_
->OnSetVolume(stream_id
, volume
);
440 void AudioRendererHost::SendErrorMessage(int stream_id
) {
441 Send(new AudioMsg_NotifyStreamStateChanged(
442 stream_id
, media::AudioOutputIPCDelegate::kError
));
445 void AudioRendererHost::OnCloseStream(int stream_id
) {
446 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
448 // Prevent oustanding callbacks from attempting to close/delete the same
450 AudioEntryMap::iterator i
= audio_entries_
.find(stream_id
);
451 if (i
== audio_entries_
.end())
453 scoped_ptr
<AudioEntry
> entry(i
->second
);
454 audio_entries_
.erase(i
);
456 media::AudioOutputController
* const controller
= entry
->controller();
457 if (mirroring_manager_
) {
458 mirroring_manager_
->RemoveDiverter(
459 render_process_id_
, entry
->render_view_id(), controller
);
462 base::Bind(&AudioRendererHost::DeleteEntry
, this, base::Passed(&entry
)));
463 audio_log_
->OnClosed(stream_id
);
466 void AudioRendererHost::DeleteEntry(scoped_ptr
<AudioEntry
> entry
) {
467 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
469 // At this point, make the final "say" in audio playback state.
470 MediaObserver
* const media_observer
=
471 GetContentClient()->browser()->GetMediaObserver();
472 if (media_observer
) {
473 media_observer
->OnAudioStreamStopped(render_process_id_
,
474 entry
->render_frame_id(),
476 if (entry
->playing())
477 base::AtomicRefCountDec(&num_playing_streams_
);
481 void AudioRendererHost::ReportErrorAndClose(int stream_id
) {
482 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
484 // Make sure this isn't a stray callback executing after the stream has been
485 // closed, so error notifications aren't sent after clients believe the stream
487 if (!LookupById(stream_id
))
490 SendErrorMessage(stream_id
);
492 audio_log_
->OnError(stream_id
);
493 OnCloseStream(stream_id
);
496 AudioRendererHost::AudioEntry
* AudioRendererHost::LookupById(int stream_id
) {
497 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
499 AudioEntryMap::const_iterator i
= audio_entries_
.find(stream_id
);
500 return i
!= audio_entries_
.end() ? i
->second
: NULL
;
503 bool AudioRendererHost::HasActiveAudio() {
504 return !base::AtomicRefCountIsZero(&num_playing_streams_
);
507 } // namespace content