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/common/media/audio_messages.h"
22 #include "content/public/browser/content_browser_client.h"
23 #include "content/public/browser/media_observer.h"
24 #include "content/public/common/content_switches.h"
25 #include "media/audio/audio_manager_base.h"
26 #include "media/base/audio_bus.h"
27 #include "media/base/limits.h"
29 using media::AudioBus;
30 using media::AudioManager;
34 class AudioRendererHost::AudioEntry
35 : public media::AudioOutputController::EventHandler {
37 AudioEntry(AudioRendererHost* host,
41 const media::AudioParameters& params,
42 const std::string& output_device_id,
43 scoped_ptr<base::SharedMemory> shared_memory,
44 scoped_ptr<media::AudioOutputController::SyncReader> reader);
45 ~AudioEntry() override;
47 int stream_id() const {
51 int render_view_id() const {
52 return render_view_id_;
55 int render_frame_id() const { return render_frame_id_; }
57 media::AudioOutputController* controller() const { return controller_.get(); }
59 base::SharedMemory* shared_memory() {
60 return shared_memory_.get();
63 media::AudioOutputController::SyncReader* reader() const {
67 bool playing() const { return playing_; }
68 void set_playing(bool playing) { playing_ = playing; }
71 std::string app_id() const override { return host_->app_id_; }
72 std::string app_class() const override { return host_->app_class_; }
76 // media::AudioOutputController::EventHandler implementation.
77 void OnCreated() override;
78 void OnPlaying() override;
79 void OnPaused() override;
80 void OnError() override;
81 void OnDeviceChange(int new_buffer_size, int new_sample_rate) override;
83 AudioRendererHost* const host_;
86 // The routing ID of the source render view/frame.
87 const int render_view_id_;
88 const int render_frame_id_;
90 // Shared memory for transmission of the audio data. Used by |reader_|.
91 const scoped_ptr<base::SharedMemory> shared_memory_;
93 // The synchronous reader to be used by |controller_|.
94 const scoped_ptr<media::AudioOutputController::SyncReader> reader_;
96 // The AudioOutputController that manages the audio stream.
97 const scoped_refptr<media::AudioOutputController> controller_;
102 AudioRendererHost::AudioEntry::AudioEntry(
103 AudioRendererHost* host,
107 const media::AudioParameters& params,
108 const std::string& output_device_id,
109 scoped_ptr<base::SharedMemory> shared_memory,
110 scoped_ptr<media::AudioOutputController::SyncReader> reader)
112 stream_id_(stream_id),
113 render_view_id_(render_view_id),
114 render_frame_id_(render_frame_id),
115 shared_memory_(shared_memory.Pass()),
116 reader_(reader.Pass()),
117 controller_(media::AudioOutputController::Create(host->audio_manager_,
123 DCHECK(controller_.get());
126 AudioRendererHost::AudioEntry::~AudioEntry() {}
128 ///////////////////////////////////////////////////////////////////////////////
129 // AudioRendererHost implementations.
131 AudioRendererHost::AudioRendererHost(
132 int render_process_id,
133 media::AudioManager* audio_manager,
134 AudioMirroringManager* mirroring_manager,
135 MediaInternals* media_internals,
136 MediaStreamManager* media_stream_manager)
137 : BrowserMessageFilter(AudioMsgStart),
138 render_process_id_(render_process_id),
139 audio_manager_(audio_manager),
140 mirroring_manager_(mirroring_manager),
141 audio_log_(media_internals->CreateAudioLog(
142 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)),
143 media_stream_manager_(media_stream_manager),
144 num_playing_streams_(0) {
145 DCHECK(audio_manager_);
146 DCHECK(media_stream_manager_);
149 AudioRendererHost::~AudioRendererHost() {
150 DCHECK(audio_entries_.empty());
153 void AudioRendererHost::GetOutputControllers(
155 const RenderViewHost::GetAudioOutputControllersCallback& callback) const {
156 BrowserThread::PostTaskAndReplyWithResult(
159 base::Bind(&AudioRendererHost::DoGetOutputControllers, this,
164 void AudioRendererHost::OnChannelClosing() {
165 // Since the IPC sender is gone, close all requested audio streams.
166 while (!audio_entries_.empty()) {
167 // Note: OnCloseStream() removes the entries from audio_entries_.
168 OnCloseStream(audio_entries_.begin()->first);
172 void AudioRendererHost::OnDestruct() const {
173 BrowserThread::DeleteOnIOThread::Destruct(this);
176 void AudioRendererHost::AudioEntry::OnCreated() {
177 BrowserThread::PostTask(
180 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_));
183 void AudioRendererHost::AudioEntry::OnPlaying() {
184 BrowserThread::PostTask(
187 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
193 void AudioRendererHost::AudioEntry::OnPaused() {
194 BrowserThread::PostTask(
197 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
203 void AudioRendererHost::AudioEntry::OnError() {
204 BrowserThread::PostTask(
207 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_));
210 void AudioRendererHost::AudioEntry::OnDeviceChange(int new_buffer_size,
211 int new_sample_rate) {
212 BrowserThread::PostTask(
215 base::Bind(base::IgnoreResult(&AudioRendererHost::Send), host_,
216 new AudioMsg_NotifyDeviceChanged(
217 stream_id_, new_buffer_size, new_sample_rate)));
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 RenderViewHost::AudioOutputControllerList
290 AudioRendererHost::DoGetOutputControllers(int render_view_id) const {
291 DCHECK_CURRENTLY_ON(BrowserThread::IO);
293 RenderViewHost::AudioOutputControllerList controllers;
294 for (AudioEntryMap::const_iterator it = audio_entries_.begin();
295 it != audio_entries_.end();
297 AudioEntry* entry = it->second;
298 if (entry->render_view_id() == render_view_id)
299 controllers.push_back(entry->controller());
305 ///////////////////////////////////////////////////////////////////////////////
306 // IPC Messages handler
307 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
309 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message)
310 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
311 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
312 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
313 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
314 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
315 IPC_MESSAGE_UNHANDLED(handled = false)
316 IPC_END_MESSAGE_MAP()
321 void AudioRendererHost::OnCreateStream(
322 int stream_id, int render_view_id, int render_frame_id, int session_id,
323 const media::AudioParameters& params) {
324 DCHECK_CURRENTLY_ON(BrowserThread::IO);
326 DVLOG(1) << "AudioRendererHost@" << this
327 << "::OnCreateStream(stream_id=" << stream_id
328 << ", render_view_id=" << render_view_id
329 << ", session_id=" << session_id << ")";
330 DCHECK_GT(render_view_id, 0);
331 DCHECK_GT(render_frame_id, 0);
333 // media::AudioParameters is validated in the deserializer.
334 if (LookupById(stream_id) != NULL) {
335 SendErrorMessage(stream_id);
339 // Initialize the |output_device_id| to an empty string which indicates that
340 // the default device should be used. If a StreamDeviceInfo instance was found
341 // though, then we use the matched output device.
342 std::string output_device_id;
343 const StreamDeviceInfo* info = media_stream_manager_->
344 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
346 output_device_id = info->device.matched_output_device_id;
348 // Create the shared memory and share with the renderer process.
349 uint32 shared_memory_size = AudioBus::CalculateMemorySize(params);
350 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
351 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
352 SendErrorMessage(stream_id);
356 scoped_ptr<AudioSyncReader> reader(
357 new AudioSyncReader(shared_memory.get(), params));
358 if (!reader->Init()) {
359 SendErrorMessage(stream_id);
363 MediaObserver* const media_observer =
364 GetContentClient()->browser()->GetMediaObserver();
366 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
368 scoped_ptr<AudioEntry> entry(new AudioEntry(this,
374 shared_memory.Pass(),
376 if (mirroring_manager_) {
377 mirroring_manager_->AddDiverter(
378 render_process_id_, entry->render_frame_id(), entry->controller());
380 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
381 audio_log_->OnCreated(stream_id, params, output_device_id);
384 void AudioRendererHost::OnPlayStream(int stream_id) {
385 DCHECK_CURRENTLY_ON(BrowserThread::IO);
387 AudioEntry* entry = LookupById(stream_id);
389 SendErrorMessage(stream_id);
393 entry->controller()->Play();
394 audio_log_->OnStarted(stream_id);
397 void AudioRendererHost::OnPauseStream(int stream_id) {
398 DCHECK_CURRENTLY_ON(BrowserThread::IO);
400 AudioEntry* entry = LookupById(stream_id);
402 SendErrorMessage(stream_id);
406 entry->controller()->Pause();
407 audio_log_->OnStopped(stream_id);
410 void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
411 DCHECK_CURRENTLY_ON(BrowserThread::IO);
413 AudioEntry* entry = LookupById(stream_id);
415 SendErrorMessage(stream_id);
419 // Make sure the volume is valid.
420 if (volume < 0 || volume > 1.0)
422 entry->controller()->SetVolume(volume);
423 audio_log_->OnSetVolume(stream_id, volume);
426 void AudioRendererHost::SendErrorMessage(int stream_id) {
427 Send(new AudioMsg_NotifyStreamStateChanged(
428 stream_id, media::AudioOutputIPCDelegate::kError));
431 void AudioRendererHost::OnCloseStream(int stream_id) {
432 DCHECK_CURRENTLY_ON(BrowserThread::IO);
434 // Prevent oustanding callbacks from attempting to close/delete the same
436 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
437 if (i == audio_entries_.end())
439 scoped_ptr<AudioEntry> entry(i->second);
440 audio_entries_.erase(i);
442 media::AudioOutputController* const controller = entry->controller();
443 if (mirroring_manager_)
444 mirroring_manager_->RemoveDiverter(controller);
446 base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry)));
447 audio_log_->OnClosed(stream_id);
450 void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
451 DCHECK_CURRENTLY_ON(BrowserThread::IO);
452 AudioStreamMonitor::StopMonitoringStream(
453 render_process_id_, entry->render_frame_id(), entry->stream_id());
454 UpdateNumPlayingStreams(entry.get(), false);
457 void AudioRendererHost::ReportErrorAndClose(int stream_id) {
458 DCHECK_CURRENTLY_ON(BrowserThread::IO);
460 // Make sure this isn't a stray callback executing after the stream has been
461 // closed, so error notifications aren't sent after clients believe the stream
463 if (!LookupById(stream_id))
466 SendErrorMessage(stream_id);
468 audio_log_->OnError(stream_id);
469 OnCloseStream(stream_id);
472 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
473 DCHECK_CURRENTLY_ON(BrowserThread::IO);
475 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id);
476 return i != audio_entries_.end() ? i->second : NULL;
479 void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry,
481 DCHECK_CURRENTLY_ON(BrowserThread::IO);
482 if (entry->playing() == is_playing)
485 bool should_alert_resource_scheduler;
487 should_alert_resource_scheduler =
488 !RenderViewHasActiveAudio(entry->render_view_id());
489 entry->set_playing(true);
490 base::AtomicRefCountInc(&num_playing_streams_);
492 entry->set_playing(false);
493 should_alert_resource_scheduler =
494 !RenderViewHasActiveAudio(entry->render_view_id());
495 base::AtomicRefCountDec(&num_playing_streams_);
498 if (should_alert_resource_scheduler && ResourceDispatcherHostImpl::Get()) {
499 ResourceDispatcherHostImpl::Get()->OnAudioRenderHostStreamStateChanged(
500 render_process_id_, entry->render_view_id(), is_playing);
504 bool AudioRendererHost::HasActiveAudio() {
505 return !base::AtomicRefCountIsZero(&num_playing_streams_);
508 bool AudioRendererHost::RenderViewHasActiveAudio(int render_view_id) const {
509 for (AudioEntryMap::const_iterator it = audio_entries_.begin();
510 it != audio_entries_.end();
512 AudioEntry* entry = it->second;
513 if (entry->render_view_id() == render_view_id && entry->playing())
519 #if defined(OS_TIZEN)
520 void AudioRendererHost::SetMediaStreamProperties(
521 const std::string& app_id,
522 const std::string& app_class) {
524 app_class_ = app_class;
528 } // namespace content