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.
4
5 #include "content/browser/renderer_host/media/audio_renderer_host.h"
6
7 #include "base/bind.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"
26
27 using media::AudioBus;
28 using media::AudioManager;
29
30 namespace content {
31
32 class AudioRendererHost::AudioEntry
33 : public media::AudioOutputController::EventHandler {
34 public:
35 AudioEntry(AudioRendererHost* host,
36 int stream_id,
37 int render_view_id,
38 int render_frame_id,
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();
44
stream_id() const45 int stream_id() const {
46 return stream_id_;
47 }
48
render_view_id() const49 int render_view_id() const {
50 return render_view_id_;
51 }
52
render_frame_id() const53 int render_frame_id() const { return render_frame_id_; }
54
controller() const55 media::AudioOutputController* controller() const { return controller_.get(); }
56
shared_memory()57 base::SharedMemory* shared_memory() {
58 return shared_memory_.get();
59 }
60
reader() const61 media::AudioOutputController::SyncReader* reader() const {
62 return reader_.get();
63 }
64
playing() const65 bool playing() const { return playing_; }
set_playing(bool playing)66 void set_playing(bool playing) { playing_ = playing; }
67
68 private:
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)
75 OVERRIDE;
76
77 AudioRendererHost* const host_;
78 const int stream_id_;
79
80 // The routing ID of the source render view/frame.
81 const int render_view_id_;
82 const int render_frame_id_;
83
84 // Shared memory for transmission of the audio data. Used by |reader_|.
85 const scoped_ptr<base::SharedMemory> shared_memory_;
86
87 // The synchronous reader to be used by |controller_|.
88 const scoped_ptr<media::AudioOutputController::SyncReader> reader_;
89
90 // The AudioOutputController that manages the audio stream.
91 const scoped_refptr<media::AudioOutputController> controller_;
92
93 bool playing_;
94 };
95
AudioEntry(AudioRendererHost * host,int stream_id,int render_view_id,int render_frame_id,const media::AudioParameters & params,const std::string & output_device_id,scoped_ptr<base::SharedMemory> shared_memory,scoped_ptr<media::AudioOutputController::SyncReader> reader)96 AudioRendererHost::AudioEntry::AudioEntry(
97 AudioRendererHost* host,
98 int stream_id,
99 int render_view_id,
100 int render_frame_id,
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)
105 : host_(host),
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_,
112 this,
113 params,
114 output_device_id,
115 reader_.get())),
116 playing_(false) {
117 DCHECK(controller_.get());
118 }
119
~AudioEntry()120 AudioRendererHost::AudioEntry::~AudioEntry() {}
121
122 ///////////////////////////////////////////////////////////////////////////////
123 // AudioRendererHost implementations.
124
AudioRendererHost(int render_process_id,media::AudioManager * audio_manager,AudioMirroringManager * mirroring_manager,MediaInternals * media_internals,MediaStreamManager * media_stream_manager)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_);
141 }
142
~AudioRendererHost()143 AudioRendererHost::~AudioRendererHost() {
144 DCHECK(audio_entries_.empty());
145 }
146
GetOutputControllers(int render_view_id,const RenderViewHost::GetAudioOutputControllersCallback & callback) const147 void AudioRendererHost::GetOutputControllers(
148 int render_view_id,
149 const RenderViewHost::GetAudioOutputControllersCallback& callback) const {
150 BrowserThread::PostTaskAndReplyWithResult(
151 BrowserThread::IO,
152 FROM_HERE,
153 base::Bind(&AudioRendererHost::DoGetOutputControllers, this,
154 render_view_id),
155 callback);
156 }
157
OnChannelClosing()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);
163 }
164 }
165
OnDestruct() const166 void AudioRendererHost::OnDestruct() const {
167 BrowserThread::DeleteOnIOThread::Destruct(this);
168 }
169
OnCreated()170 void AudioRendererHost::AudioEntry::OnCreated() {
171 BrowserThread::PostTask(
172 BrowserThread::IO,
173 FROM_HERE,
174 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_));
175 }
176
OnPlaying()177 void AudioRendererHost::AudioEntry::OnPlaying() {
178 BrowserThread::PostTask(
179 BrowserThread::IO,
180 FROM_HERE,
181 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
182 host_,
183 stream_id_,
184 true));
185 }
186
OnPaused()187 void AudioRendererHost::AudioEntry::OnPaused() {
188 BrowserThread::PostTask(
189 BrowserThread::IO,
190 FROM_HERE,
191 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
192 host_,
193 stream_id_,
194 false));
195 }
196
OnError()197 void AudioRendererHost::AudioEntry::OnError() {
198 BrowserThread::PostTask(
199 BrowserThread::IO,
200 FROM_HERE,
201 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_));
202 }
203
OnDeviceChange(int new_buffer_size,int new_sample_rate)204 void AudioRendererHost::AudioEntry::OnDeviceChange(int new_buffer_size,
205 int new_sample_rate) {
206 BrowserThread::PostTask(
207 BrowserThread::IO,
208 FROM_HERE,
209 base::Bind(base::IgnoreResult(&AudioRendererHost::Send), host_,
210 new AudioMsg_NotifyDeviceChanged(
211 stream_id_, new_buffer_size, new_sample_rate)));
212 }
213
DoCompleteCreation(int stream_id)214 void AudioRendererHost::DoCompleteCreation(int stream_id) {
215 DCHECK_CURRENTLY_ON(BrowserThread::IO);
216
217 if (!PeerHandle()) {
218 DLOG(WARNING) << "Renderer process handle is invalid.";
219 ReportErrorAndClose(stream_id);
220 return;
221 }
222
223 AudioEntry* const entry = LookupById(stream_id);
224 if (!entry) {
225 ReportErrorAndClose(stream_id);
226 return;
227 }
228
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());
237 return;
238 }
239
240 AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader());
241
242 base::SyncSocket::TransitDescriptor socket_descriptor;
243
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());
248 return;
249 }
250
251 Send(new AudioMsg_NotifyStreamCreated(
252 entry->stream_id(), foreign_memory_handle, socket_descriptor,
253 entry->shared_memory()->requested_size()));
254 }
255
DoNotifyStreamStateChanged(int stream_id,bool is_playing)256 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
257 bool is_playing) {
258 DCHECK_CURRENTLY_ON(BrowserThread::IO);
259
260 AudioEntry* const entry = LookupById(stream_id);
261 if (!entry)
262 return;
263
264 Send(new AudioMsg_NotifyStreamStateChanged(
265 stream_id,
266 is_playing ? media::AudioOutputIPCDelegate::kPlaying
267 : media::AudioOutputIPCDelegate::kPaused));
268
269 if (is_playing) {
270 AudioStreamMonitor::StartMonitoringStream(
271 render_process_id_,
272 entry->render_frame_id(),
273 entry->stream_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_);
280 }
281 } else {
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_);
288 }
289 }
290 }
291
292 RenderViewHost::AudioOutputControllerList
DoGetOutputControllers(int render_view_id) const293 AudioRendererHost::DoGetOutputControllers(int render_view_id) const {
294 DCHECK_CURRENTLY_ON(BrowserThread::IO);
295
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());
302 }
303
304 return controllers;
305 }
306
307 ///////////////////////////////////////////////////////////////////////////////
308 // IPC Messages handler
OnMessageReceived(const IPC::Message & message)309 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
310 bool handled = true;
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()
319
320 return handled;
321 }
322
OnCreateStream(int stream_id,int render_view_id,int render_frame_id,int session_id,const media::AudioParameters & params)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);
327
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);
334
335 // media::AudioParameters is validated in the deserializer.
336 if (LookupById(stream_id) != NULL) {
337 SendErrorMessage(stream_id);
338 return;
339 }
340
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);
347 if (info)
348 output_device_id = info->device.matched_output_device_id;
349
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);
355 return;
356 }
357
358 scoped_ptr<AudioSyncReader> reader(
359 new AudioSyncReader(shared_memory.get(), params));
360 if (!reader->Init()) {
361 SendErrorMessage(stream_id);
362 return;
363 }
364
365 MediaObserver* const media_observer =
366 GetContentClient()->browser()->GetMediaObserver();
367 if (media_observer)
368 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
369
370 scoped_ptr<AudioEntry> entry(new AudioEntry(
371 this,
372 stream_id,
373 render_view_id,
374 render_frame_id,
375 params,
376 output_device_id,
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());
382 }
383 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
384 audio_log_->OnCreated(stream_id, params, output_device_id);
385 }
386
OnPlayStream(int stream_id)387 void AudioRendererHost::OnPlayStream(int stream_id) {
388 DCHECK_CURRENTLY_ON(BrowserThread::IO);
389
390 AudioEntry* entry = LookupById(stream_id);
391 if (!entry) {
392 SendErrorMessage(stream_id);
393 return;
394 }
395
396 entry->controller()->Play();
397 audio_log_->OnStarted(stream_id);
398 }
399
OnPauseStream(int stream_id)400 void AudioRendererHost::OnPauseStream(int stream_id) {
401 DCHECK_CURRENTLY_ON(BrowserThread::IO);
402
403 AudioEntry* entry = LookupById(stream_id);
404 if (!entry) {
405 SendErrorMessage(stream_id);
406 return;
407 }
408
409 entry->controller()->Pause();
410 audio_log_->OnStopped(stream_id);
411 }
412
OnSetVolume(int stream_id,double volume)413 void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
414 DCHECK_CURRENTLY_ON(BrowserThread::IO);
415
416 AudioEntry* entry = LookupById(stream_id);
417 if (!entry) {
418 SendErrorMessage(stream_id);
419 return;
420 }
421
422 // Make sure the volume is valid.
423 if (volume < 0 || volume > 1.0)
424 return;
425 entry->controller()->SetVolume(volume);
426 audio_log_->OnSetVolume(stream_id, volume);
427 }
428
SendErrorMessage(int stream_id)429 void AudioRendererHost::SendErrorMessage(int stream_id) {
430 Send(new AudioMsg_NotifyStreamStateChanged(
431 stream_id, media::AudioOutputIPCDelegate::kError));
432 }
433
OnCloseStream(int stream_id)434 void AudioRendererHost::OnCloseStream(int stream_id) {
435 DCHECK_CURRENTLY_ON(BrowserThread::IO);
436
437 // Prevent oustanding callbacks from attempting to close/delete the same
438 // AudioEntry twice.
439 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
440 if (i == audio_entries_.end())
441 return;
442 scoped_ptr<AudioEntry> entry(i->second);
443 audio_entries_.erase(i);
444
445 media::AudioOutputController* const controller = entry->controller();
446 if (mirroring_manager_)
447 mirroring_manager_->RemoveDiverter(controller);
448 controller->Close(
449 base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry)));
450 audio_log_->OnClosed(stream_id);
451 }
452
DeleteEntry(scoped_ptr<AudioEntry> entry)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_);
459 }
460
ReportErrorAndClose(int stream_id)461 void AudioRendererHost::ReportErrorAndClose(int stream_id) {
462 DCHECK_CURRENTLY_ON(BrowserThread::IO);
463
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
466 // is closed.
467 if (!LookupById(stream_id))
468 return;
469
470 SendErrorMessage(stream_id);
471
472 audio_log_->OnError(stream_id);
473 OnCloseStream(stream_id);
474 }
475
LookupById(int stream_id)476 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
477 DCHECK_CURRENTLY_ON(BrowserThread::IO);
478
479 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id);
480 return i != audio_entries_.end() ? i->second : NULL;
481 }
482
HasActiveAudio()483 bool AudioRendererHost::HasActiveAudio() {
484 return !base::AtomicRefCountIsZero(&num_playing_streams_);
485 }
486
487 } // namespace content
488