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