| 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" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 const int kTimerInitialIntervalSeconds = 5; | 29 const int kTimerInitialIntervalSeconds = 5; |
| 30 #endif // defined(OS_IOS) | 30 #endif // defined(OS_IOS) |
| 31 } | 31 } |
| 32 | 32 |
| 33 namespace media { | 33 namespace media { |
| 34 | 34 |
| 35 // static | 35 // static |
| 36 AudioInputController::Factory* AudioInputController::factory_ = NULL; | 36 AudioInputController::Factory* AudioInputController::factory_ = NULL; |
| 37 | 37 |
| 38 AudioInputController::AudioInputController(EventHandler* handler, | 38 AudioInputController::AudioInputController(EventHandler* handler, |
| 39 SyncWriter* sync_writer) | 39 SyncWriter* sync_writer, |
| 40 KeyPressMonitor* key_press_monitor) |
| 40 : creator_loop_(base::MessageLoopProxy::current()), | 41 : creator_loop_(base::MessageLoopProxy::current()), |
| 41 handler_(handler), | 42 handler_(handler), |
| 42 stream_(NULL), | 43 stream_(NULL), |
| 43 data_is_active_(false), | 44 data_is_active_(false), |
| 44 state_(kEmpty), | 45 state_(kEmpty), |
| 45 sync_writer_(sync_writer), | 46 sync_writer_(sync_writer), |
| 46 max_volume_(0.0) { | 47 max_volume_(0.0), |
| 48 key_press_monitor_(key_press_monitor), |
| 49 key_pressed_(false) { |
| 47 DCHECK(creator_loop_.get()); | 50 DCHECK(creator_loop_.get()); |
| 48 } | 51 } |
| 49 | 52 |
| 50 AudioInputController::~AudioInputController() { | 53 AudioInputController::~AudioInputController() { |
| 51 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_); | 54 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_); |
| 52 } | 55 } |
| 53 | 56 |
| 54 // static | 57 // static |
| 55 scoped_refptr<AudioInputController> AudioInputController::Create( | 58 scoped_refptr<AudioInputController> AudioInputController::Create( |
| 56 AudioManager* audio_manager, | 59 AudioManager* audio_manager, |
| 57 EventHandler* event_handler, | 60 EventHandler* event_handler, |
| 58 const AudioParameters& params, | 61 const AudioParameters& params, |
| 59 const std::string& device_id) { | 62 const std::string& device_id, |
| 63 KeyPressMonitor* key_press_monitor) { |
| 60 DCHECK(audio_manager); | 64 DCHECK(audio_manager); |
| 61 | 65 |
| 62 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) | 66 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) |
| 63 return NULL; | 67 return NULL; |
| 64 | 68 |
| 65 if (factory_) | 69 if (factory_) { |
| 66 return factory_->Create(audio_manager, event_handler, params); | 70 return factory_->Create( |
| 67 | 71 audio_manager, event_handler, params, key_press_monitor); |
| 68 scoped_refptr<AudioInputController> controller(new AudioInputController( | 72 } |
| 69 event_handler, NULL)); | 73 scoped_refptr<AudioInputController> controller( |
| 74 new AudioInputController(event_handler, NULL, key_press_monitor)); |
| 70 | 75 |
| 71 controller->message_loop_ = audio_manager->GetMessageLoop(); | 76 controller->message_loop_ = audio_manager->GetMessageLoop(); |
| 72 | 77 |
| 73 // Create and open a new audio input stream from the existing | 78 // Create and open a new audio input stream from the existing |
| 74 // audio-device thread. | 79 // audio-device thread. |
| 75 if (!controller->message_loop_->PostTask(FROM_HERE, | 80 if (!controller->message_loop_->PostTask(FROM_HERE, |
| 76 base::Bind(&AudioInputController::DoCreate, controller, | 81 base::Bind(&AudioInputController::DoCreate, controller, |
| 77 base::Unretained(audio_manager), params, device_id))) { | 82 base::Unretained(audio_manager), params, device_id))) { |
| 78 controller = NULL; | 83 controller = NULL; |
| 79 } | 84 } |
| 80 | 85 |
| 81 return controller; | 86 return controller; |
| 82 } | 87 } |
| 83 | 88 |
| 84 // static | 89 // static |
| 85 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( | 90 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( |
| 86 AudioManager* audio_manager, | 91 AudioManager* audio_manager, |
| 87 EventHandler* event_handler, | 92 EventHandler* event_handler, |
| 88 const AudioParameters& params, | 93 const AudioParameters& params, |
| 89 const std::string& device_id, | 94 const std::string& device_id, |
| 90 SyncWriter* sync_writer) { | 95 SyncWriter* sync_writer, |
| 96 KeyPressMonitor* key_press_monitor) { |
| 91 DCHECK(audio_manager); | 97 DCHECK(audio_manager); |
| 92 DCHECK(sync_writer); | 98 DCHECK(sync_writer); |
| 93 | 99 |
| 94 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) | 100 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) |
| 95 return NULL; | 101 return NULL; |
| 96 | 102 |
| 97 // Create the AudioInputController object and ensure that it runs on | 103 // Create the AudioInputController object and ensure that it runs on |
| 98 // the audio-manager thread. | 104 // the audio-manager thread. |
| 99 scoped_refptr<AudioInputController> controller(new AudioInputController( | 105 scoped_refptr<AudioInputController> controller( |
| 100 event_handler, sync_writer)); | 106 new AudioInputController(event_handler, sync_writer, key_press_monitor)); |
| 101 controller->message_loop_ = audio_manager->GetMessageLoop(); | 107 controller->message_loop_ = audio_manager->GetMessageLoop(); |
| 102 | 108 |
| 103 // Create and open a new audio input stream from the existing | 109 // Create and open a new audio input stream from the existing |
| 104 // audio-device thread. Use the provided audio-input device. | 110 // audio-device thread. Use the provided audio-input device. |
| 105 if (!controller->message_loop_->PostTask(FROM_HERE, | 111 if (!controller->message_loop_->PostTask(FROM_HERE, |
| 106 base::Bind(&AudioInputController::DoCreate, controller, | 112 base::Bind(&AudioInputController::DoCreate, controller, |
| 107 base::Unretained(audio_manager), params, device_id))) { | 113 base::Unretained(audio_manager), params, device_id))) { |
| 108 controller = NULL; | 114 controller = NULL; |
| 109 } | 115 } |
| 110 | 116 |
| 111 return controller; | 117 return controller; |
| 112 } | 118 } |
| 113 | 119 |
| 114 // static | 120 // static |
| 115 scoped_refptr<AudioInputController> AudioInputController::CreateForStream( | 121 scoped_refptr<AudioInputController> AudioInputController::CreateForStream( |
| 116 const scoped_refptr<base::MessageLoopProxy>& message_loop, | 122 const scoped_refptr<base::MessageLoopProxy>& message_loop, |
| 117 EventHandler* event_handler, | 123 EventHandler* event_handler, |
| 118 AudioInputStream* stream, | 124 AudioInputStream* stream, |
| 119 SyncWriter* sync_writer) { | 125 SyncWriter* sync_writer, |
| 126 KeyPressMonitor* key_press_monitor) { |
| 120 DCHECK(sync_writer); | 127 DCHECK(sync_writer); |
| 121 DCHECK(stream); | 128 DCHECK(stream); |
| 122 | 129 |
| 123 // Create the AudioInputController object and ensure that it runs on | 130 // Create the AudioInputController object and ensure that it runs on |
| 124 // the audio-manager thread. | 131 // the audio-manager thread. |
| 125 scoped_refptr<AudioInputController> controller(new AudioInputController( | 132 scoped_refptr<AudioInputController> controller( |
| 126 event_handler, sync_writer)); | 133 new AudioInputController(event_handler, sync_writer, key_press_monitor)); |
| 127 controller->message_loop_ = message_loop; | 134 controller->message_loop_ = message_loop; |
| 128 | 135 |
| 129 // TODO(miu): See TODO at top of file. Until that's resolved, we need to | 136 // 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 | 137 // disable the error auto-detection here (since the audio mirroring |
| 131 // implementation will reliably report error and close events). Note, of | 138 // implementation will reliably report error and close events). Note, of |
| 132 // course, that we're assuming CreateForStream() has been called for the audio | 139 // course, that we're assuming CreateForStream() has been called for the audio |
| 133 // mirroring use case only. | 140 // mirroring use case only. |
| 134 if (!controller->message_loop_->PostTask( | 141 if (!controller->message_loop_->PostTask( |
| 135 FROM_HERE, | 142 FROM_HERE, |
| 136 base::Bind(&AudioInputController::DoCreateForStream, controller, | 143 base::Bind(&AudioInputController::DoCreateForStream, controller, |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 } | 233 } |
| 227 | 234 |
| 228 if (no_data_timer_) { | 235 if (no_data_timer_) { |
| 229 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed, | 236 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed, |
| 230 // a callback to DoCheckForNoData() is made. | 237 // a callback to DoCheckForNoData() is made. |
| 231 no_data_timer_->Reset(); | 238 no_data_timer_->Reset(); |
| 232 } | 239 } |
| 233 | 240 |
| 234 stream_->Start(this); | 241 stream_->Start(this); |
| 235 handler_->OnRecording(this); | 242 handler_->OnRecording(this); |
| 243 |
| 244 key_press_monitor_->AddKeyPressListener(this); |
| 236 } | 245 } |
| 237 | 246 |
| 238 void AudioInputController::DoClose() { | 247 void AudioInputController::DoClose() { |
| 239 DCHECK(message_loop_->BelongsToCurrentThread()); | 248 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 240 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); | 249 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); |
| 241 | 250 |
| 242 // Delete the timer on the same thread that created it. | 251 // Delete the timer on the same thread that created it. |
| 243 no_data_timer_.reset(); | 252 no_data_timer_.reset(); |
| 244 | 253 |
| 245 if (state_ != kClosed) { | 254 if (state_ != kClosed) { |
| 246 DoStopCloseAndClearStream(NULL); | 255 DoStopCloseAndClearStream(NULL); |
| 247 SetDataIsActive(false); | 256 SetDataIsActive(false); |
| 248 | 257 |
| 249 if (LowLatencyMode()) { | 258 if (LowLatencyMode()) { |
| 250 sync_writer_->Close(); | 259 sync_writer_->Close(); |
| 251 } | 260 } |
| 252 | 261 |
| 253 state_ = kClosed; | 262 state_ = kClosed; |
| 254 } | 263 } |
| 264 key_press_monitor_->RemoveKeyPressListener(this); |
| 255 } | 265 } |
| 256 | 266 |
| 257 void AudioInputController::DoReportError() { | 267 void AudioInputController::DoReportError() { |
| 258 DCHECK(message_loop_->BelongsToCurrentThread()); | 268 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 259 handler_->OnError(this); | 269 handler_->OnError(this); |
| 260 } | 270 } |
| 261 | 271 |
| 262 void AudioInputController::DoSetVolume(double volume) { | 272 void AudioInputController::DoSetVolume(double volume) { |
| 263 DCHECK(message_loop_->BelongsToCurrentThread()); | 273 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 264 DCHECK_GE(volume, 0); | 274 DCHECK_GE(volume, 0); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 // |kTimerResetIntervalSeconds|. | 323 // |kTimerResetIntervalSeconds|. |
| 314 no_data_timer_->Start( | 324 no_data_timer_->Start( |
| 315 FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds), | 325 FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds), |
| 316 base::Bind(&AudioInputController::DoCheckForNoData, | 326 base::Bind(&AudioInputController::DoCheckForNoData, |
| 317 base::Unretained(this))); | 327 base::Unretained(this))); |
| 318 } | 328 } |
| 319 | 329 |
| 320 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data, | 330 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data, |
| 321 uint32 size, uint32 hardware_delay_bytes, | 331 uint32 size, uint32 hardware_delay_bytes, |
| 322 double volume) { | 332 double volume) { |
| 333 bool key_pressed = false; |
| 323 { | 334 { |
| 324 base::AutoLock auto_lock(lock_); | 335 base::AutoLock auto_lock(lock_); |
| 325 if (state_ != kRecording) | 336 if (state_ != kRecording) |
| 326 return; | 337 return; |
| 338 |
| 339 std::swap(key_pressed, key_pressed_); |
| 327 } | 340 } |
| 328 | 341 |
| 329 // Mark data as active to ensure that the periodic calls to | 342 // Mark data as active to ensure that the periodic calls to |
| 330 // DoCheckForNoData() does not report an error to the event handler. | 343 // DoCheckForNoData() does not report an error to the event handler. |
| 331 SetDataIsActive(true); | 344 SetDataIsActive(true); |
| 332 | 345 |
| 333 // Use SyncSocket if we are in a low-latency mode. | 346 // Use SyncSocket if we are in a low-latency mode. |
| 334 if (LowLatencyMode()) { | 347 if (LowLatencyMode()) { |
| 335 sync_writer_->Write(data, size, volume); | 348 sync_writer_->Write(data, size, volume, key_pressed); |
| 336 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); | 349 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); |
| 337 return; | 350 return; |
| 338 } | 351 } |
| 339 | 352 |
| 340 handler_->OnData(this, data, size); | 353 handler_->OnData(this, data, size); |
| 341 } | 354 } |
| 342 | 355 |
| 343 void AudioInputController::OnClose(AudioInputStream* stream) { | 356 void AudioInputController::OnClose(AudioInputStream* stream) { |
| 344 DVLOG(1) << "AudioInputController::OnClose()"; | 357 DVLOG(1) << "AudioInputController::OnClose()"; |
| 345 // TODO(satish): Sometimes the device driver closes the input stream without | 358 // 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 | 359 // us asking for it (may be if the device was unplugged?). Check how to handle |
| 347 // such cases here. | 360 // such cases here. |
| 348 } | 361 } |
| 349 | 362 |
| 350 void AudioInputController::OnError(AudioInputStream* stream) { | 363 void AudioInputController::OnError(AudioInputStream* stream) { |
| 351 // Handle error on the audio-manager thread. | 364 // Handle error on the audio-manager thread. |
| 352 message_loop_->PostTask(FROM_HERE, base::Bind( | 365 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 353 &AudioInputController::DoReportError, this)); | 366 &AudioInputController::DoReportError, this)); |
| 354 } | 367 } |
| 355 | 368 |
| 369 void AudioInputController::OnKeyPressed() { |
| 370 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 371 base::AutoLock auto_lock(lock_); |
| 372 key_pressed_ = true; |
| 373 } |
| 374 |
| 356 void AudioInputController::DoStopCloseAndClearStream( | 375 void AudioInputController::DoStopCloseAndClearStream( |
| 357 base::WaitableEvent *done) { | 376 base::WaitableEvent* done) { |
| 358 DCHECK(message_loop_->BelongsToCurrentThread()); | 377 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 359 | 378 |
| 360 // Allow calling unconditionally and bail if we don't have a stream to close. | 379 // Allow calling unconditionally and bail if we don't have a stream to close. |
| 361 if (stream_ != NULL) { | 380 if (stream_ != NULL) { |
| 362 stream_->Stop(); | 381 stream_->Stop(); |
| 363 stream_->Close(); | 382 stream_->Close(); |
| 364 stream_ = NULL; | 383 stream_ = NULL; |
| 365 } | 384 } |
| 366 | 385 |
| 367 // Should be last in the method, do not touch "this" from here on. | 386 // Should be last in the method, do not touch "this" from here on. |
| 368 if (done != NULL) | 387 if (done != NULL) |
| 369 done->Signal(); | 388 done->Signal(); |
| 370 } | 389 } |
| 371 | 390 |
| 372 void AudioInputController::SetDataIsActive(bool enabled) { | 391 void AudioInputController::SetDataIsActive(bool enabled) { |
| 373 base::subtle::Release_Store(&data_is_active_, enabled); | 392 base::subtle::Release_Store(&data_is_active_, enabled); |
| 374 } | 393 } |
| 375 | 394 |
| 376 bool AudioInputController::GetDataIsActive() { | 395 bool AudioInputController::GetDataIsActive() { |
| 377 return (base::subtle::Acquire_Load(&data_is_active_) != false); | 396 return (base::subtle::Acquire_Load(&data_is_active_) != false); |
| 378 } | 397 } |
| 379 | 398 |
| 380 } // namespace media | 399 } // namespace media |
| OLD | NEW |