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 #if defined(OS_WIN)
    172     base::SyncSocket::Handle socket_handle,
    173 #else
    174     base::FileDescriptor socket_descriptor,
    175 #endif
    176     uint32 length) {
    177   DCHECK(io_message_loop_->BelongsToCurrentThread());
    178 
    179   WebRtcLogMessage(base::StringPrintf(
    180       "AMF::OnStreamCreated. stream_id=%d",
    181       stream_id));
    182 
    183 #if !defined(OS_WIN)
    184   base::SyncSocket::Handle socket_handle = socket_descriptor.fd;
    185 #endif
    186 
    187   media::AudioOutputIPCDelegate* delegate = delegates_.Lookup(stream_id);
    188   if (!delegate) {
    189     DLOG(WARNING) << "Got OnStreamCreated() event for a non-existent or removed"
    190                   << " audio renderer. (stream_id=" << stream_id << ").";
    191     base::SharedMemory::CloseHandle(handle);
    192     base::SyncSocket socket(socket_handle);
    193     return;
    194   }
    195   delegate->OnStreamCreated(handle, socket_handle, length);
    196 }
    197 
    198 void AudioMessageFilter::OnStreamStateChanged(
    199     int stream_id, media::AudioOutputIPCDelegate::State state) {
    200   DCHECK(io_message_loop_->BelongsToCurrentThread());
    201   media::AudioOutputIPCDelegate* delegate = delegates_.Lookup(stream_id);
    202   if (!delegate) {
    203     DLOG(WARNING) << "Got OnStreamStateChanged() event for a non-existent or"
    204                   << " removed audio renderer.  State: " << state;
    205     return;
    206   }
    207   delegate->OnStateChanged(state);
    208 }
    209 
    210 void AudioMessageFilter::OnOutputDeviceChanged(int stream_id,
    211                                                int new_buffer_size,
    212                                                int new_sample_rate) {
    213   DCHECK(io_message_loop_->BelongsToCurrentThread());
    214   base::AutoLock auto_lock(lock_);
    215 
    216   WebRtcLogMessage(base::StringPrintf(
    217       "AMF::OnOutputDeviceChanged. stream_id=%d"
    218       ", new_buffer_size=%d, new_sample_rate=%d",
    219       stream_id,
    220       new_buffer_size,
    221       new_sample_rate));
    222 
    223   // Ignore the message if an audio hardware config hasn't been created; this
    224   // can occur if the renderer is using the high latency audio path.
    225   CHECK(audio_hardware_config_);
    226 
    227   // TODO(crogers): fix OnOutputDeviceChanged() to pass AudioParameters.
    228   media::ChannelLayout channel_layout =
    229       audio_hardware_config_->GetOutputChannelLayout();
    230   int channels = audio_hardware_config_->GetOutputChannels();
    231 
    232   media::AudioParameters output_params;
    233   output_params.Reset(
    234       media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
    235       channel_layout,
    236       channels,
    237       0,
    238       new_sample_rate,
    239       16,
    240       new_buffer_size);
    241 
    242   audio_hardware_config_->UpdateOutputConfig(output_params);
    243 }
    244 
    245 void AudioMessageFilter::SetAudioHardwareConfig(
    246     media::AudioHardwareConfig* config) {
    247   base::AutoLock auto_lock(lock_);
    248   audio_hardware_config_ = config;
    249 }
    250 
    251 }  // namespace content
    252