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/audio_stream_monitor.h"
14 #include "content/browser/media/capture/audio_mirroring_manager.h"
15 #include "content/browser/media/media_internals.h"
16 #include "content/browser/renderer_host/media/audio_input_device_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/base/audio_bus.h"
25 #include "media/base/limits.h"
27 using media::AudioBus;
28 using media::AudioManager;
32 class AudioRendererHost::AudioEntry
33 : public media::AudioOutputController::EventHandler {
35 AudioEntry(AudioRendererHost* host,
39 const media::AudioParameters& params,
40 const std::string& output_device_id,
41 scoped_ptr<base::SharedMemory> shared_memory,
42 scoped_ptr<media::AudioOutputController::SyncReader> reader);
43 virtual ~AudioEntry();
45 int stream_id() const {
49 int render_view_id() const {
50 return render_view_id_;
53 int render_frame_id() const { return render_frame_id_; }
55 media::AudioOutputController* controller() const { return controller_.get(); }
57 base::SharedMemory* shared_memory() {
58 return shared_memory_.get();
61 media::AudioOutputController::SyncReader* reader() const {
65 bool playing() const { return playing_; }
66 void set_playing(bool playing) { playing_ = playing; }
69 // media::AudioOutputController::EventHandler implementation.
70 virtual void OnCreated() OVERRIDE;
71 virtual void OnPlaying() OVERRIDE;
72 virtual void OnPaused() OVERRIDE;
73 virtual void OnError() OVERRIDE;
74 virtual void OnDeviceChange(int new_buffer_size, int new_sample_rate)
77 AudioRendererHost* const host_;
80 // The routing ID of the source render view/frame.
81 const int render_view_id_;
82 const int render_frame_id_;
84 // Shared memory for transmission of the audio data. Used by |reader_|.
85 const scoped_ptr<base::SharedMemory> shared_memory_;
87 // The synchronous reader to be used by |controller_|.
88 const scoped_ptr<media::AudioOutputController::SyncReader> reader_;
90 // The AudioOutputController that manages the audio stream.
91 const scoped_refptr<media::AudioOutputController> controller_;
96 AudioRendererHost::AudioEntry::AudioEntry(
97 AudioRendererHost* host,
101 const media::AudioParameters& params,
102 const std::string& output_device_id,
103 scoped_ptr<base::SharedMemory> shared_memory,
104 scoped_ptr<media::AudioOutputController::SyncReader> reader)
106 stream_id_(stream_id),
107 render_view_id_(render_view_id),
108 render_frame_id_(render_frame_id),
109 shared_memory_(shared_memory.Pass()),
110 reader_(reader.Pass()),
111 controller_(media::AudioOutputController::Create(host->audio_manager_,
117 DCHECK(controller_.get());
120 AudioRendererHost::AudioEntry::~AudioEntry() {}
122 ///////////////////////////////////////////////////////////////////////////////
123 // AudioRendererHost implementations.
125 AudioRendererHost::AudioRendererHost(
126 int render_process_id,
127 media::AudioManager* audio_manager,
128 AudioMirroringManager* mirroring_manager,
129 MediaInternals* media_internals,
130 MediaStreamManager* media_stream_manager)
131 : BrowserMessageFilter(AudioMsgStart),
132 render_process_id_(render_process_id),
133 audio_manager_(audio_manager),
134 mirroring_manager_(mirroring_manager),
135 audio_log_(media_internals->CreateAudioLog(
136 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)),
137 media_stream_manager_(media_stream_manager),
138 num_playing_streams_(0) {
139 DCHECK(audio_manager_);
140 DCHECK(media_stream_manager_);
143 AudioRendererHost::~AudioRendererHost() {
144 DCHECK(audio_entries_.empty());
147 void AudioRendererHost::GetOutputControllers(
149 const RenderViewHost::GetAudioOutputControllersCallback& callback) const {
150 BrowserThread::PostTaskAndReplyWithResult(
153 base::Bind(&AudioRendererHost::DoGetOutputControllers, this,
158 void AudioRendererHost::OnChannelClosing() {
159 // Since the IPC sender is gone, close all requested audio streams.
160 while (!audio_entries_.empty()) {
161 // Note: OnCloseStream() removes the entries from audio_entries_.
162 OnCloseStream(audio_entries_.begin()->first);
166 void AudioRendererHost::OnDestruct() const {
167 BrowserThread::DeleteOnIOThread::Destruct(this);
170 void AudioRendererHost::AudioEntry::OnCreated() {
171 BrowserThread::PostTask(
174 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_));
177 void AudioRendererHost::AudioEntry::OnPlaying() {
178 BrowserThread::PostTask(
181 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
187 void AudioRendererHost::AudioEntry::OnPaused() {
188 BrowserThread::PostTask(
191 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
197 void AudioRendererHost::AudioEntry::OnError() {
198 BrowserThread::PostTask(
201 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_));
204 void AudioRendererHost::AudioEntry::OnDeviceChange(int new_buffer_size,
205 int new_sample_rate) {
206 BrowserThread::PostTask(
209 base::Bind(base::IgnoreResult(&AudioRendererHost::Send), host_,
210 new AudioMsg_NotifyDeviceChanged(
211 stream_id_, new_buffer_size, new_sample_rate)));
214 void AudioRendererHost::DoCompleteCreation(int stream_id) {
215 DCHECK_CURRENTLY_ON(BrowserThread::IO);
218 DLOG(WARNING) << "Renderer process handle is invalid.";
219 ReportErrorAndClose(stream_id);
223 AudioEntry* const entry = LookupById(stream_id);
225 ReportErrorAndClose(stream_id);
229 // Once the audio stream is created then complete the creation process by
230 // mapping shared memory and sharing with the renderer process.
231 base::SharedMemoryHandle foreign_memory_handle;
232 if (!entry->shared_memory()->ShareToProcess(PeerHandle(),
233 &foreign_memory_handle)) {
234 // If we failed to map and share the shared memory then close the audio
235 // stream and send an error message.
236 ReportErrorAndClose(entry->stream_id());
240 AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader());
242 base::SyncSocket::TransitDescriptor socket_descriptor;
244 // If we failed to prepare the sync socket for the renderer then we fail
245 // the construction of audio stream.
246 if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) {
247 ReportErrorAndClose(entry->stream_id());
251 Send(new AudioMsg_NotifyStreamCreated(
252 entry->stream_id(), foreign_memory_handle, socket_descriptor,
253 entry->shared_memory()->requested_size()));
256 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
258 DCHECK_CURRENTLY_ON(BrowserThread::IO);
260 AudioEntry* const entry = LookupById(stream_id);
264 Send(new AudioMsg_NotifyStreamStateChanged(
266 is_playing ? media::AudioOutputIPCDelegate::kPlaying
267 : media::AudioOutputIPCDelegate::kPaused));
270 AudioStreamMonitor::StartMonitoringStream(
272 entry->render_frame_id(),
274 base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip,
275 entry->controller()));
276 // TODO(dalecurtis): See about using AudioStreamMonitor instead.
277 if (!entry->playing()) {
278 entry->set_playing(true);
279 base::AtomicRefCountInc(&num_playing_streams_);
282 AudioStreamMonitor::StopMonitoringStream(
283 render_process_id_, entry->render_frame_id(), entry->stream_id());
284 // TODO(dalecurtis): See about using AudioStreamMonitor instead.
285 if (entry->playing()) {
286 entry->set_playing(false);
287 base::AtomicRefCountDec(&num_playing_streams_);
292 RenderViewHost::AudioOutputControllerList
293 AudioRendererHost::DoGetOutputControllers(int render_view_id) const {
294 DCHECK_CURRENTLY_ON(BrowserThread::IO);
296 RenderViewHost::AudioOutputControllerList controllers;
297 AudioEntryMap::const_iterator it = audio_entries_.begin();
298 for (; it != audio_entries_.end(); ++it) {
299 AudioEntry* entry = it->second;
300 if (entry->render_view_id() == render_view_id)
301 controllers.push_back(entry->controller());
307 ///////////////////////////////////////////////////////////////////////////////
308 // IPC Messages handler
309 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
311 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message)
312 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
313 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
314 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
315 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
316 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
317 IPC_MESSAGE_UNHANDLED(handled = false)
318 IPC_END_MESSAGE_MAP()
323 void AudioRendererHost::OnCreateStream(
324 int stream_id, int render_view_id, int render_frame_id, int session_id,
325 const media::AudioParameters& params) {
326 DCHECK_CURRENTLY_ON(BrowserThread::IO);
328 DVLOG(1) << "AudioRendererHost@" << this
329 << "::OnCreateStream(stream_id=" << stream_id
330 << ", render_view_id=" << render_view_id
331 << ", session_id=" << session_id << ")";
332 DCHECK_GT(render_view_id, 0);
333 DCHECK_GT(render_frame_id, 0);
335 // media::AudioParameters is validated in the deserializer.
336 if (LookupById(stream_id) != NULL) {
337 SendErrorMessage(stream_id);
341 // Initialize the |output_device_id| to an empty string which indicates that
342 // the default device should be used. If a StreamDeviceInfo instance was found
343 // though, then we use the matched output device.
344 std::string output_device_id;
345 const StreamDeviceInfo* info = media_stream_manager_->
346 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
348 output_device_id = info->device.matched_output_device_id;
350 // Create the shared memory and share with the renderer process.
351 uint32 shared_memory_size = AudioBus::CalculateMemorySize(params);
352 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
353 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
354 SendErrorMessage(stream_id);
358 scoped_ptr<AudioSyncReader> reader(
359 new AudioSyncReader(shared_memory.get(), params));
360 if (!reader->Init()) {
361 SendErrorMessage(stream_id);
365 MediaObserver* const media_observer =
366 GetContentClient()->browser()->GetMediaObserver();
368 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
370 scoped_ptr<AudioEntry> entry(new AudioEntry(
377 shared_memory.Pass(),
378 reader.PassAs<media::AudioOutputController::SyncReader>()));
379 if (mirroring_manager_) {
380 mirroring_manager_->AddDiverter(
381 render_process_id_, entry->render_frame_id(), entry->controller());
383 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
384 audio_log_->OnCreated(stream_id, params, output_device_id);
387 void AudioRendererHost::OnPlayStream(int stream_id) {
388 DCHECK_CURRENTLY_ON(BrowserThread::IO);
390 AudioEntry* entry = LookupById(stream_id);
392 SendErrorMessage(stream_id);
396 entry->controller()->Play();
397 audio_log_->OnStarted(stream_id);
400 void AudioRendererHost::OnPauseStream(int stream_id) {
401 DCHECK_CURRENTLY_ON(BrowserThread::IO);
403 AudioEntry* entry = LookupById(stream_id);
405 SendErrorMessage(stream_id);
409 entry->controller()->Pause();
410 audio_log_->OnStopped(stream_id);
413 void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
414 DCHECK_CURRENTLY_ON(BrowserThread::IO);
416 AudioEntry* entry = LookupById(stream_id);
418 SendErrorMessage(stream_id);
422 // Make sure the volume is valid.
423 if (volume < 0 || volume > 1.0)
425 entry->controller()->SetVolume(volume);
426 audio_log_->OnSetVolume(stream_id, volume);
429 void AudioRendererHost::SendErrorMessage(int stream_id) {
430 Send(new AudioMsg_NotifyStreamStateChanged(
431 stream_id, media::AudioOutputIPCDelegate::kError));
434 void AudioRendererHost::OnCloseStream(int stream_id) {
435 DCHECK_CURRENTLY_ON(BrowserThread::IO);
437 // Prevent oustanding callbacks from attempting to close/delete the same
439 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
440 if (i == audio_entries_.end())
442 scoped_ptr<AudioEntry> entry(i->second);
443 audio_entries_.erase(i);
445 media::AudioOutputController* const controller = entry->controller();
446 if (mirroring_manager_)
447 mirroring_manager_->RemoveDiverter(controller);
449 base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry)));
450 audio_log_->OnClosed(stream_id);
453 void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
454 DCHECK_CURRENTLY_ON(BrowserThread::IO);
455 AudioStreamMonitor::StopMonitoringStream(
456 render_process_id_, entry->render_frame_id(), entry->stream_id());
457 if (entry->playing())
458 base::AtomicRefCountDec(&num_playing_streams_);
461 void AudioRendererHost::ReportErrorAndClose(int stream_id) {
462 DCHECK_CURRENTLY_ON(BrowserThread::IO);
464 // Make sure this isn't a stray callback executing after the stream has been
465 // closed, so error notifications aren't sent after clients believe the stream
467 if (!LookupById(stream_id))
470 SendErrorMessage(stream_id);
472 audio_log_->OnError(stream_id);
473 OnCloseStream(stream_id);
476 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
477 DCHECK_CURRENTLY_ON(BrowserThread::IO);
479 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id);
480 return i != audio_entries_.end() ? i->second : NULL;
483 bool AudioRendererHost::HasActiveAudio() {
484 return !base::AtomicRefCountIsZero(&num_playing_streams_);
487 } // namespace content