• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/capture/audio_mirroring_manager.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_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"
25 
26 using media::AudioBus;
27 using media::AudioManager;
28 
29 namespace content {
30 
31 class AudioRendererHost::AudioEntry
32     : public media::AudioOutputController::EventHandler {
33  public:
34   AudioEntry(AudioRendererHost* host,
35              int stream_id,
36              int render_view_id,
37              int render_frame_id,
38              const media::AudioParameters& params,
39              const std::string& output_device_id,
40              scoped_ptr<base::SharedMemory> shared_memory,
41              scoped_ptr<media::AudioOutputController::SyncReader> reader);
42   virtual ~AudioEntry();
43 
stream_id() const44   int stream_id() const {
45     return stream_id_;
46   }
47 
render_view_id() const48   int render_view_id() const {
49     return render_view_id_;
50   }
51 
render_frame_id() const52   int render_frame_id() const { return render_frame_id_; }
53 
controller() const54   media::AudioOutputController* controller() const { return controller_.get(); }
55 
shared_memory()56   base::SharedMemory* shared_memory() {
57     return shared_memory_.get();
58   }
59 
reader() const60   media::AudioOutputController::SyncReader* reader() const {
61     return reader_.get();
62   }
63 
playing() const64   bool playing() const { return playing_; }
set_playing(bool playing)65   void set_playing(bool playing) { playing_ = playing; }
66 
67  private:
68   // media::AudioOutputController::EventHandler implementation.
69   virtual void OnCreated() OVERRIDE;
70   virtual void OnPlaying() OVERRIDE;
71   virtual void OnPaused() OVERRIDE;
72   virtual void OnError() OVERRIDE;
73   virtual void OnDeviceChange(int new_buffer_size, int new_sample_rate)
74       OVERRIDE;
75 
76   AudioRendererHost* const host_;
77   const int stream_id_;
78 
79   // The routing ID of the source render view/frame.
80   const int render_view_id_;
81   const int render_frame_id_;
82 
83   // Shared memory for transmission of the audio data.  Used by |reader_|.
84   const scoped_ptr<base::SharedMemory> shared_memory_;
85 
86   // The synchronous reader to be used by |controller_|.
87   const scoped_ptr<media::AudioOutputController::SyncReader> reader_;
88 
89   // The AudioOutputController that manages the audio stream.
90   const scoped_refptr<media::AudioOutputController> controller_;
91 
92   bool playing_;
93 };
94 
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)95 AudioRendererHost::AudioEntry::AudioEntry(
96     AudioRendererHost* host,
97     int stream_id,
98     int render_view_id,
99     int render_frame_id,
100     const media::AudioParameters& params,
101     const std::string& output_device_id,
102     scoped_ptr<base::SharedMemory> shared_memory,
103     scoped_ptr<media::AudioOutputController::SyncReader> reader)
104     : host_(host),
105       stream_id_(stream_id),
106       render_view_id_(render_view_id),
107       render_frame_id_(render_frame_id),
108       shared_memory_(shared_memory.Pass()),
109       reader_(reader.Pass()),
110       controller_(media::AudioOutputController::Create(host->audio_manager_,
111                                                        this,
112                                                        params,
113                                                        output_device_id,
114                                                        reader_.get())),
115       playing_(false) {
116   DCHECK(controller_.get());
117 }
118 
~AudioEntry()119 AudioRendererHost::AudioEntry::~AudioEntry() {}
120 
121 ///////////////////////////////////////////////////////////////////////////////
122 // AudioRendererHost implementations.
123 
AudioRendererHost(int render_process_id,media::AudioManager * audio_manager,AudioMirroringManager * mirroring_manager,MediaInternals * media_internals,MediaStreamManager * media_stream_manager)124 AudioRendererHost::AudioRendererHost(
125     int render_process_id,
126     media::AudioManager* audio_manager,
127     AudioMirroringManager* mirroring_manager,
128     MediaInternals* media_internals,
129     MediaStreamManager* media_stream_manager)
130     : BrowserMessageFilter(AudioMsgStart),
131       render_process_id_(render_process_id),
132       audio_manager_(audio_manager),
133       mirroring_manager_(mirroring_manager),
134       audio_log_(media_internals->CreateAudioLog(
135           media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)),
136       media_stream_manager_(media_stream_manager),
137       num_playing_streams_(0) {
138   DCHECK(audio_manager_);
139   DCHECK(media_stream_manager_);
140 }
141 
~AudioRendererHost()142 AudioRendererHost::~AudioRendererHost() {
143   DCHECK(audio_entries_.empty());
144 }
145 
GetOutputControllers(int render_view_id,const RenderViewHost::GetAudioOutputControllersCallback & callback) const146 void AudioRendererHost::GetOutputControllers(
147     int render_view_id,
148     const RenderViewHost::GetAudioOutputControllersCallback& callback) const {
149   BrowserThread::PostTaskAndReplyWithResult(
150       BrowserThread::IO,
151       FROM_HERE,
152       base::Bind(&AudioRendererHost::DoGetOutputControllers, this,
153                  render_view_id),
154       callback);
155 }
156 
OnChannelClosing()157 void AudioRendererHost::OnChannelClosing() {
158   // Since the IPC sender is gone, close all requested audio streams.
159   while (!audio_entries_.empty()) {
160     // Note: OnCloseStream() removes the entries from audio_entries_.
161     OnCloseStream(audio_entries_.begin()->first);
162   }
163 }
164 
OnDestruct() const165 void AudioRendererHost::OnDestruct() const {
166   BrowserThread::DeleteOnIOThread::Destruct(this);
167 }
168 
OnCreated()169 void AudioRendererHost::AudioEntry::OnCreated() {
170   BrowserThread::PostTask(
171       BrowserThread::IO,
172       FROM_HERE,
173       base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_));
174 }
175 
OnPlaying()176 void AudioRendererHost::AudioEntry::OnPlaying() {
177   BrowserThread::PostTask(
178       BrowserThread::IO,
179       FROM_HERE,
180       base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
181                  host_,
182                  stream_id_,
183                  true));
184 }
185 
OnPaused()186 void AudioRendererHost::AudioEntry::OnPaused() {
187   BrowserThread::PostTask(
188       BrowserThread::IO,
189       FROM_HERE,
190       base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
191                  host_,
192                  stream_id_,
193                  false));
194 }
195 
OnError()196 void AudioRendererHost::AudioEntry::OnError() {
197   BrowserThread::PostTask(
198       BrowserThread::IO,
199       FROM_HERE,
200       base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_));
201 }
202 
OnDeviceChange(int new_buffer_size,int new_sample_rate)203 void AudioRendererHost::AudioEntry::OnDeviceChange(int new_buffer_size,
204                                                    int new_sample_rate) {
205   BrowserThread::PostTask(
206       BrowserThread::IO,
207       FROM_HERE,
208       base::Bind(base::IgnoreResult(&AudioRendererHost::Send), host_,
209                  new AudioMsg_NotifyDeviceChanged(
210                      stream_id_, new_buffer_size, new_sample_rate)));
211 }
212 
DoCompleteCreation(int stream_id)213 void AudioRendererHost::DoCompleteCreation(int stream_id) {
214   DCHECK_CURRENTLY_ON(BrowserThread::IO);
215 
216   if (!PeerHandle()) {
217     DLOG(WARNING) << "Renderer process handle is invalid.";
218     ReportErrorAndClose(stream_id);
219     return;
220   }
221 
222   AudioEntry* const entry = LookupById(stream_id);
223   if (!entry) {
224     ReportErrorAndClose(stream_id);
225     return;
226   }
227 
228   // Once the audio stream is created then complete the creation process by
229   // mapping shared memory and sharing with the renderer process.
230   base::SharedMemoryHandle foreign_memory_handle;
231   if (!entry->shared_memory()->ShareToProcess(PeerHandle(),
232                                               &foreign_memory_handle)) {
233     // If we failed to map and share the shared memory then close the audio
234     // stream and send an error message.
235     ReportErrorAndClose(entry->stream_id());
236     return;
237   }
238 
239   AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader());
240 
241 #if defined(OS_WIN)
242   base::SyncSocket::Handle foreign_socket_handle;
243 #else
244   base::FileDescriptor foreign_socket_handle;
245 #endif
246 
247   // If we failed to prepare the sync socket for the renderer then we fail
248   // the construction of audio stream.
249   if (!reader->PrepareForeignSocketHandle(PeerHandle(),
250                                           &foreign_socket_handle)) {
251     ReportErrorAndClose(entry->stream_id());
252     return;
253   }
254 
255   Send(new AudioMsg_NotifyStreamCreated(
256       entry->stream_id(),
257       foreign_memory_handle,
258       foreign_socket_handle,
259       entry->shared_memory()->requested_size()));
260 }
261 
DoNotifyStreamStateChanged(int stream_id,bool is_playing)262 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
263                                                    bool is_playing) {
264   DCHECK_CURRENTLY_ON(BrowserThread::IO);
265 
266   AudioEntry* const entry = LookupById(stream_id);
267   if (!entry)
268     return;
269 
270   Send(new AudioMsg_NotifyStreamStateChanged(
271       stream_id,
272       is_playing ? media::AudioOutputIPCDelegate::kPlaying
273                  : media::AudioOutputIPCDelegate::kPaused));
274 
275   MediaObserver* const media_observer =
276       GetContentClient()->browser()->GetMediaObserver();
277   if (media_observer) {
278     if (is_playing) {
279       media_observer->OnAudioStreamPlaying(
280           render_process_id_,
281           entry->render_frame_id(),
282           entry->stream_id(),
283           base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip,
284                      entry->controller()));
285       if (!entry->playing()) {
286         entry->set_playing(true);
287         base::AtomicRefCountInc(&num_playing_streams_);
288       }
289     } else {
290       media_observer->OnAudioStreamStopped(render_process_id_,
291                                            entry->render_frame_id(),
292                                            entry->stream_id());
293       if (entry->playing()) {
294         entry->set_playing(false);
295         base::AtomicRefCountDec(&num_playing_streams_);
296       }
297     }
298   }
299 }
300 
301 RenderViewHost::AudioOutputControllerList
DoGetOutputControllers(int render_view_id) const302 AudioRendererHost::DoGetOutputControllers(int render_view_id) const {
303   DCHECK_CURRENTLY_ON(BrowserThread::IO);
304 
305   RenderViewHost::AudioOutputControllerList controllers;
306   AudioEntryMap::const_iterator it = audio_entries_.begin();
307   for (; it != audio_entries_.end(); ++it) {
308     AudioEntry* entry = it->second;
309     if (entry->render_view_id() == render_view_id)
310       controllers.push_back(entry->controller());
311   }
312 
313   return controllers;
314 }
315 
316 ///////////////////////////////////////////////////////////////////////////////
317 // IPC Messages handler
OnMessageReceived(const IPC::Message & message)318 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
319   bool handled = true;
320   IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message)
321     IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
322     IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
323     IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
324     IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
325     IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
326     IPC_MESSAGE_UNHANDLED(handled = false)
327   IPC_END_MESSAGE_MAP()
328 
329   return handled;
330 }
331 
OnCreateStream(int stream_id,int render_view_id,int render_frame_id,int session_id,const media::AudioParameters & params)332 void AudioRendererHost::OnCreateStream(
333     int stream_id, int render_view_id, int render_frame_id, int session_id,
334     const media::AudioParameters& params) {
335   DCHECK_CURRENTLY_ON(BrowserThread::IO);
336 
337   DVLOG(1) << "AudioRendererHost@" << this
338            << "::OnCreateStream(stream_id=" << stream_id
339            << ", render_view_id=" << render_view_id
340            << ", session_id=" << session_id << ")";
341   DCHECK_GT(render_view_id, 0);
342   DCHECK_GT(render_frame_id, 0);
343 
344   // media::AudioParameters is validated in the deserializer.
345   if (LookupById(stream_id) != NULL) {
346     SendErrorMessage(stream_id);
347     return;
348   }
349 
350   // Initialize the |output_device_id| to an empty string which indicates that
351   // the default device should be used. If a StreamDeviceInfo instance was found
352   // though, then we use the matched output device.
353   std::string output_device_id;
354   const StreamDeviceInfo* info = media_stream_manager_->
355       audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
356   if (info)
357     output_device_id = info->device.matched_output_device_id;
358 
359   // Create the shared memory and share with the renderer process.
360   // For synchronized I/O (if input_channels > 0) then we allocate
361   // extra memory after the output data for the input data.
362   uint32 shared_memory_size = AudioBus::CalculateMemorySize(params);
363   scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
364   if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
365     SendErrorMessage(stream_id);
366     return;
367   }
368 
369   scoped_ptr<AudioSyncReader> reader(
370       new AudioSyncReader(shared_memory.get(), params));
371   if (!reader->Init()) {
372     SendErrorMessage(stream_id);
373     return;
374   }
375 
376   MediaObserver* const media_observer =
377       GetContentClient()->browser()->GetMediaObserver();
378   if (media_observer)
379     media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
380 
381   scoped_ptr<AudioEntry> entry(new AudioEntry(
382       this,
383       stream_id,
384       render_view_id,
385       render_frame_id,
386       params,
387       output_device_id,
388       shared_memory.Pass(),
389       reader.PassAs<media::AudioOutputController::SyncReader>()));
390   if (mirroring_manager_) {
391     mirroring_manager_->AddDiverter(
392         render_process_id_, entry->render_view_id(), entry->controller());
393   }
394   audio_entries_.insert(std::make_pair(stream_id, entry.release()));
395   audio_log_->OnCreated(stream_id, params, output_device_id);
396 }
397 
OnPlayStream(int stream_id)398 void AudioRendererHost::OnPlayStream(int stream_id) {
399   DCHECK_CURRENTLY_ON(BrowserThread::IO);
400 
401   AudioEntry* entry = LookupById(stream_id);
402   if (!entry) {
403     SendErrorMessage(stream_id);
404     return;
405   }
406 
407   entry->controller()->Play();
408   audio_log_->OnStarted(stream_id);
409 }
410 
OnPauseStream(int stream_id)411 void AudioRendererHost::OnPauseStream(int stream_id) {
412   DCHECK_CURRENTLY_ON(BrowserThread::IO);
413 
414   AudioEntry* entry = LookupById(stream_id);
415   if (!entry) {
416     SendErrorMessage(stream_id);
417     return;
418   }
419 
420   entry->controller()->Pause();
421   audio_log_->OnStopped(stream_id);
422 }
423 
OnSetVolume(int stream_id,double volume)424 void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
425   DCHECK_CURRENTLY_ON(BrowserThread::IO);
426 
427   AudioEntry* entry = LookupById(stream_id);
428   if (!entry) {
429     SendErrorMessage(stream_id);
430     return;
431   }
432 
433   // Make sure the volume is valid.
434   if (volume < 0 || volume > 1.0)
435     return;
436   entry->controller()->SetVolume(volume);
437   audio_log_->OnSetVolume(stream_id, volume);
438 }
439 
SendErrorMessage(int stream_id)440 void AudioRendererHost::SendErrorMessage(int stream_id) {
441   Send(new AudioMsg_NotifyStreamStateChanged(
442       stream_id, media::AudioOutputIPCDelegate::kError));
443 }
444 
OnCloseStream(int stream_id)445 void AudioRendererHost::OnCloseStream(int stream_id) {
446   DCHECK_CURRENTLY_ON(BrowserThread::IO);
447 
448   // Prevent oustanding callbacks from attempting to close/delete the same
449   // AudioEntry twice.
450   AudioEntryMap::iterator i = audio_entries_.find(stream_id);
451   if (i == audio_entries_.end())
452     return;
453   scoped_ptr<AudioEntry> entry(i->second);
454   audio_entries_.erase(i);
455 
456   media::AudioOutputController* const controller = entry->controller();
457   if (mirroring_manager_) {
458     mirroring_manager_->RemoveDiverter(
459         render_process_id_, entry->render_view_id(), controller);
460   }
461   controller->Close(
462       base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry)));
463   audio_log_->OnClosed(stream_id);
464 }
465 
DeleteEntry(scoped_ptr<AudioEntry> entry)466 void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
467   DCHECK_CURRENTLY_ON(BrowserThread::IO);
468 
469   // At this point, make the final "say" in audio playback state.
470   MediaObserver* const media_observer =
471       GetContentClient()->browser()->GetMediaObserver();
472   if (media_observer) {
473     media_observer->OnAudioStreamStopped(render_process_id_,
474                                          entry->render_frame_id(),
475                                          entry->stream_id());
476     if (entry->playing())
477       base::AtomicRefCountDec(&num_playing_streams_);
478   }
479 }
480 
ReportErrorAndClose(int stream_id)481 void AudioRendererHost::ReportErrorAndClose(int stream_id) {
482   DCHECK_CURRENTLY_ON(BrowserThread::IO);
483 
484   // Make sure this isn't a stray callback executing after the stream has been
485   // closed, so error notifications aren't sent after clients believe the stream
486   // is closed.
487   if (!LookupById(stream_id))
488     return;
489 
490   SendErrorMessage(stream_id);
491 
492   audio_log_->OnError(stream_id);
493   OnCloseStream(stream_id);
494 }
495 
LookupById(int stream_id)496 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
497   DCHECK_CURRENTLY_ON(BrowserThread::IO);
498 
499   AudioEntryMap::const_iterator i = audio_entries_.find(stream_id);
500   return i != audio_entries_.end() ? i->second : NULL;
501 }
502 
HasActiveAudio()503 bool AudioRendererHost::HasActiveAudio() {
504   return !base::AtomicRefCountIsZero(&num_playing_streams_);
505 }
506 
507 }  // namespace content
508