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