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