audio_input_device.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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 "media/audio/audio_input_device.h" 6 7#include "base/bind.h" 8#include "base/message_loop.h" 9#include "base/threading/thread_restrictions.h" 10#include "base/time.h" 11#include "media/audio/audio_manager_base.h" 12#include "media/base/audio_bus.h" 13 14namespace media { 15 16AudioInputDevice::CaptureCallback::~CaptureCallback() {} 17AudioInputDevice::CaptureEventHandler::~CaptureEventHandler() {} 18 19// Takes care of invoking the capture callback on the audio thread. 20// An instance of this class is created for each capture stream in 21// OnLowLatencyCreated(). 22class AudioInputDevice::AudioThreadCallback 23 : public AudioDeviceThread::Callback { 24 public: 25 AudioThreadCallback(const AudioParameters& audio_parameters, 26 base::SharedMemoryHandle memory, 27 int memory_length, 28 CaptureCallback* capture_callback); 29 virtual ~AudioThreadCallback(); 30 31 virtual void MapSharedMemory() OVERRIDE; 32 33 // Called whenever we receive notifications about pending data. 34 virtual void Process(int pending_data) OVERRIDE; 35 36 private: 37 CaptureCallback* capture_callback_; 38 scoped_ptr<AudioBus> audio_bus_; 39 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); 40}; 41 42AudioInputDevice::AudioInputDevice( 43 AudioInputIPC* ipc, 44 const scoped_refptr<base::MessageLoopProxy>& io_loop) 45 : ScopedLoopObserver(io_loop), 46 callback_(NULL), 47 event_handler_(NULL), 48 ipc_(ipc), 49 stream_id_(0), 50 session_id_(0), 51 pending_device_ready_(false), 52 agc_is_enabled_(false) { 53 CHECK(ipc_); 54} 55 56void AudioInputDevice::Initialize(const AudioParameters& params, 57 CaptureCallback* callback, 58 CaptureEventHandler* event_handler) { 59 DCHECK(!callback_); 60 DCHECK(!event_handler_); 61 audio_parameters_ = params; 62 callback_ = callback; 63 event_handler_ = event_handler; 64} 65 66void AudioInputDevice::SetDevice(int session_id) { 67 DVLOG(1) << "SetDevice (session_id=" << session_id << ")"; 68 message_loop()->PostTask(FROM_HERE, 69 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this, session_id)); 70} 71 72void AudioInputDevice::Start() { 73 DVLOG(1) << "Start()"; 74 message_loop()->PostTask(FROM_HERE, 75 base::Bind(&AudioInputDevice::InitializeOnIOThread, this)); 76} 77 78void AudioInputDevice::Stop() { 79 DVLOG(1) << "Stop()"; 80 81 { 82 base::AutoLock auto_lock(audio_thread_lock_); 83 audio_thread_.Stop(MessageLoop::current()); 84 } 85 86 message_loop()->PostTask(FROM_HERE, 87 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this)); 88} 89 90void AudioInputDevice::SetVolume(double volume) { 91 if (volume < 0 || volume > 1.0) { 92 DLOG(ERROR) << "Invalid volume value specified"; 93 return; 94 } 95 96 message_loop()->PostTask(FROM_HERE, 97 base::Bind(&AudioInputDevice::SetVolumeOnIOThread, this, volume)); 98} 99 100void AudioInputDevice::SetAutomaticGainControl(bool enabled) { 101 DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")"; 102 message_loop()->PostTask(FROM_HERE, 103 base::Bind(&AudioInputDevice::SetAutomaticGainControlOnIOThread, 104 this, enabled)); 105} 106 107void AudioInputDevice::OnStreamCreated( 108 base::SharedMemoryHandle handle, 109 base::SyncSocket::Handle socket_handle, 110 int length) { 111 DCHECK(message_loop()->BelongsToCurrentThread()); 112#if defined(OS_WIN) 113 DCHECK(handle); 114 DCHECK(socket_handle); 115#else 116 DCHECK_GE(handle.fd, 0); 117 DCHECK_GE(socket_handle, 0); 118#endif 119 DCHECK(length); 120 DVLOG(1) << "OnStreamCreated (stream_id=" << stream_id_ << ")"; 121 122 // We should only get this callback if stream_id_ is valid. If it is not, 123 // the IPC layer should have closed the shared memory and socket handles 124 // for us and not invoked the callback. The basic assertion is that when 125 // stream_id_ is 0 the AudioInputDevice instance is not registered as a 126 // delegate and hence it should not receive callbacks. 127 DCHECK(stream_id_); 128 129 base::AutoLock auto_lock(audio_thread_lock_); 130 131 DCHECK(audio_thread_.IsStopped()); 132 audio_callback_.reset( 133 new AudioInputDevice::AudioThreadCallback(audio_parameters_, handle, 134 length, callback_)); 135 audio_thread_.Start(audio_callback_.get(), socket_handle, "AudioInputDevice"); 136 137 MessageLoop::current()->PostTask(FROM_HERE, 138 base::Bind(&AudioInputDevice::StartOnIOThread, this)); 139} 140 141void AudioInputDevice::OnVolume(double volume) { 142 NOTIMPLEMENTED(); 143} 144 145void AudioInputDevice::OnStateChanged( 146 AudioInputIPCDelegate::State state) { 147 DCHECK(message_loop()->BelongsToCurrentThread()); 148 149 // Do nothing if the stream has been closed. 150 if (!stream_id_) 151 return; 152 153 switch (state) { 154 case AudioInputIPCDelegate::kStopped: 155 // TODO(xians): Should we just call ShutDownOnIOThread here instead? 156 ipc_->RemoveDelegate(stream_id_); 157 158 audio_thread_.Stop(MessageLoop::current()); 159 audio_callback_.reset(); 160 161 if (event_handler_) 162 event_handler_->OnDeviceStopped(); 163 164 stream_id_ = 0; 165 pending_device_ready_ = false; 166 break; 167 case AudioInputIPCDelegate::kRecording: 168 NOTIMPLEMENTED(); 169 break; 170 case AudioInputIPCDelegate::kError: 171 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)"; 172 // Don't dereference the callback object if the audio thread 173 // is stopped or stopping. That could mean that the callback 174 // object has been deleted. 175 // TODO(tommi): Add an explicit contract for clearing the callback 176 // object. Possibly require calling Initialize again or provide 177 // a callback object via Start() and clear it in Stop(). 178 if (!audio_thread_.IsStopped()) 179 callback_->OnCaptureError(); 180 break; 181 default: 182 NOTREACHED(); 183 break; 184 } 185} 186 187void AudioInputDevice::OnDeviceReady(const std::string& device_id) { 188 DCHECK(message_loop()->BelongsToCurrentThread()); 189 DVLOG(1) << "OnDeviceReady (device_id=" << device_id << ")"; 190 191 // Takes care of the case when Stop() is called before OnDeviceReady(). 192 if (!pending_device_ready_) 193 return; 194 195 // If AudioInputDeviceManager returns an empty string, it means no device 196 // is ready for start. 197 if (device_id.empty()) { 198 ipc_->RemoveDelegate(stream_id_); 199 stream_id_ = 0; 200 } else { 201 ipc_->CreateStream(stream_id_, audio_parameters_, device_id, 202 agc_is_enabled_); 203 } 204 205 pending_device_ready_ = false; 206 // Notify the client that the device has been started. 207 if (event_handler_) 208 event_handler_->OnDeviceStarted(device_id); 209} 210 211void AudioInputDevice::OnIPCClosed() { 212 ipc_ = NULL; 213} 214 215AudioInputDevice::~AudioInputDevice() { 216 // TODO(henrika): The current design requires that the user calls 217 // Stop before deleting this class. 218 CHECK_EQ(0, stream_id_); 219} 220 221void AudioInputDevice::InitializeOnIOThread() { 222 DCHECK(message_loop()->BelongsToCurrentThread()); 223 // Make sure we don't call Start() more than once. 224 DCHECK_EQ(0, stream_id_); 225 if (stream_id_) 226 return; 227 228 stream_id_ = ipc_->AddDelegate(this); 229 // If |session_id_| is not specified, it will directly create the stream; 230 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser 231 // and create the stream when getting a OnDeviceReady() callback. 232 if (!session_id_) { 233 ipc_->CreateStream(stream_id_, audio_parameters_, 234 AudioManagerBase::kDefaultDeviceId, agc_is_enabled_); 235 } else { 236 ipc_->StartDevice(stream_id_, session_id_); 237 pending_device_ready_ = true; 238 } 239} 240 241void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { 242 DCHECK(message_loop()->BelongsToCurrentThread()); 243 session_id_ = session_id; 244} 245 246void AudioInputDevice::StartOnIOThread() { 247 DCHECK(message_loop()->BelongsToCurrentThread()); 248 if (stream_id_) 249 ipc_->RecordStream(stream_id_); 250} 251 252void AudioInputDevice::ShutDownOnIOThread() { 253 DCHECK(message_loop()->BelongsToCurrentThread()); 254 // NOTE: |completion| may be NULL. 255 // Make sure we don't call shutdown more than once. 256 if (stream_id_) { 257 if (ipc_) { 258 ipc_->CloseStream(stream_id_); 259 ipc_->RemoveDelegate(stream_id_); 260 } 261 262 stream_id_ = 0; 263 session_id_ = 0; 264 pending_device_ready_ = false; 265 agc_is_enabled_ = false; 266 } 267 268 // We can run into an issue where ShutDownOnIOThread is called right after 269 // OnStreamCreated is called in cases where Start/Stop are called before we 270 // get the OnStreamCreated callback. To handle that corner case, we call 271 // Stop(). In most cases, the thread will already be stopped. 272 // Another situation is when the IO thread goes away before Stop() is called 273 // in which case, we cannot use the message loop to close the thread handle 274 // and can't not rely on the main thread existing either. 275 base::ThreadRestrictions::ScopedAllowIO allow_io; 276 audio_thread_.Stop(NULL); 277 audio_callback_.reset(); 278} 279 280void AudioInputDevice::SetVolumeOnIOThread(double volume) { 281 DCHECK(message_loop()->BelongsToCurrentThread()); 282 if (stream_id_) 283 ipc_->SetVolume(stream_id_, volume); 284} 285 286void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) { 287 DCHECK(message_loop()->BelongsToCurrentThread()); 288 DCHECK_EQ(0, stream_id_) << 289 "The AGC state can not be modified while capturing is active."; 290 if (stream_id_) 291 return; 292 293 // We simply store the new AGC setting here. This value will be used when 294 // a new stream is initialized and by GetAutomaticGainControl(). 295 agc_is_enabled_ = enabled; 296} 297 298void AudioInputDevice::WillDestroyCurrentMessageLoop() { 299 LOG(ERROR) << "IO loop going away before the input device has been stopped"; 300 ShutDownOnIOThread(); 301} 302 303// AudioInputDevice::AudioThreadCallback 304AudioInputDevice::AudioThreadCallback::AudioThreadCallback( 305 const AudioParameters& audio_parameters, 306 base::SharedMemoryHandle memory, 307 int memory_length, 308 CaptureCallback* capture_callback) 309 : AudioDeviceThread::Callback(audio_parameters, 0, memory, memory_length), 310 capture_callback_(capture_callback) { 311 audio_bus_ = AudioBus::Create(audio_parameters_); 312} 313 314AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { 315} 316 317void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { 318 shared_memory_.Map(memory_length_); 319} 320 321void AudioInputDevice::AudioThreadCallback::Process(int pending_data) { 322 // The shared memory represents parameters, size of the data buffer and the 323 // actual data buffer containing audio data. Map the memory into this 324 // structure and parse out parameters and the data area. 325 AudioInputBuffer* buffer = 326 reinterpret_cast<AudioInputBuffer*>(shared_memory_.memory()); 327 DCHECK_EQ(buffer->params.size, 328 memory_length_ - sizeof(AudioInputBufferParameters)); 329 double volume = buffer->params.volume; 330 331 int audio_delay_milliseconds = pending_data / bytes_per_ms_; 332 int16* memory = reinterpret_cast<int16*>(&buffer->audio[0]); 333 const int bytes_per_sample = sizeof(memory[0]); 334 335 // Deinterleave each channel and convert to 32-bit floating-point 336 // with nominal range -1.0 -> +1.0. 337 audio_bus_->FromInterleaved(memory, audio_bus_->frames(), bytes_per_sample); 338 339 // Deliver captured data to the client in floating point format 340 // and update the audio-delay measurement. 341 capture_callback_->Capture(audio_bus_.get(), 342 audio_delay_milliseconds, volume); 343} 344 345} // namespace media 346