| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/audio/audio_input_controller.h" | 5 #include "media/audio/audio_input_controller.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/threading/thread_restrictions.h" | 8 #include "base/threading/thread_restrictions.h" |
| 9 #include "media/base/limits.h" | 9 #include "media/base/limits.h" |
| 10 #include "media/base/scoped_histogram_timer.h" | 10 #include "media/base/scoped_histogram_timer.h" |
| 11 #include "media/base/user_input_monitor.h" |
| 11 | 12 |
| 12 namespace { | 13 namespace { |
| 13 const int kMaxInputChannels = 2; | 14 const int kMaxInputChannels = 2; |
| 14 | 15 |
| 15 // TODO(henrika): remove usage of timers and add support for proper | 16 // 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 // 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 // to resolve http://crbug.com/79936 for Windows platforms. This then caused |
| 18 // breakage (very hard to repro bugs!) on other platforms: See | 19 // breakage (very hard to repro bugs!) on other platforms: See |
| 19 // http://crbug.com/226327 and http://crbug.com/230972. | 20 // http://crbug.com/226327 and http://crbug.com/230972. |
| 20 const int kTimerResetIntervalSeconds = 1; | 21 const int kTimerResetIntervalSeconds = 1; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 39 SyncWriter* sync_writer, | 40 SyncWriter* sync_writer, |
| 40 UserInputMonitor* user_input_monitor) | 41 UserInputMonitor* user_input_monitor) |
| 41 : creator_loop_(base::MessageLoopProxy::current()), | 42 : creator_loop_(base::MessageLoopProxy::current()), |
| 42 handler_(handler), | 43 handler_(handler), |
| 43 stream_(NULL), | 44 stream_(NULL), |
| 44 data_is_active_(false), | 45 data_is_active_(false), |
| 45 state_(kEmpty), | 46 state_(kEmpty), |
| 46 sync_writer_(sync_writer), | 47 sync_writer_(sync_writer), |
| 47 max_volume_(0.0), | 48 max_volume_(0.0), |
| 48 user_input_monitor_(user_input_monitor), | 49 user_input_monitor_(user_input_monitor), |
| 49 key_pressed_(false) { | 50 prev_key_down_count_(0) { |
| 50 DCHECK(creator_loop_.get()); | 51 DCHECK(creator_loop_.get()); |
| 51 } | 52 } |
| 52 | 53 |
| 53 AudioInputController::~AudioInputController() { | 54 AudioInputController::~AudioInputController() { |
| 54 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_); | 55 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_); |
| 55 } | 56 } |
| 56 | 57 |
| 57 // static | 58 // static |
| 58 scoped_refptr<AudioInputController> AudioInputController::Create( | 59 scoped_refptr<AudioInputController> AudioInputController::Create( |
| 59 AudioManager* audio_manager, | 60 AudioManager* audio_manager, |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 no_data_timer_.reset(new base::Timer( | 212 no_data_timer_.reset(new base::Timer( |
| 212 FROM_HERE, base::TimeDelta::FromSeconds(kTimerInitialIntervalSeconds), | 213 FROM_HERE, base::TimeDelta::FromSeconds(kTimerInitialIntervalSeconds), |
| 213 base::Bind(&AudioInputController::DoCheckForNoData, | 214 base::Bind(&AudioInputController::DoCheckForNoData, |
| 214 base::Unretained(this)), false)); | 215 base::Unretained(this)), false)); |
| 215 } else { | 216 } else { |
| 216 DVLOG(1) << "Disabled: timer check for no data."; | 217 DVLOG(1) << "Disabled: timer check for no data."; |
| 217 } | 218 } |
| 218 | 219 |
| 219 state_ = kCreated; | 220 state_ = kCreated; |
| 220 handler_->OnCreated(this); | 221 handler_->OnCreated(this); |
| 222 |
| 223 if (user_input_monitor_) { |
| 224 user_input_monitor_->EnableKeyPressMonitoring(); |
| 225 prev_key_down_count_ = user_input_monitor_->GetKeyPressCount(); |
| 226 } |
| 221 } | 227 } |
| 222 | 228 |
| 223 void AudioInputController::DoRecord() { | 229 void AudioInputController::DoRecord() { |
| 224 DCHECK(message_loop_->BelongsToCurrentThread()); | 230 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 225 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime"); | 231 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime"); |
| 226 | 232 |
| 227 if (state_ != kCreated) | 233 if (state_ != kCreated) |
| 228 return; | 234 return; |
| 229 | 235 |
| 230 { | 236 { |
| 231 base::AutoLock auto_lock(lock_); | 237 base::AutoLock auto_lock(lock_); |
| 232 state_ = kRecording; | 238 state_ = kRecording; |
| 233 } | 239 } |
| 234 | 240 |
| 235 if (no_data_timer_) { | 241 if (no_data_timer_) { |
| 236 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed, | 242 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed, |
| 237 // a callback to DoCheckForNoData() is made. | 243 // a callback to DoCheckForNoData() is made. |
| 238 no_data_timer_->Reset(); | 244 no_data_timer_->Reset(); |
| 239 } | 245 } |
| 240 | 246 |
| 241 stream_->Start(this); | 247 stream_->Start(this); |
| 242 handler_->OnRecording(this); | 248 handler_->OnRecording(this); |
| 243 | |
| 244 if (user_input_monitor_) | |
| 245 user_input_monitor_->AddKeyStrokeListener(this); | |
| 246 } | 249 } |
| 247 | 250 |
| 248 void AudioInputController::DoClose() { | 251 void AudioInputController::DoClose() { |
| 249 DCHECK(message_loop_->BelongsToCurrentThread()); | 252 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 250 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); | 253 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); |
| 251 | 254 |
| 252 // Delete the timer on the same thread that created it. | 255 // Delete the timer on the same thread that created it. |
| 253 no_data_timer_.reset(); | 256 no_data_timer_.reset(); |
| 254 | 257 |
| 255 if (state_ != kClosed) { | 258 if (state_ != kClosed) { |
| 256 DoStopCloseAndClearStream(NULL); | 259 DoStopCloseAndClearStream(NULL); |
| 257 SetDataIsActive(false); | 260 SetDataIsActive(false); |
| 258 | 261 |
| 259 if (LowLatencyMode()) { | 262 if (LowLatencyMode()) { |
| 260 sync_writer_->Close(); | 263 sync_writer_->Close(); |
| 261 } | 264 } |
| 262 | 265 |
| 263 state_ = kClosed; | 266 state_ = kClosed; |
| 264 | 267 |
| 265 if (user_input_monitor_) | 268 if (user_input_monitor_) |
| 266 user_input_monitor_->RemoveKeyStrokeListener(this); | 269 user_input_monitor_->DisableKeyPressMonitoring(); |
| 267 } | 270 } |
| 268 } | 271 } |
| 269 | 272 |
| 270 void AudioInputController::DoReportError() { | 273 void AudioInputController::DoReportError() { |
| 271 DCHECK(message_loop_->BelongsToCurrentThread()); | 274 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 272 handler_->OnError(this); | 275 handler_->OnError(this); |
| 273 } | 276 } |
| 274 | 277 |
| 275 void AudioInputController::DoSetVolume(double volume) { | 278 void AudioInputController::DoSetVolume(double volume) { |
| 276 DCHECK(message_loop_->BelongsToCurrentThread()); | 279 DCHECK(message_loop_->BelongsToCurrentThread()); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 SetDataIsActive(false); | 326 SetDataIsActive(false); |
| 324 | 327 |
| 325 // Restart the timer to ensure that we check the flag again in | 328 // Restart the timer to ensure that we check the flag again in |
| 326 // |kTimerResetIntervalSeconds|. | 329 // |kTimerResetIntervalSeconds|. |
| 327 no_data_timer_->Start( | 330 no_data_timer_->Start( |
| 328 FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds), | 331 FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds), |
| 329 base::Bind(&AudioInputController::DoCheckForNoData, | 332 base::Bind(&AudioInputController::DoCheckForNoData, |
| 330 base::Unretained(this))); | 333 base::Unretained(this))); |
| 331 } | 334 } |
| 332 | 335 |
| 333 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data, | 336 void AudioInputController::OnData(AudioInputStream* stream, |
| 334 uint32 size, uint32 hardware_delay_bytes, | 337 const uint8* data, |
| 338 uint32 size, |
| 339 uint32 hardware_delay_bytes, |
| 335 double volume) { | 340 double volume) { |
| 336 bool key_pressed = false; | |
| 337 { | 341 { |
| 338 base::AutoLock auto_lock(lock_); | 342 base::AutoLock auto_lock(lock_); |
| 339 if (state_ != kRecording) | 343 if (state_ != kRecording) |
| 340 return; | 344 return; |
| 345 } |
| 341 | 346 |
| 342 std::swap(key_pressed, key_pressed_); | 347 bool key_pressed = false; |
| 348 if (user_input_monitor_) { |
| 349 size_t current_count = user_input_monitor_->GetKeyPressCount(); |
| 350 key_pressed = current_count != prev_key_down_count_; |
| 351 prev_key_down_count_ = current_count; |
| 352 DVLOG_IF(6, key_pressed) << "Detected keypress."; |
| 343 } | 353 } |
| 344 | 354 |
| 345 // Mark data as active to ensure that the periodic calls to | 355 // Mark data as active to ensure that the periodic calls to |
| 346 // DoCheckForNoData() does not report an error to the event handler. | 356 // DoCheckForNoData() does not report an error to the event handler. |
| 347 SetDataIsActive(true); | 357 SetDataIsActive(true); |
| 348 | 358 |
| 349 // Use SyncSocket if we are in a low-latency mode. | 359 // Use SyncSocket if we are in a low-latency mode. |
| 350 if (LowLatencyMode()) { | 360 if (LowLatencyMode()) { |
| 351 sync_writer_->Write(data, size, volume, key_pressed); | 361 sync_writer_->Write(data, size, volume, key_pressed); |
| 352 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); | 362 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); |
| 353 return; | 363 return; |
| 354 } | 364 } |
| 355 | 365 |
| 356 handler_->OnData(this, data, size); | 366 handler_->OnData(this, data, size); |
| 357 } | 367 } |
| 358 | 368 |
| 359 void AudioInputController::OnClose(AudioInputStream* stream) { | 369 void AudioInputController::OnClose(AudioInputStream* stream) { |
| 360 DVLOG(1) << "AudioInputController::OnClose()"; | 370 DVLOG(1) << "AudioInputController::OnClose()"; |
| 361 // TODO(satish): Sometimes the device driver closes the input stream without | 371 // TODO(satish): Sometimes the device driver closes the input stream without |
| 362 // us asking for it (may be if the device was unplugged?). Check how to handle | 372 // us asking for it (may be if the device was unplugged?). Check how to handle |
| 363 // such cases here. | 373 // such cases here. |
| 364 } | 374 } |
| 365 | 375 |
| 366 void AudioInputController::OnError(AudioInputStream* stream) { | 376 void AudioInputController::OnError(AudioInputStream* stream) { |
| 367 // Handle error on the audio-manager thread. | 377 // Handle error on the audio-manager thread. |
| 368 message_loop_->PostTask(FROM_HERE, base::Bind( | 378 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 369 &AudioInputController::DoReportError, this)); | 379 &AudioInputController::DoReportError, this)); |
| 370 } | 380 } |
| 371 | 381 |
| 372 void AudioInputController::OnKeyStroke() { | |
| 373 base::AutoLock auto_lock(lock_); | |
| 374 key_pressed_ = true; | |
| 375 } | |
| 376 | |
| 377 void AudioInputController::DoStopCloseAndClearStream( | 382 void AudioInputController::DoStopCloseAndClearStream( |
| 378 base::WaitableEvent* done) { | 383 base::WaitableEvent* done) { |
| 379 DCHECK(message_loop_->BelongsToCurrentThread()); | 384 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 380 | 385 |
| 381 // Allow calling unconditionally and bail if we don't have a stream to close. | 386 // Allow calling unconditionally and bail if we don't have a stream to close. |
| 382 if (stream_ != NULL) { | 387 if (stream_ != NULL) { |
| 383 stream_->Stop(); | 388 stream_->Stop(); |
| 384 stream_->Close(); | 389 stream_->Close(); |
| 385 stream_ = NULL; | 390 stream_ = NULL; |
| 386 } | 391 } |
| 387 | 392 |
| 388 // Should be last in the method, do not touch "this" from here on. | 393 // Should be last in the method, do not touch "this" from here on. |
| 389 if (done != NULL) | 394 if (done != NULL) |
| 390 done->Signal(); | 395 done->Signal(); |
| 391 } | 396 } |
| 392 | 397 |
| 393 void AudioInputController::SetDataIsActive(bool enabled) { | 398 void AudioInputController::SetDataIsActive(bool enabled) { |
| 394 base::subtle::Release_Store(&data_is_active_, enabled); | 399 base::subtle::Release_Store(&data_is_active_, enabled); |
| 395 } | 400 } |
| 396 | 401 |
| 397 bool AudioInputController::GetDataIsActive() { | 402 bool AudioInputController::GetDataIsActive() { |
| 398 return (base::subtle::Acquire_Load(&data_is_active_) != false); | 403 return (base::subtle::Acquire_Load(&data_is_active_) != false); |
| 399 } | 404 } |
| 400 | 405 |
| 401 } // namespace media | 406 } // namespace media |
| OLD | NEW |