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