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