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/command_line.h"
10 #include "base/metrics/histogram.h"
11 #include "base/process.h"
12 #include "base/shared_memory.h"
13 #include "content/browser/browser_main_loop.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_mirroring_manager.h"
17 #include "content/browser/renderer_host/media/audio_sync_reader.h"
18 #include "content/browser/renderer_host/media/media_stream_manager.h"
19 #include "content/common/media/audio_messages.h"
20 #include "content/public/browser/content_browser_client.h"
21 #include "content/public/browser/media_observer.h"
22 #include "content/public/common/content_switches.h"
23 #include "media/audio/audio_manager_base.h"
24 #include "media/audio/shared_memory_util.h"
25 #include "media/base/audio_bus.h"
26 #include "media/base/limits.h"
28 using media::AudioBus
;
32 class AudioRendererHost::AudioEntry
33 : public media::AudioOutputController::EventHandler
{
35 AudioEntry(AudioRendererHost
* host
,
38 const media::AudioParameters
& params
,
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 OnAudible(bool is_audible
) 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
& input_device_id
,
92 scoped_ptr
<base::SharedMemory
> shared_memory
,
93 scoped_ptr
<media::AudioOutputController::SyncReader
> reader
)
95 stream_id_(stream_id
),
96 render_view_id_(render_view_id
),
97 controller_(media::AudioOutputController::Create(
98 host
->audio_manager_
, this, params
, input_device_id
, reader
.get())),
99 shared_memory_(shared_memory
.Pass()),
100 reader_(reader
.Pass()) {
101 DCHECK(controller_
.get());
104 AudioRendererHost::AudioEntry::~AudioEntry() {}
106 ///////////////////////////////////////////////////////////////////////////////
107 // AudioRendererHost implementations.
108 AudioRendererHost::AudioRendererHost(
109 int render_process_id
,
110 media::AudioManager
* audio_manager
,
111 AudioMirroringManager
* mirroring_manager
,
112 MediaInternals
* media_internals
,
113 MediaStreamManager
* media_stream_manager
)
114 : render_process_id_(render_process_id
),
115 audio_manager_(audio_manager
),
116 mirroring_manager_(mirroring_manager
),
117 media_internals_(media_internals
),
118 media_stream_manager_(media_stream_manager
) {
119 DCHECK(audio_manager_
);
120 DCHECK(media_stream_manager_
);
123 AudioRendererHost::~AudioRendererHost() {
124 DCHECK(audio_entries_
.empty());
127 void AudioRendererHost::OnChannelClosing() {
128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
130 BrowserMessageFilter::OnChannelClosing();
132 // Since the IPC channel is gone, close all requested audio streams.
133 while (!audio_entries_
.empty()) {
134 // Note: OnCloseStream() removes the entries from audio_entries_.
135 OnCloseStream(audio_entries_
.begin()->first
);
139 void AudioRendererHost::OnDestruct() const {
140 BrowserThread::DeleteOnIOThread::Destruct(this);
143 void AudioRendererHost::AudioEntry::OnCreated() {
144 BrowserThread::PostTask(
147 base::Bind(&AudioRendererHost::DoCompleteCreation
, host_
, this));
150 void AudioRendererHost::AudioEntry::OnPlaying() {
151 BrowserThread::PostTask(
155 base::IgnoreResult(&AudioRendererHost::Send
), host_
,
156 new AudioMsg_NotifyStreamStateChanged(
157 stream_id_
, media::AudioOutputIPCDelegate::kPlaying
)));
160 void AudioRendererHost::AudioEntry::OnAudible(bool is_audible
) {
161 BrowserThread::PostTask(
164 base::Bind(&AudioRendererHost::DoNotifyAudibleState
, host_
,
168 void AudioRendererHost::AudioEntry::OnPaused() {
169 BrowserThread::PostTask(
173 base::IgnoreResult(&AudioRendererHost::Send
), host_
,
174 new AudioMsg_NotifyStreamStateChanged(
175 stream_id_
, media::AudioOutputIPCDelegate::kPaused
)));
178 void AudioRendererHost::AudioEntry::OnError() {
179 BrowserThread::PostTask(
182 base::Bind(&AudioRendererHost::ReportErrorAndClose
, host_
, stream_id_
));
185 void AudioRendererHost::AudioEntry::OnDeviceChange(int new_buffer_size
,
186 int new_sample_rate
) {
187 BrowserThread::PostTask(
190 base::Bind(base::IgnoreResult(&AudioRendererHost::Send
), host_
,
191 new AudioMsg_NotifyDeviceChanged(
192 stream_id_
, new_buffer_size
, new_sample_rate
)));
195 void AudioRendererHost::DoCompleteCreation(AudioEntry
* entry
) {
196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
198 if (!peer_handle()) {
199 NOTREACHED() << "Renderer process handle is invalid.";
200 ReportErrorAndClose(entry
->stream_id());
204 // Once the audio stream is created then complete the creation process by
205 // mapping shared memory and sharing with the renderer process.
206 base::SharedMemoryHandle foreign_memory_handle
;
207 if (!entry
->shared_memory()->ShareToProcess(peer_handle(),
208 &foreign_memory_handle
)) {
209 // If we failed to map and share the shared memory then close the audio
210 // stream and send an error message.
211 ReportErrorAndClose(entry
->stream_id());
215 AudioSyncReader
* reader
= static_cast<AudioSyncReader
*>(entry
->reader());
218 base::SyncSocket::Handle foreign_socket_handle
;
220 base::FileDescriptor foreign_socket_handle
;
223 // If we failed to prepare the sync socket for the renderer then we fail
224 // the construction of audio stream.
225 if (!reader
->PrepareForeignSocketHandle(peer_handle(),
226 &foreign_socket_handle
)) {
227 ReportErrorAndClose(entry
->stream_id());
231 Send(new AudioMsg_NotifyStreamCreated(
233 foreign_memory_handle
,
234 foreign_socket_handle
,
235 media::PacketSizeInBytes(entry
->shared_memory()->requested_size())));
238 void AudioRendererHost::DoNotifyAudibleState(AudioEntry
* entry
,
240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
242 MediaObserver
* const media_observer
=
243 GetContentClient()->browser()->GetMediaObserver();
244 if (media_observer
) {
245 DVLOG(1) << "AudioRendererHost@" << this
246 << "::DoNotifyAudibleState(is_audible=" << is_audible
247 << ") for stream_id=" << entry
->stream_id();
249 if (CommandLine::ForCurrentProcess()->HasSwitch(
250 switches::kEnableAudibleNotifications
)) {
251 media_observer
->OnAudioStreamPlayingChanged(
252 render_process_id_
, entry
->render_view_id(), entry
->stream_id(),
258 ///////////////////////////////////////////////////////////////////////////////
259 // IPC Messages handler
260 bool AudioRendererHost::OnMessageReceived(const IPC::Message
& message
,
261 bool* message_was_ok
) {
263 IPC_BEGIN_MESSAGE_MAP_EX(AudioRendererHost
, message
, *message_was_ok
)
264 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream
, OnCreateStream
)
265 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream
, OnPlayStream
)
266 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream
, OnPauseStream
)
267 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream
, OnCloseStream
)
268 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume
, OnSetVolume
)
269 IPC_MESSAGE_UNHANDLED(handled
= false)
270 IPC_END_MESSAGE_MAP_EX()
275 void AudioRendererHost::OnCreateStream(
276 int stream_id
, int render_view_id
, int session_id
,
277 const media::AudioParameters
& params
) {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
280 DVLOG(1) << "AudioRendererHost@" << this
281 << "::OnCreateStream(stream_id=" << stream_id
282 << ", render_view_id=" << render_view_id
283 << ", session_id=" << session_id
<< ")";
284 DCHECK_GT(render_view_id
, 0);
286 // media::AudioParameters is validated in the deserializer.
287 int input_channels
= params
.input_channels();
288 if (input_channels
< 0 ||
289 input_channels
> media::limits::kMaxChannels
||
290 LookupById(stream_id
) != NULL
) {
291 SendErrorMessage(stream_id
);
295 // When the |input_channels| is valid, clients are trying to create a unified
296 // IO stream which opens an input device mapping to the |session_id|.
297 std::string input_device_id
;
298 if (input_channels
> 0) {
299 const StreamDeviceInfo
* info
= media_stream_manager_
->
300 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id
);
302 SendErrorMessage(stream_id
);
303 DLOG(WARNING
) << "No permission has been granted to input stream with "
304 << "session_id=" << session_id
;
308 input_device_id
= info
->device
.id
;
311 // Calculate output and input memory size.
312 int output_memory_size
= AudioBus::CalculateMemorySize(params
);
313 int frames
= params
.frames_per_buffer();
314 int input_memory_size
=
315 AudioBus::CalculateMemorySize(input_channels
, frames
);
317 // Create the shared memory and share with the renderer process.
318 // For synchronized I/O (if input_channels > 0) then we allocate
319 // extra memory after the output data for the input data.
320 uint32 io_buffer_size
= output_memory_size
+ input_memory_size
;
321 uint32 shared_memory_size
=
322 media::TotalSharedMemorySizeInBytes(io_buffer_size
);
323 scoped_ptr
<base::SharedMemory
> shared_memory(new base::SharedMemory());
324 if (!shared_memory
->CreateAndMapAnonymous(shared_memory_size
)) {
325 SendErrorMessage(stream_id
);
329 scoped_ptr
<AudioSyncReader
> reader(
330 new AudioSyncReader(shared_memory
.get(), params
, input_channels
));
331 if (!reader
->Init()) {
332 SendErrorMessage(stream_id
);
336 scoped_ptr
<AudioEntry
> entry(new AudioEntry(
337 this, stream_id
, render_view_id
, params
, input_device_id
,
338 shared_memory
.Pass(),
339 reader
.PassAs
<media::AudioOutputController::SyncReader
>()));
340 if (mirroring_manager_
) {
341 mirroring_manager_
->AddDiverter(
342 render_process_id_
, entry
->render_view_id(), entry
->controller());
344 audio_entries_
.insert(std::make_pair(stream_id
, entry
.release()));
345 if (media_internals_
)
346 media_internals_
->OnSetAudioStreamStatus(this, stream_id
, "created");
349 void AudioRendererHost::OnPlayStream(int stream_id
) {
350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
352 AudioEntry
* entry
= LookupById(stream_id
);
354 SendErrorMessage(stream_id
);
358 entry
->controller()->Play();
359 if (media_internals_
)
360 media_internals_
->OnSetAudioStreamPlaying(this, stream_id
, true);
363 void AudioRendererHost::OnPauseStream(int stream_id
) {
364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
366 AudioEntry
* entry
= LookupById(stream_id
);
368 SendErrorMessage(stream_id
);
372 entry
->controller()->Pause();
373 if (media_internals_
)
374 media_internals_
->OnSetAudioStreamPlaying(this, stream_id
, false);
377 void AudioRendererHost::OnSetVolume(int stream_id
, double volume
) {
378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
380 AudioEntry
* entry
= LookupById(stream_id
);
382 SendErrorMessage(stream_id
);
386 // Make sure the volume is valid.
387 if (volume
< 0 || volume
> 1.0)
389 entry
->controller()->SetVolume(volume
);
390 if (media_internals_
)
391 media_internals_
->OnSetAudioStreamVolume(this, stream_id
, volume
);
394 void AudioRendererHost::SendErrorMessage(int stream_id
) {
395 Send(new AudioMsg_NotifyStreamStateChanged(
396 stream_id
, media::AudioOutputIPCDelegate::kError
));
399 void AudioRendererHost::OnCloseStream(int stream_id
) {
400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
402 // Prevent oustanding callbacks from attempting to close/delete the same
404 AudioEntryMap::iterator i
= audio_entries_
.find(stream_id
);
405 if (i
== audio_entries_
.end())
407 scoped_ptr
<AudioEntry
> entry(i
->second
);
408 audio_entries_
.erase(i
);
410 media::AudioOutputController
* const controller
= entry
->controller();
411 if (mirroring_manager_
) {
412 mirroring_manager_
->RemoveDiverter(
413 render_process_id_
, entry
->render_view_id(), controller
);
416 base::Bind(&AudioRendererHost::DeleteEntry
, this, base::Passed(&entry
)));
418 if (media_internals_
)
419 media_internals_
->OnSetAudioStreamStatus(this, stream_id
, "closed");
422 void AudioRendererHost::DeleteEntry(scoped_ptr
<AudioEntry
> entry
) {
423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
425 // At this point, make the final "say" in audio playback state.
426 MediaObserver
* const media_observer
=
427 GetContentClient()->browser()->GetMediaObserver();
428 if (media_observer
) {
429 media_observer
->OnAudioStreamPlayingChanged(
430 render_process_id_
, entry
->render_view_id(), entry
->stream_id(), false);
433 // Notify the media observer.
434 if (media_internals_
)
435 media_internals_
->OnDeleteAudioStream(this, entry
->stream_id());
437 // Note: |entry| will be deleted upon leaving this scope.
440 void AudioRendererHost::ReportErrorAndClose(int stream_id
) {
441 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
443 // Make sure this isn't a stray callback executing after the stream has been
444 // closed, so error notifications aren't sent after clients believe the stream
446 if (!LookupById(stream_id
))
449 SendErrorMessage(stream_id
);
451 if (media_internals_
)
452 media_internals_
->OnSetAudioStreamStatus(this, stream_id
, "error");
454 OnCloseStream(stream_id
);
457 AudioRendererHost::AudioEntry
* AudioRendererHost::LookupById(int stream_id
) {
458 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
460 AudioEntryMap::const_iterator i
= audio_entries_
.find(stream_id
);
461 return i
!= audio_entries_
.end() ? i
->second
: NULL
;
464 } // namespace content