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_input_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 "ipc/ipc_logging.h"
     13 #include "ipc/ipc_sender.h"
     14 
     15 namespace content {
     16 
     17 namespace {
     18 const int kStreamIDNotSet = -1;
     19 }
     20 
     21 class AudioInputMessageFilter::AudioInputIPCImpl
     22     : public NON_EXPORTED_BASE(media::AudioInputIPC) {
     23  public:
     24   AudioInputIPCImpl(const scoped_refptr<AudioInputMessageFilter>& filter,
     25                     int render_view_id);
     26   virtual ~AudioInputIPCImpl();
     27 
     28   // media::AudioInputIPC implementation.
     29   virtual void CreateStream(media::AudioInputIPCDelegate* delegate,
     30                             int session_id,
     31                             const media::AudioParameters& params,
     32                             bool automatic_gain_control,
     33                             uint32 total_segments) OVERRIDE;
     34   virtual void RecordStream() OVERRIDE;
     35   virtual void SetVolume(double volume) OVERRIDE;
     36   virtual void CloseStream() OVERRIDE;
     37 
     38  private:
     39   const scoped_refptr<AudioInputMessageFilter> filter_;
     40   const int render_view_id_;
     41   int stream_id_;
     42 };
     43 
     44 AudioInputMessageFilter* AudioInputMessageFilter::g_filter = NULL;
     45 
     46 AudioInputMessageFilter::AudioInputMessageFilter(
     47     const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
     48     : sender_(NULL),
     49       io_message_loop_(io_message_loop) {
     50   DCHECK(!g_filter);
     51   g_filter = this;
     52 }
     53 
     54 AudioInputMessageFilter::~AudioInputMessageFilter() {
     55   DCHECK_EQ(g_filter, this);
     56   g_filter = NULL;
     57 }
     58 
     59 // static
     60 AudioInputMessageFilter* AudioInputMessageFilter::Get() {
     61   return g_filter;
     62 }
     63 
     64 void AudioInputMessageFilter::Send(IPC::Message* message) {
     65   DCHECK(io_message_loop_->BelongsToCurrentThread());
     66   if (!sender_) {
     67     delete message;
     68   } else {
     69     sender_->Send(message);
     70   }
     71 }
     72 
     73 bool AudioInputMessageFilter::OnMessageReceived(const IPC::Message& message) {
     74   DCHECK(io_message_loop_->BelongsToCurrentThread());
     75   bool handled = true;
     76   IPC_BEGIN_MESSAGE_MAP(AudioInputMessageFilter, message)
     77     IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamCreated,
     78                         OnStreamCreated)
     79     IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamVolume, OnStreamVolume)
     80     IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamStateChanged,
     81                         OnStreamStateChanged)
     82     IPC_MESSAGE_UNHANDLED(handled = false)
     83   IPC_END_MESSAGE_MAP()
     84   return handled;
     85 }
     86 
     87 void AudioInputMessageFilter::OnFilterAdded(IPC::Sender* sender) {
     88   DCHECK(io_message_loop_->BelongsToCurrentThread());
     89 
     90   // Captures the sender for IPC.
     91   sender_ = sender;
     92 }
     93 
     94 void AudioInputMessageFilter::OnFilterRemoved() {
     95   DCHECK(io_message_loop_->BelongsToCurrentThread());
     96 
     97   // Once removed, a filter will not be used again.  At this time all
     98   // delegates must be notified so they release their reference.
     99   OnChannelClosing();
    100 }
    101 
    102 void AudioInputMessageFilter::OnChannelClosing() {
    103   DCHECK(io_message_loop_->BelongsToCurrentThread());
    104   sender_ = NULL;
    105 
    106   DLOG_IF(WARNING, !delegates_.IsEmpty())
    107       << "Not all audio devices have been closed.";
    108 
    109   IDMap<media::AudioInputIPCDelegate>::iterator it(&delegates_);
    110   while (!it.IsAtEnd()) {
    111     it.GetCurrentValue()->OnIPCClosed();
    112     delegates_.Remove(it.GetCurrentKey());
    113     it.Advance();
    114   }
    115 }
    116 
    117 void AudioInputMessageFilter::OnStreamCreated(
    118     int stream_id,
    119     base::SharedMemoryHandle handle,
    120 #if defined(OS_WIN)
    121     base::SyncSocket::Handle socket_handle,
    122 #else
    123     base::FileDescriptor socket_descriptor,
    124 #endif
    125     uint32 length,
    126     uint32 total_segments) {
    127   DCHECK(io_message_loop_->BelongsToCurrentThread());
    128 
    129   WebRtcLogMessage(base::StringPrintf(
    130       "AIMF::OnStreamCreated. stream_id=%d",
    131       stream_id));
    132 
    133 #if !defined(OS_WIN)
    134   base::SyncSocket::Handle socket_handle = socket_descriptor.fd;
    135 #endif
    136   media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id);
    137   if (!delegate) {
    138     DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
    139                   << " audio capturer (stream_id=" << stream_id << ").";
    140     base::SharedMemory::CloseHandle(handle);
    141     base::SyncSocket socket(socket_handle);
    142     return;
    143   }
    144   // Forward message to the stream delegate.
    145   delegate->OnStreamCreated(handle, socket_handle, length, total_segments);
    146 }
    147 
    148 void AudioInputMessageFilter::OnStreamVolume(int stream_id, double volume) {
    149   DCHECK(io_message_loop_->BelongsToCurrentThread());
    150   media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id);
    151   if (!delegate) {
    152     DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
    153                   << " audio capturer.";
    154     return;
    155   }
    156   delegate->OnVolume(volume);
    157 }
    158 
    159 void AudioInputMessageFilter::OnStreamStateChanged(
    160     int stream_id, media::AudioInputIPCDelegate::State state) {
    161   DCHECK(io_message_loop_->BelongsToCurrentThread());
    162   media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id);
    163   if (!delegate) {
    164     DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
    165                   << " audio renderer.";
    166     return;
    167   }
    168   delegate->OnStateChanged(state);
    169 }
    170 
    171 AudioInputMessageFilter::AudioInputIPCImpl::AudioInputIPCImpl(
    172     const scoped_refptr<AudioInputMessageFilter>& filter, int render_view_id)
    173     : filter_(filter),
    174       render_view_id_(render_view_id),
    175       stream_id_(kStreamIDNotSet) {}
    176 
    177 AudioInputMessageFilter::AudioInputIPCImpl::~AudioInputIPCImpl() {}
    178 
    179 scoped_ptr<media::AudioInputIPC> AudioInputMessageFilter::CreateAudioInputIPC(
    180     int render_view_id) {
    181   DCHECK_GT(render_view_id, 0);
    182   return scoped_ptr<media::AudioInputIPC>(
    183       new AudioInputIPCImpl(this, render_view_id));
    184 }
    185 
    186 void AudioInputMessageFilter::AudioInputIPCImpl::CreateStream(
    187     media::AudioInputIPCDelegate* delegate,
    188     int session_id,
    189     const media::AudioParameters& params,
    190     bool automatic_gain_control,
    191     uint32 total_segments) {
    192   DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
    193   DCHECK(delegate);
    194 
    195   stream_id_ = filter_->delegates_.Add(delegate);
    196 
    197   AudioInputHostMsg_CreateStream_Config config;
    198   config.params = params;
    199   config.automatic_gain_control = automatic_gain_control;
    200   config.shared_memory_count = total_segments;
    201   filter_->Send(new AudioInputHostMsg_CreateStream(
    202       stream_id_, render_view_id_, session_id, config));
    203 }
    204 
    205 void AudioInputMessageFilter::AudioInputIPCImpl::RecordStream() {
    206   DCHECK_NE(stream_id_, kStreamIDNotSet);
    207   filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_));
    208 }
    209 
    210 void AudioInputMessageFilter::AudioInputIPCImpl::SetVolume(double volume) {
    211   DCHECK_NE(stream_id_, kStreamIDNotSet);
    212   filter_->Send(new AudioInputHostMsg_SetVolume(stream_id_, volume));
    213 }
    214 
    215 void AudioInputMessageFilter::AudioInputIPCImpl::CloseStream() {
    216   DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
    217   DCHECK_NE(stream_id_, kStreamIDNotSet);
    218   filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
    219   filter_->delegates_.Remove(stream_id_);
    220   stream_id_ = kStreamIDNotSet;
    221 }
    222 
    223 }  // namespace content
    224