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 media_internals_(media_internals),
121 media_stream_manager_(media_stream_manager) {
122 DCHECK(audio_manager_);
123 DCHECK(media_stream_manager_);
126 AudioRendererHost::~AudioRendererHost() {
127 DCHECK(audio_entries_.empty());
130 void AudioRendererHost::GetOutputControllers(
132 const RenderViewHost::GetAudioOutputControllersCallback& callback) const {
133 BrowserThread::PostTaskAndReplyWithResult(
136 base::Bind(&AudioRendererHost::DoGetOutputControllers, this,
141 void AudioRendererHost::OnChannelClosing() {
142 // Since the IPC channel is gone, close all requested audio streams.
143 while (!audio_entries_.empty()) {
144 // Note: OnCloseStream() removes the entries from audio_entries_.
145 OnCloseStream(audio_entries_.begin()->first);
149 void AudioRendererHost::OnDestruct() const {
150 BrowserThread::DeleteOnIOThread::Destruct(this);
153 void AudioRendererHost::AudioEntry::OnCreated() {
154 BrowserThread::PostTask(
157 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_));
160 void AudioRendererHost::AudioEntry::OnPlaying() {
161 BrowserThread::PostTask(
165 base::IgnoreResult(&AudioRendererHost::Send), host_,
166 new AudioMsg_NotifyStreamStateChanged(
167 stream_id_, media::AudioOutputIPCDelegate::kPlaying)));
170 void AudioRendererHost::AudioEntry::OnPowerMeasured(float power_dbfs,
172 BrowserThread::PostTask(
175 base::Bind(&AudioRendererHost::DoNotifyAudioPowerLevel, host_,
176 stream_id_, power_dbfs, clipped));
179 void AudioRendererHost::AudioEntry::OnPaused() {
180 BrowserThread::PostTask(
184 base::IgnoreResult(&AudioRendererHost::Send), host_,
185 new AudioMsg_NotifyStreamStateChanged(
186 stream_id_, media::AudioOutputIPCDelegate::kPaused)));
189 void AudioRendererHost::AudioEntry::OnError() {
190 BrowserThread::PostTask(
193 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_));
196 void AudioRendererHost::AudioEntry::OnDeviceChange(int new_buffer_size,
197 int new_sample_rate) {
198 BrowserThread::PostTask(
201 base::Bind(base::IgnoreResult(&AudioRendererHost::Send), host_,
202 new AudioMsg_NotifyDeviceChanged(
203 stream_id_, new_buffer_size, new_sample_rate)));
206 void AudioRendererHost::DoCompleteCreation(int stream_id) {
207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
210 DLOG(WARNING) << "Renderer process handle is invalid.";
211 ReportErrorAndClose(stream_id);
215 AudioEntry* const entry = LookupById(stream_id);
217 ReportErrorAndClose(stream_id);
221 // Once the audio stream is created then complete the creation process by
222 // mapping shared memory and sharing with the renderer process.
223 base::SharedMemoryHandle foreign_memory_handle;
224 if (!entry->shared_memory()->ShareToProcess(PeerHandle(),
225 &foreign_memory_handle)) {
226 // If we failed to map and share the shared memory then close the audio
227 // stream and send an error message.
228 ReportErrorAndClose(entry->stream_id());
232 AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader());
235 base::SyncSocket::Handle foreign_socket_handle;
237 base::FileDescriptor foreign_socket_handle;
240 // If we failed to prepare the sync socket for the renderer then we fail
241 // the construction of audio stream.
242 if (!reader->PrepareForeignSocketHandle(PeerHandle(),
243 &foreign_socket_handle)) {
244 ReportErrorAndClose(entry->stream_id());
248 Send(new AudioMsg_NotifyStreamCreated(
250 foreign_memory_handle,
251 foreign_socket_handle,
252 entry->shared_memory()->requested_size()));
255 RenderViewHost::AudioOutputControllerList
256 AudioRendererHost::DoGetOutputControllers(int render_view_id) const {
257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
259 RenderViewHost::AudioOutputControllerList controllers;
260 AudioEntryMap::const_iterator it = audio_entries_.begin();
261 for (; it != audio_entries_.end(); ++it) {
262 AudioEntry* entry = it->second;
263 if (entry->render_view_id() == render_view_id)
264 controllers.push_back(entry->controller());
270 void AudioRendererHost::DoNotifyAudioPowerLevel(int stream_id,
273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
275 MediaObserver* const media_observer =
276 GetContentClient()->browser()->GetMediaObserver();
277 if (media_observer) {
278 AudioEntry* const entry = LookupById(stream_id);
280 media_observer->OnAudioStreamPlayingChanged(
281 render_process_id_, entry->render_view_id(), entry->stream_id(),
282 true, power_dbfs, clipped);
287 ///////////////////////////////////////////////////////////////////////////////
288 // IPC Messages handler
289 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message,
290 bool* message_was_ok) {
292 IPC_BEGIN_MESSAGE_MAP_EX(AudioRendererHost, message, *message_was_ok)
293 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
294 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
295 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
296 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
297 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
298 IPC_MESSAGE_UNHANDLED(handled = false)
299 IPC_END_MESSAGE_MAP_EX()
304 void AudioRendererHost::OnCreateStream(
305 int stream_id, int render_view_id, int session_id,
306 const media::AudioParameters& params) {
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
309 DVLOG(1) << "AudioRendererHost@" << this
310 << "::OnCreateStream(stream_id=" << stream_id
311 << ", render_view_id=" << render_view_id
312 << ", session_id=" << session_id << ")";
313 DCHECK_GT(render_view_id, 0);
315 // media::AudioParameters is validated in the deserializer.
316 int input_channels = params.input_channels();
317 if (input_channels < 0 ||
318 input_channels > media::limits::kMaxChannels ||
319 LookupById(stream_id) != NULL) {
320 SendErrorMessage(stream_id);
324 // When the |input_channels| is valid, clients are trying to create a unified
325 // IO stream which opens an input device mapping to the |session_id|.
326 // Initialize the |output_device_id| to an empty string which indicates that
327 // the default device should be used. If a StreamDeviceInfo instance was found
328 // though, then we use the matched output device.
329 std::string input_device_id, output_device_id;
330 const StreamDeviceInfo* info = media_stream_manager_->
331 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
333 output_device_id = info->device.matched_output_device_id;
335 if (input_channels > 0) {
337 SendErrorMessage(stream_id);
338 DLOG(WARNING) << "No permission has been granted to input stream with "
339 << "session_id=" << session_id;
343 input_device_id = info->device.id;
346 // Calculate output and input memory size.
347 int output_memory_size = AudioBus::CalculateMemorySize(params);
348 int frames = params.frames_per_buffer();
349 int input_memory_size = AudioBus::CalculateMemorySize(input_channels, frames);
351 // Create the shared memory and share with the renderer process.
352 // For synchronized I/O (if input_channels > 0) then we allocate
353 // extra memory after the output data for the input data.
354 uint32 shared_memory_size = output_memory_size + input_memory_size;
355 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
356 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
357 SendErrorMessage(stream_id);
361 scoped_ptr<AudioSyncReader> reader(
362 new AudioSyncReader(shared_memory.get(), params, input_channels));
363 if (!reader->Init()) {
364 SendErrorMessage(stream_id);
368 MediaObserver* const media_observer =
369 GetContentClient()->browser()->GetMediaObserver();
371 media_observer->OnCreatingAudioStream(render_process_id_, render_view_id);
373 scoped_ptr<AudioEntry> entry(new AudioEntry(
374 this, stream_id, render_view_id, params, output_device_id,
375 input_device_id, shared_memory.Pass(),
376 reader.PassAs<media::AudioOutputController::SyncReader>()));
377 if (mirroring_manager_) {
378 mirroring_manager_->AddDiverter(
379 render_process_id_, entry->render_view_id(), entry->controller());
381 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
382 if (media_internals_) {
383 media_internals_->OnAudioStreamCreated(
384 this, stream_id, params, input_device_id);
388 void AudioRendererHost::OnPlayStream(int stream_id) {
389 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
391 AudioEntry* entry = LookupById(stream_id);
393 SendErrorMessage(stream_id);
397 entry->controller()->Play();
398 if (media_internals_)
399 media_internals_->OnSetAudioStreamPlaying(this, stream_id, true);
402 void AudioRendererHost::OnPauseStream(int stream_id) {
403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
405 AudioEntry* entry = LookupById(stream_id);
407 SendErrorMessage(stream_id);
411 entry->controller()->Pause();
412 if (media_internals_)
413 media_internals_->OnSetAudioStreamPlaying(this, stream_id, false);
416 void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
419 AudioEntry* entry = LookupById(stream_id);
421 SendErrorMessage(stream_id);
425 // Make sure the volume is valid.
426 if (volume < 0 || volume > 1.0)
428 entry->controller()->SetVolume(volume);
429 if (media_internals_)
430 media_internals_->OnSetAudioStreamVolume(this, stream_id, volume);
433 void AudioRendererHost::SendErrorMessage(int stream_id) {
434 Send(new AudioMsg_NotifyStreamStateChanged(
435 stream_id, media::AudioOutputIPCDelegate::kError));
438 void AudioRendererHost::OnCloseStream(int stream_id) {
439 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
441 // Prevent oustanding callbacks from attempting to close/delete the same
443 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
444 if (i == audio_entries_.end())
446 scoped_ptr<AudioEntry> entry(i->second);
447 audio_entries_.erase(i);
449 media::AudioOutputController* const controller = entry->controller();
450 if (mirroring_manager_) {
451 mirroring_manager_->RemoveDiverter(
452 render_process_id_, entry->render_view_id(), controller);
455 base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry)));
457 if (media_internals_)
458 media_internals_->OnSetAudioStreamStatus(this, stream_id, "closed");
461 void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
462 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
464 // At this point, make the final "say" in audio playback state.
465 MediaObserver* const media_observer =
466 GetContentClient()->browser()->GetMediaObserver();
467 if (media_observer) {
468 media_observer->OnAudioStreamPlayingChanged(
469 render_process_id_, entry->render_view_id(), entry->stream_id(),
470 false, -std::numeric_limits<float>::infinity(), false);
473 // Notify the media observer.
474 if (media_internals_)
475 media_internals_->OnDeleteAudioStream(this, entry->stream_id());
477 // Note: |entry| will be deleted upon leaving this scope.
480 void AudioRendererHost::ReportErrorAndClose(int stream_id) {
481 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
483 // Make sure this isn't a stray callback executing after the stream has been
484 // closed, so error notifications aren't sent after clients believe the stream
486 if (!LookupById(stream_id))
489 SendErrorMessage(stream_id);
491 if (media_internals_)
492 media_internals_->OnSetAudioStreamStatus(this, stream_id, "error");
494 OnCloseStream(stream_id);
497 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
498 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
500 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id);
501 return i != audio_entries_.end() ? i->second : NULL;
504 } // namespace content