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