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/media_internals.h"
14 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
15 #include "content/browser/renderer_host/media/audio_mirroring_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
,
37 const media::AudioParameters
& params
,
38 const std::string
& output_device_id
,
39 const std::string
& input_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 media::AudioOutputController
* controller() const { return controller_
.get(); }
54 base::SharedMemory
* shared_memory() {
55 return shared_memory_
.get();
58 media::AudioOutputController::SyncReader
* reader() const {
63 // media::AudioOutputController::EventHandler implementation.
64 virtual void OnCreated() OVERRIDE
;
65 virtual void OnPlaying() OVERRIDE
;
66 virtual void OnPowerMeasured(float power_dbfs
, bool clipped
) OVERRIDE
;
67 virtual void OnPaused() OVERRIDE
;
68 virtual void OnError() OVERRIDE
;
69 virtual void OnDeviceChange(int new_buffer_size
, int new_sample_rate
)
72 AudioRendererHost
* const host_
;
75 // The routing ID of the source render view.
76 const int render_view_id_
;
78 // The AudioOutputController that manages the audio stream.
79 const scoped_refptr
<media::AudioOutputController
> controller_
;
81 // Shared memory for transmission of the audio data.
82 const scoped_ptr
<base::SharedMemory
> shared_memory_
;
84 // The synchronous reader to be used by the controller.
85 const scoped_ptr
<media::AudioOutputController::SyncReader
> reader_
;
88 AudioRendererHost::AudioEntry::AudioEntry(
89 AudioRendererHost
* host
, int stream_id
, int render_view_id
,
90 const media::AudioParameters
& params
,
91 const std::string
& output_device_id
,
92 const std::string
& input_device_id
,
93 scoped_ptr
<base::SharedMemory
> shared_memory
,
94 scoped_ptr
<media::AudioOutputController::SyncReader
> reader
)
96 stream_id_(stream_id
),
97 render_view_id_(render_view_id
),
98 controller_(media::AudioOutputController::Create(
99 host
->audio_manager_
, this, params
, output_device_id
,
100 input_device_id
, reader
.get())),
101 shared_memory_(shared_memory
.Pass()),
102 reader_(reader
.Pass()) {
103 DCHECK(controller_
.get());
106 AudioRendererHost::AudioEntry::~AudioEntry() {}
108 ///////////////////////////////////////////////////////////////////////////////
109 // AudioRendererHost implementations.
111 AudioRendererHost::AudioRendererHost(
112 int render_process_id
,
113 media::AudioManager
* audio_manager
,
114 AudioMirroringManager
* mirroring_manager
,
115 MediaInternals
* media_internals
,
116 MediaStreamManager
* media_stream_manager
)
117 : render_process_id_(render_process_id
),
118 audio_manager_(audio_manager
),
119 mirroring_manager_(mirroring_manager
),
120 audio_log_(media_internals
->CreateAudioLog(
121 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER
)),
122 media_stream_manager_(media_stream_manager
) {
123 DCHECK(audio_manager_
);
124 DCHECK(media_stream_manager_
);
127 AudioRendererHost::~AudioRendererHost() {
128 DCHECK(audio_entries_
.empty());
131 void AudioRendererHost::GetOutputControllers(
133 const RenderViewHost::GetAudioOutputControllersCallback
& callback
) const {
134 BrowserThread::PostTaskAndReplyWithResult(
137 base::Bind(&AudioRendererHost::DoGetOutputControllers
, this,
142 void AudioRendererHost::OnChannelClosing() {
143 // Since the IPC channel is gone, close all requested audio streams.
144 while (!audio_entries_
.empty()) {
145 // Note: OnCloseStream() removes the entries from audio_entries_.
146 OnCloseStream(audio_entries_
.begin()->first
);
150 void AudioRendererHost::OnDestruct() const {
151 BrowserThread::DeleteOnIOThread::Destruct(this);
154 void AudioRendererHost::AudioEntry::OnCreated() {
155 BrowserThread::PostTask(
158 base::Bind(&AudioRendererHost::DoCompleteCreation
, host_
, stream_id_
));
161 void AudioRendererHost::AudioEntry::OnPlaying() {
162 BrowserThread::PostTask(
166 base::IgnoreResult(&AudioRendererHost::Send
), host_
,
167 new AudioMsg_NotifyStreamStateChanged(
168 stream_id_
, media::AudioOutputIPCDelegate::kPlaying
)));
171 void AudioRendererHost::AudioEntry::OnPowerMeasured(float power_dbfs
,
173 BrowserThread::PostTask(
176 base::Bind(&AudioRendererHost::DoNotifyAudioPowerLevel
, host_
,
177 stream_id_
, power_dbfs
, clipped
));
180 void AudioRendererHost::AudioEntry::OnPaused() {
181 BrowserThread::PostTask(
185 base::IgnoreResult(&AudioRendererHost::Send
), host_
,
186 new AudioMsg_NotifyStreamStateChanged(
187 stream_id_
, media::AudioOutputIPCDelegate::kPaused
)));
190 void AudioRendererHost::AudioEntry::OnError() {
191 BrowserThread::PostTask(
194 base::Bind(&AudioRendererHost::ReportErrorAndClose
, host_
, stream_id_
));
197 void AudioRendererHost::AudioEntry::OnDeviceChange(int new_buffer_size
,
198 int new_sample_rate
) {
199 BrowserThread::PostTask(
202 base::Bind(base::IgnoreResult(&AudioRendererHost::Send
), host_
,
203 new AudioMsg_NotifyDeviceChanged(
204 stream_id_
, new_buffer_size
, new_sample_rate
)));
207 void AudioRendererHost::DoCompleteCreation(int stream_id
) {
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
211 DLOG(WARNING
) << "Renderer process handle is invalid.";
212 ReportErrorAndClose(stream_id
);
216 AudioEntry
* const entry
= LookupById(stream_id
);
218 ReportErrorAndClose(stream_id
);
222 // Once the audio stream is created then complete the creation process by
223 // mapping shared memory and sharing with the renderer process.
224 base::SharedMemoryHandle foreign_memory_handle
;
225 if (!entry
->shared_memory()->ShareToProcess(PeerHandle(),
226 &foreign_memory_handle
)) {
227 // If we failed to map and share the shared memory then close the audio
228 // stream and send an error message.
229 ReportErrorAndClose(entry
->stream_id());
233 AudioSyncReader
* reader
= static_cast<AudioSyncReader
*>(entry
->reader());
236 base::SyncSocket::Handle foreign_socket_handle
;
238 base::FileDescriptor foreign_socket_handle
;
241 // If we failed to prepare the sync socket for the renderer then we fail
242 // the construction of audio stream.
243 if (!reader
->PrepareForeignSocketHandle(PeerHandle(),
244 &foreign_socket_handle
)) {
245 ReportErrorAndClose(entry
->stream_id());
249 Send(new AudioMsg_NotifyStreamCreated(
251 foreign_memory_handle
,
252 foreign_socket_handle
,
253 entry
->shared_memory()->requested_size()));
256 RenderViewHost::AudioOutputControllerList
257 AudioRendererHost::DoGetOutputControllers(int render_view_id
) const {
258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
260 RenderViewHost::AudioOutputControllerList controllers
;
261 AudioEntryMap::const_iterator it
= audio_entries_
.begin();
262 for (; it
!= audio_entries_
.end(); ++it
) {
263 AudioEntry
* entry
= it
->second
;
264 if (entry
->render_view_id() == render_view_id
)
265 controllers
.push_back(entry
->controller());
271 void AudioRendererHost::DoNotifyAudioPowerLevel(int stream_id
,
274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
276 MediaObserver
* const media_observer
=
277 GetContentClient()->browser()->GetMediaObserver();
278 if (media_observer
) {
279 AudioEntry
* const entry
= LookupById(stream_id
);
281 media_observer
->OnAudioStreamPlayingChanged(
282 render_process_id_
, entry
->render_view_id(), entry
->stream_id(),
283 true, power_dbfs
, clipped
);
288 ///////////////////////////////////////////////////////////////////////////////
289 // IPC Messages handler
290 bool AudioRendererHost::OnMessageReceived(const IPC::Message
& message
,
291 bool* message_was_ok
) {
293 IPC_BEGIN_MESSAGE_MAP_EX(AudioRendererHost
, message
, *message_was_ok
)
294 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream
, OnCreateStream
)
295 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream
, OnPlayStream
)
296 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream
, OnPauseStream
)
297 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream
, OnCloseStream
)
298 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume
, OnSetVolume
)
299 IPC_MESSAGE_UNHANDLED(handled
= false)
300 IPC_END_MESSAGE_MAP_EX()
305 void AudioRendererHost::OnCreateStream(
306 int stream_id
, int render_view_id
, int session_id
,
307 const media::AudioParameters
& params
) {
308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
310 DVLOG(1) << "AudioRendererHost@" << this
311 << "::OnCreateStream(stream_id=" << stream_id
312 << ", render_view_id=" << render_view_id
313 << ", session_id=" << session_id
<< ")";
314 DCHECK_GT(render_view_id
, 0);
316 // media::AudioParameters is validated in the deserializer.
317 int input_channels
= params
.input_channels();
318 if (input_channels
< 0 ||
319 input_channels
> media::limits::kMaxChannels
||
320 LookupById(stream_id
) != NULL
) {
321 SendErrorMessage(stream_id
);
325 // When the |input_channels| is valid, clients are trying to create a unified
326 // IO stream which opens an input device mapping to the |session_id|.
327 // Initialize the |output_device_id| to an empty string which indicates that
328 // the default device should be used. If a StreamDeviceInfo instance was found
329 // though, then we use the matched output device.
330 std::string input_device_id
, output_device_id
;
331 const StreamDeviceInfo
* info
= media_stream_manager_
->
332 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id
);
334 output_device_id
= info
->device
.matched_output_device_id
;
336 if (input_channels
> 0) {
338 SendErrorMessage(stream_id
);
339 DLOG(WARNING
) << "No permission has been granted to input stream with "
340 << "session_id=" << session_id
;
344 input_device_id
= info
->device
.id
;
347 // Calculate output and input memory size.
348 int output_memory_size
= AudioBus::CalculateMemorySize(params
);
349 int frames
= params
.frames_per_buffer();
350 int input_memory_size
= AudioBus::CalculateMemorySize(input_channels
, frames
);
352 // Create the shared memory and share with the renderer process.
353 // For synchronized I/O (if input_channels > 0) then we allocate
354 // extra memory after the output data for the input data.
355 uint32 shared_memory_size
= output_memory_size
+ input_memory_size
;
356 scoped_ptr
<base::SharedMemory
> shared_memory(new base::SharedMemory());
357 if (!shared_memory
->CreateAndMapAnonymous(shared_memory_size
)) {
358 SendErrorMessage(stream_id
);
362 scoped_ptr
<AudioSyncReader
> reader(
363 new AudioSyncReader(shared_memory
.get(), params
, input_channels
));
364 if (!reader
->Init()) {
365 SendErrorMessage(stream_id
);
369 MediaObserver
* const media_observer
=
370 GetContentClient()->browser()->GetMediaObserver();
372 media_observer
->OnCreatingAudioStream(render_process_id_
, render_view_id
);
374 scoped_ptr
<AudioEntry
> entry(new AudioEntry(
375 this, stream_id
, render_view_id
, params
, output_device_id
,
376 input_device_id
, shared_memory
.Pass(),
377 reader
.PassAs
<media::AudioOutputController::SyncReader
>()));
378 if (mirroring_manager_
) {
379 mirroring_manager_
->AddDiverter(
380 render_process_id_
, entry
->render_view_id(), entry
->controller());
382 audio_entries_
.insert(std::make_pair(stream_id
, entry
.release()));
383 audio_log_
->OnCreated(stream_id
, params
, input_device_id
, output_device_id
);
386 void AudioRendererHost::OnPlayStream(int stream_id
) {
387 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
389 AudioEntry
* entry
= LookupById(stream_id
);
391 SendErrorMessage(stream_id
);
395 entry
->controller()->Play();
396 audio_log_
->OnStarted(stream_id
);
399 void AudioRendererHost::OnPauseStream(int stream_id
) {
400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
402 AudioEntry
* entry
= LookupById(stream_id
);
404 SendErrorMessage(stream_id
);
408 entry
->controller()->Pause();
409 audio_log_
->OnStopped(stream_id
);
412 void AudioRendererHost::OnSetVolume(int stream_id
, double volume
) {
413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
415 AudioEntry
* entry
= LookupById(stream_id
);
417 SendErrorMessage(stream_id
);
421 // Make sure the volume is valid.
422 if (volume
< 0 || volume
> 1.0)
424 entry
->controller()->SetVolume(volume
);
425 audio_log_
->OnSetVolume(stream_id
, volume
);
428 void AudioRendererHost::SendErrorMessage(int stream_id
) {
429 Send(new AudioMsg_NotifyStreamStateChanged(
430 stream_id
, media::AudioOutputIPCDelegate::kError
));
433 void AudioRendererHost::OnCloseStream(int stream_id
) {
434 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
436 // Prevent oustanding callbacks from attempting to close/delete the same
438 AudioEntryMap::iterator i
= audio_entries_
.find(stream_id
);
439 if (i
== audio_entries_
.end())
441 scoped_ptr
<AudioEntry
> entry(i
->second
);
442 audio_entries_
.erase(i
);
444 media::AudioOutputController
* const controller
= entry
->controller();
445 if (mirroring_manager_
) {
446 mirroring_manager_
->RemoveDiverter(
447 render_process_id_
, entry
->render_view_id(), controller
);
450 base::Bind(&AudioRendererHost::DeleteEntry
, this, base::Passed(&entry
)));
451 audio_log_
->OnClosed(stream_id
);
454 void AudioRendererHost::DeleteEntry(scoped_ptr
<AudioEntry
> entry
) {
455 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
457 // At this point, make the final "say" in audio playback state.
458 MediaObserver
* const media_observer
=
459 GetContentClient()->browser()->GetMediaObserver();
460 if (media_observer
) {
461 media_observer
->OnAudioStreamPlayingChanged(
462 render_process_id_
, entry
->render_view_id(), entry
->stream_id(),
463 false, -std::numeric_limits
<float>::infinity(), false);
467 void AudioRendererHost::ReportErrorAndClose(int stream_id
) {
468 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
470 // Make sure this isn't a stray callback executing after the stream has been
471 // closed, so error notifications aren't sent after clients believe the stream
473 if (!LookupById(stream_id
))
476 SendErrorMessage(stream_id
);
478 audio_log_
->OnError(stream_id
);
479 OnCloseStream(stream_id
);
482 AudioRendererHost::AudioEntry
* AudioRendererHost::LookupById(int stream_id
) {
483 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
485 AudioEntryMap::const_iterator i
= audio_entries_
.find(stream_id
);
486 return i
!= audio_entries_
.end() ? i
->second
: NULL
;
489 } // namespace content