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