Home | History | Annotate | Download | only in media
      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/renderer/media/audio_message_filter.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/message_loop/message_loop_proxy.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "content/common/media/audio_messages.h"
     11 #include "content/renderer/media/webrtc_logging.h"
     12 #include "content/renderer/render_thread_impl.h"
     13 #include "ipc/ipc_logging.h"
     14 
     15 namespace content {
     16 
     17 namespace {
     18 const int kStreamIDNotSet = -1;
     19 }
     20 
     21 class AudioMessageFilter::AudioOutputIPCImpl
     22     : public NON_EXPORTED_BASE(media::AudioOutputIPC) {
     23  public:
     24   AudioOutputIPCImpl(const scoped_refptr<AudioMessageFilter>& filter,
     25                      int render_view_id,
     26                      int render_frame_id);
     27   virtual ~AudioOutputIPCImpl();
     28 
     29   // media::AudioOutputIPC implementation.
     30   virtual void CreateStream(media::AudioOutputIPCDelegate* delegate,
     31                             const media::AudioParameters& params,
     32                             int session_id) OVERRIDE;
     33   virtual void PlayStream() OVERRIDE;
     34   virtual void PauseStream() OVERRIDE;
     35   virtual void CloseStream() OVERRIDE;
     36   virtual void SetVolume(double volume) OVERRIDE;
     37 
     38  private:
     39   const scoped_refptr<AudioMessageFilter> filter_;
     40   const int render_view_id_;
     41   const int render_frame_id_;
     42   int stream_id_;
     43 };
     44 
     45 AudioMessageFilter* AudioMessageFilter::g_filter = NULL;
     46 
     47 AudioMessageFilter::AudioMessageFilter(
     48     const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
     49     : sender_(NULL),
     50       audio_hardware_config_(NULL),
     51       io_message_loop_(io_message_loop) {
     52   DCHECK(!g_filter);
     53   g_filter = this;
     54 }
     55 
     56 AudioMessageFilter::~AudioMessageFilter() {
     57   DCHECK_EQ(g_filter, this);
     58   g_filter = NULL;
     59 }
     60 
     61 // static
     62 AudioMessageFilter* AudioMessageFilter::Get() {
     63   return g_filter;
     64 }
     65 
     66 AudioMessageFilter::AudioOutputIPCImpl::AudioOutputIPCImpl(
     67     const scoped_refptr<AudioMessageFilter>& filter,
     68     int render_view_id,
     69     int render_frame_id)
     70     : filter_(filter),
     71       render_view_id_(render_view_id),
     72       render_frame_id_(render_frame_id),
     73       stream_id_(kStreamIDNotSet) {}
     74 
     75 AudioMessageFilter::AudioOutputIPCImpl::~AudioOutputIPCImpl() {}
     76 
     77 scoped_ptr<media::AudioOutputIPC> AudioMessageFilter::CreateAudioOutputIPC(
     78     int render_view_id, int render_frame_id) {
     79   DCHECK_GT(render_view_id, 0);
     80   return scoped_ptr<media::AudioOutputIPC>(
     81       new AudioOutputIPCImpl(this, render_view_id, render_frame_id));
     82 }
     83 
     84 void AudioMessageFilter::AudioOutputIPCImpl::CreateStream(
     85     media::AudioOutputIPCDelegate* delegate,
     86     const media::AudioParameters& params,
     87     int session_id) {
     88   DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
     89   DCHECK(delegate);
     90   DCHECK_EQ(stream_id_, kStreamIDNotSet);
     91   stream_id_ = filter_->delegates_.Add(delegate);
     92   filter_->Send(new AudioHostMsg_CreateStream(
     93       stream_id_, render_view_id_, render_frame_id_, session_id, params));
     94 }
     95 
     96 void AudioMessageFilter::AudioOutputIPCImpl::PlayStream() {
     97   DCHECK_NE(stream_id_, kStreamIDNotSet);
     98   filter_->Send(new AudioHostMsg_PlayStream(stream_id_));
     99 }
    100 
    101 void AudioMessageFilter::AudioOutputIPCImpl::PauseStream() {
    102   DCHECK_NE(stream_id_, kStreamIDNotSet);
    103   filter_->Send(new AudioHostMsg_PauseStream(stream_id_));
    104 }
    105 
    106 void AudioMessageFilter::AudioOutputIPCImpl::CloseStream() {
    107   DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
    108   DCHECK_NE(stream_id_, kStreamIDNotSet);
    109   filter_->Send(new AudioHostMsg_CloseStream(stream_id_));
    110   filter_->delegates_.Remove(stream_id_);
    111   stream_id_ = kStreamIDNotSet;
    112 }
    113 
    114 void AudioMessageFilter::AudioOutputIPCImpl::SetVolume(double volume) {
    115   DCHECK_NE(stream_id_, kStreamIDNotSet);
    116   filter_->Send(new AudioHostMsg_SetVolume(stream_id_, volume));
    117 }
    118 
    119 void AudioMessageFilter::Send(IPC::Message* message) {
    120   DCHECK(io_message_loop_->BelongsToCurrentThread());
    121   if (!sender_) {
    122     delete message;
    123   } else {
    124     sender_->Send(message);
    125   }
    126 }
    127 
    128 bool AudioMessageFilter::OnMessageReceived(const IPC::Message& message) {
    129   DCHECK(io_message_loop_->BelongsToCurrentThread());
    130   bool handled = true;
    131   IPC_BEGIN_MESSAGE_MAP(AudioMessageFilter, message)
    132     IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamCreated, OnStreamCreated)
    133     IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamStateChanged, OnStreamStateChanged)
    134     IPC_MESSAGE_HANDLER(AudioMsg_NotifyDeviceChanged, OnOutputDeviceChanged)
    135     IPC_MESSAGE_UNHANDLED(handled = false)
    136   IPC_END_MESSAGE_MAP()
    137   return handled;
    138 }
    139 
    140 void AudioMessageFilter::OnFilterAdded(IPC::Sender* sender) {
    141   DCHECK(io_message_loop_->BelongsToCurrentThread());
    142   sender_ = sender;
    143 }
    144 
    145 void AudioMessageFilter::OnFilterRemoved() {
    146   DCHECK(io_message_loop_->BelongsToCurrentThread());
    147 
    148   // Once removed, a filter will not be used again.  At this time all
    149   // delegates must be notified so they release their reference.
    150   OnChannelClosing();
    151 }
    152 
    153 void AudioMessageFilter::OnChannelClosing() {
    154   DCHECK(io_message_loop_->BelongsToCurrentThread());
    155   sender_ = NULL;
    156 
    157   DLOG_IF(WARNING, !delegates_.IsEmpty())
    158       << "Not all audio devices have been closed.";
    159 
    160   IDMap<media::AudioOutputIPCDelegate>::iterator it(&delegates_);
    161   while (!it.IsAtEnd()) {
    162     it.GetCurrentValue()->OnIPCClosed();
    163     delegates_.Remove(it.GetCurrentKey());
    164     it.Advance();
    165   }
    166 }
    167 
    168 void AudioMessageFilter::OnStreamCreated(
    169     int stream_id,
    170     base::SharedMemoryHandle handle,
    171     base::SyncSocket::TransitDescriptor socket_descriptor,
    172     uint32 length) {
    173   DCHECK(io_message_loop_->BelongsToCurrentThread());
    174 
    175   WebRtcLogMessage(base::StringPrintf(
    176       "AMF::OnStreamCreated. stream_id=%d",
    177       stream_id));
    178 
    179   base::SyncSocket::Handle socket_handle =
    180       base::SyncSocket::UnwrapHandle(socket_descriptor);
    181 
    182   media::AudioOutputIPCDelegate* delegate = delegates_.Lookup(stream_id);
    183   if (!delegate) {
    184     DLOG(WARNING) << "Got OnStreamCreated() event for a non-existent or removed"
    185                   << " audio renderer. (stream_id=" << stream_id << ").";
    186     base::SharedMemory::CloseHandle(handle);
    187     base::SyncSocket socket(socket_handle);
    188     return;
    189   }
    190   delegate->OnStreamCreated(handle, socket_handle, length);
    191 }
    192 
    193 void AudioMessageFilter::OnStreamStateChanged(
    194     int stream_id, media::AudioOutputIPCDelegate::State state) {
    195   DCHECK(io_message_loop_->BelongsToCurrentThread());
    196   media::AudioOutputIPCDelegate* delegate = delegates_.Lookup(stream_id);
    197   if (!delegate) {
    198     DLOG(WARNING) << "Got OnStreamStateChanged() event for a non-existent or"
    199                   << " removed audio renderer.  State: " << state;
    200     return;
    201   }
    202   delegate->OnStateChanged(state);
    203 }
    204 
    205 void AudioMessageFilter::OnOutputDeviceChanged(int stream_id,
    206                                                int new_buffer_size,
    207                                                int new_sample_rate) {
    208   DCHECK(io_message_loop_->BelongsToCurrentThread());
    209   base::AutoLock auto_lock(lock_);
    210 
    211   WebRtcLogMessage(base::StringPrintf(
    212       "AMF::OnOutputDeviceChanged. stream_id=%d"
    213       ", new_buffer_size=%d, new_sample_rate=%d",
    214       stream_id,
    215       new_buffer_size,
    216       new_sample_rate));
    217 
    218   // Ignore the message if an audio hardware config hasn't been created; this
    219   // can occur if the renderer is using the high latency audio path.
    220   CHECK(audio_hardware_config_);
    221 
    222   // TODO(crogers): fix OnOutputDeviceChanged() to pass AudioParameters.
    223   media::ChannelLayout channel_layout =
    224       audio_hardware_config_->GetOutputChannelLayout();
    225   int channels = audio_hardware_config_->GetOutputChannels();
    226 
    227   media::AudioParameters output_params;
    228   output_params.Reset(
    229       media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
    230       channel_layout,
    231       channels,
    232       new_sample_rate,
    233       16,
    234       new_buffer_size);
    235 
    236   audio_hardware_config_->UpdateOutputConfig(output_params);
    237 }
    238 
    239 void AudioMessageFilter::SetAudioHardwareConfig(
    240     media::AudioHardwareConfig* config) {
    241   base::AutoLock auto_lock(lock_);
    242   audio_hardware_config_ = config;
    243 }
    244 
    245 }  // namespace content
    246