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