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_controller.h" 6 7 #include "base/bind.h" 8 #include "base/threading/thread_restrictions.h" 9 #include "media/base/limits.h" 10 #include "media/base/scoped_histogram_timer.h" 11 12 namespace { 13 const int kMaxInputChannels = 2; 14 15 // TODO(henrika): remove usage of timers and add support for proper 16 // notification of when the input device is removed. This was originally added 17 // to resolve http://crbug.com/79936 for Windows platforms. This then caused 18 // breakage (very hard to repro bugs!) on other platforms: See 19 // http://crbug.com/226327 and http://crbug.com/230972. 20 const int kTimerResetIntervalSeconds = 1; 21 #if defined(OS_IOS) 22 // The first callback on iOS is received after the current background 23 // audio has faded away. 24 const int kTimerInitialIntervalSeconds = 4; 25 #else 26 // We have received reports that the timer can be too trigger happy on some 27 // Mac devices and the initial timer interval has therefore been increased 28 // from 1 second to 5 seconds. 29 const int kTimerInitialIntervalSeconds = 5; 30 #endif // defined(OS_IOS) 31 } 32 33 namespace media { 34 35 // static 36 AudioInputController::Factory* AudioInputController::factory_ = NULL; 37 38 AudioInputController::AudioInputController(EventHandler* handler, 39 SyncWriter* sync_writer) 40 : creator_loop_(base::MessageLoopProxy::current()), 41 handler_(handler), 42 stream_(NULL), 43 data_is_active_(false), 44 state_(kEmpty), 45 sync_writer_(sync_writer), 46 max_volume_(0.0) { 47 DCHECK(creator_loop_.get()); 48 } 49 50 AudioInputController::~AudioInputController() { 51 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_); 52 } 53 54 // static 55 scoped_refptr<AudioInputController> AudioInputController::Create( 56 AudioManager* audio_manager, 57 EventHandler* event_handler, 58 const AudioParameters& params, 59 const std::string& device_id) { 60 DCHECK(audio_manager); 61 62 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) 63 return NULL; 64 65 if (factory_) 66 return factory_->Create(audio_manager, event_handler, params); 67 68 scoped_refptr<AudioInputController> controller(new AudioInputController( 69 event_handler, NULL)); 70 71 controller->message_loop_ = audio_manager->GetMessageLoop(); 72 73 // Create and open a new audio input stream from the existing 74 // audio-device thread. 75 if (!controller->message_loop_->PostTask(FROM_HERE, 76 base::Bind(&AudioInputController::DoCreate, controller, 77 base::Unretained(audio_manager), params, device_id))) { 78 controller = NULL; 79 } 80 81 return controller; 82 } 83 84 // static 85 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( 86 AudioManager* audio_manager, 87 EventHandler* event_handler, 88 const AudioParameters& params, 89 const std::string& device_id, 90 SyncWriter* sync_writer) { 91 DCHECK(audio_manager); 92 DCHECK(sync_writer); 93 94 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) 95 return NULL; 96 97 // Create the AudioInputController object and ensure that it runs on 98 // the audio-manager thread. 99 scoped_refptr<AudioInputController> controller(new AudioInputController( 100 event_handler, sync_writer)); 101 controller->message_loop_ = audio_manager->GetMessageLoop(); 102 103 // Create and open a new audio input stream from the existing 104 // audio-device thread. Use the provided audio-input device. 105 if (!controller->message_loop_->PostTask(FROM_HERE, 106 base::Bind(&AudioInputController::DoCreate, controller, 107 base::Unretained(audio_manager), params, device_id))) { 108 controller = NULL; 109 } 110 111 return controller; 112 } 113 114 // static 115 scoped_refptr<AudioInputController> AudioInputController::CreateForStream( 116 const scoped_refptr<base::MessageLoopProxy>& message_loop, 117 EventHandler* event_handler, 118 AudioInputStream* stream, 119 SyncWriter* sync_writer) { 120 DCHECK(sync_writer); 121 DCHECK(stream); 122 123 // Create the AudioInputController object and ensure that it runs on 124 // the audio-manager thread. 125 scoped_refptr<AudioInputController> controller(new AudioInputController( 126 event_handler, sync_writer)); 127 controller->message_loop_ = message_loop; 128 129 // TODO(miu): See TODO at top of file. Until that's resolved, we need to 130 // disable the error auto-detection here (since the audio mirroring 131 // implementation will reliably report error and close events). Note, of 132 // course, that we're assuming CreateForStream() has been called for the audio 133 // mirroring use case only. 134 if (!controller->message_loop_->PostTask( 135 FROM_HERE, 136 base::Bind(&AudioInputController::DoCreateForStream, controller, 137 stream, false))) { 138 controller = NULL; 139 } 140 141 return controller; 142 } 143 144 void AudioInputController::Record() { 145 message_loop_->PostTask(FROM_HERE, base::Bind( 146 &AudioInputController::DoRecord, this)); 147 } 148 149 void AudioInputController::Close(const base::Closure& closed_task) { 150 DCHECK(!closed_task.is_null()); 151 DCHECK(creator_loop_->BelongsToCurrentThread()); 152 153 message_loop_->PostTaskAndReply( 154 FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task); 155 } 156 157 void AudioInputController::SetVolume(double volume) { 158 message_loop_->PostTask(FROM_HERE, base::Bind( 159 &AudioInputController::DoSetVolume, this, volume)); 160 } 161 162 void AudioInputController::SetAutomaticGainControl(bool enabled) { 163 message_loop_->PostTask(FROM_HERE, base::Bind( 164 &AudioInputController::DoSetAutomaticGainControl, this, enabled)); 165 } 166 167 void AudioInputController::DoCreate(AudioManager* audio_manager, 168 const AudioParameters& params, 169 const std::string& device_id) { 170 DCHECK(message_loop_->BelongsToCurrentThread()); 171 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime"); 172 // TODO(miu): See TODO at top of file. Until that's resolved, assume all 173 // platform audio input requires the |no_data_timer_| be used to auto-detect 174 // errors. In reality, probably only Windows and IOS need to be treated as 175 // unreliable here. 176 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id), 177 true); 178 } 179 180 void AudioInputController::DoCreateForStream( 181 AudioInputStream* stream_to_control, bool enable_nodata_timer) { 182 DCHECK(message_loop_->BelongsToCurrentThread()); 183 184 DCHECK(!stream_); 185 stream_ = stream_to_control; 186 187 if (!stream_) { 188 handler_->OnError(this); 189 return; 190 } 191 192 if (stream_ && !stream_->Open()) { 193 stream_->Close(); 194 stream_ = NULL; 195 handler_->OnError(this); 196 return; 197 } 198 199 DCHECK(!no_data_timer_.get()); 200 if (enable_nodata_timer) { 201 // Create the data timer which will call DoCheckForNoData(). The timer 202 // is started in DoRecord() and restarted in each DoCheckForNoData() 203 // callback. 204 no_data_timer_.reset(new base::Timer( 205 FROM_HERE, base::TimeDelta::FromSeconds(kTimerInitialIntervalSeconds), 206 base::Bind(&AudioInputController::DoCheckForNoData, 207 base::Unretained(this)), false)); 208 } else { 209 DVLOG(1) << "Disabled: timer check for no data."; 210 } 211 212 state_ = kCreated; 213 handler_->OnCreated(this); 214 } 215 216 void AudioInputController::DoRecord() { 217 DCHECK(message_loop_->BelongsToCurrentThread()); 218 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime"); 219 220 if (state_ != kCreated) 221 return; 222 223 { 224 base::AutoLock auto_lock(lock_); 225 state_ = kRecording; 226 } 227 228 if (no_data_timer_) { 229 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed, 230 // a callback to DoCheckForNoData() is made. 231 no_data_timer_->Reset(); 232 } 233 234 stream_->Start(this); 235 handler_->OnRecording(this); 236 } 237 238 void AudioInputController::DoClose() { 239 DCHECK(message_loop_->BelongsToCurrentThread()); 240 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); 241 242 // Delete the timer on the same thread that created it. 243 no_data_timer_.reset(); 244 245 if (state_ != kClosed) { 246 DoStopCloseAndClearStream(NULL); 247 SetDataIsActive(false); 248 249 if (LowLatencyMode()) { 250 sync_writer_->Close(); 251 } 252 253 state_ = kClosed; 254 } 255 } 256 257 void AudioInputController::DoReportError() { 258 DCHECK(message_loop_->BelongsToCurrentThread()); 259 handler_->OnError(this); 260 } 261 262 void AudioInputController::DoSetVolume(double volume) { 263 DCHECK(message_loop_->BelongsToCurrentThread()); 264 DCHECK_GE(volume, 0); 265 DCHECK_LE(volume, 1.0); 266 267 if (state_ != kCreated && state_ != kRecording) 268 return; 269 270 // Only ask for the maximum volume at first call and use cached value 271 // for remaining function calls. 272 if (!max_volume_) { 273 max_volume_ = stream_->GetMaxVolume(); 274 } 275 276 if (max_volume_ == 0.0) { 277 DLOG(WARNING) << "Failed to access input volume control"; 278 return; 279 } 280 281 // Set the stream volume and scale to a range matched to the platform. 282 stream_->SetVolume(max_volume_ * volume); 283 } 284 285 void AudioInputController::DoSetAutomaticGainControl(bool enabled) { 286 DCHECK(message_loop_->BelongsToCurrentThread()); 287 DCHECK_NE(state_, kRecording); 288 289 // Ensure that the AGC state only can be modified before streaming starts. 290 if (state_ != kCreated || state_ == kRecording) 291 return; 292 293 stream_->SetAutomaticGainControl(enabled); 294 } 295 296 void AudioInputController::DoCheckForNoData() { 297 DCHECK(message_loop_->BelongsToCurrentThread()); 298 299 if (!GetDataIsActive()) { 300 // The data-is-active marker will be false only if it has been more than 301 // one second since a data packet was recorded. This can happen if a 302 // capture device has been removed or disabled. 303 handler_->OnError(this); 304 return; 305 } 306 307 // Mark data as non-active. The flag will be re-enabled in OnData() each 308 // time a data packet is received. Hence, under normal conditions, the 309 // flag will only be disabled during a very short period. 310 SetDataIsActive(false); 311 312 // Restart the timer to ensure that we check the flag again in 313 // |kTimerResetIntervalSeconds|. 314 no_data_timer_->Start( 315 FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds), 316 base::Bind(&AudioInputController::DoCheckForNoData, 317 base::Unretained(this))); 318 } 319 320 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data, 321 uint32 size, uint32 hardware_delay_bytes, 322 double volume) { 323 { 324 base::AutoLock auto_lock(lock_); 325 if (state_ != kRecording) 326 return; 327 } 328 329 // Mark data as active to ensure that the periodic calls to 330 // DoCheckForNoData() does not report an error to the event handler. 331 SetDataIsActive(true); 332 333 // Use SyncSocket if we are in a low-latency mode. 334 if (LowLatencyMode()) { 335 sync_writer_->Write(data, size, volume); 336 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); 337 return; 338 } 339 340 handler_->OnData(this, data, size); 341 } 342 343 void AudioInputController::OnClose(AudioInputStream* stream) { 344 DVLOG(1) << "AudioInputController::OnClose()"; 345 // TODO(satish): Sometimes the device driver closes the input stream without 346 // us asking for it (may be if the device was unplugged?). Check how to handle 347 // such cases here. 348 } 349 350 void AudioInputController::OnError(AudioInputStream* stream) { 351 // Handle error on the audio-manager thread. 352 message_loop_->PostTask(FROM_HERE, base::Bind( 353 &AudioInputController::DoReportError, this)); 354 } 355 356 void AudioInputController::DoStopCloseAndClearStream( 357 base::WaitableEvent *done) { 358 DCHECK(message_loop_->BelongsToCurrentThread()); 359 360 // Allow calling unconditionally and bail if we don't have a stream to close. 361 if (stream_ != NULL) { 362 stream_->Stop(); 363 stream_->Close(); 364 stream_ = NULL; 365 } 366 367 // Should be last in the method, do not touch "this" from here on. 368 if (done != NULL) 369 done->Signal(); 370 } 371 372 void AudioInputController::SetDataIsActive(bool enabled) { 373 base::subtle::Release_Store(&data_is_active_, enabled); 374 } 375 376 bool AudioInputController::GetDataIsActive() { 377 return (base::subtle::Acquire_Load(&data_is_active_) != false); 378 } 379 380 } // namespace media 381