Chromium Code Reviews| 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 "base/time/time.h" | |
| 9 #include "media/base/limits.h" | 10 #include "media/base/limits.h" |
| 10 #include "media/base/scoped_histogram_timer.h" | 11 #include "media/base/scoped_histogram_timer.h" |
| 11 #include "media/base/user_input_monitor.h" | 12 #include "media/base/user_input_monitor.h" |
| 12 | 13 |
| 14 using base::TimeDelta; | |
| 15 | |
| 13 namespace { | 16 namespace { |
| 14 const int kMaxInputChannels = 3; | 17 const int kMaxInputChannels = 3; |
| 15 | 18 |
| 16 // TODO(henrika): remove usage of timers and add support for proper | 19 // TODO(henrika): remove usage of timers and add support for proper |
| 17 // notification of when the input device is removed. This was originally added | 20 // notification of when the input device is removed. This was originally added |
| 18 // to resolve http://crbug.com/79936 for Windows platforms. This then caused | 21 // to resolve http://crbug.com/79936 for Windows platforms. This then caused |
| 19 // breakage (very hard to repro bugs!) on other platforms: See | 22 // breakage (very hard to repro bugs!) on other platforms: See |
| 20 // http://crbug.com/226327 and http://crbug.com/230972. | 23 // http://crbug.com/226327 and http://crbug.com/230972. |
| 21 // See also that the timer has been disabled on Mac now due to | 24 // See also that the timer has been disabled on Mac now due to |
| 22 // crbug.com/357501. | 25 // crbug.com/357501. |
| 23 const int kTimerResetIntervalSeconds = 1; | 26 const int kTimerResetIntervalSeconds = 1; |
| 24 // We have received reports that the timer can be too trigger happy on some | 27 // We have received reports that the timer can be too trigger happy on some |
| 25 // Mac devices and the initial timer interval has therefore been increased | 28 // Mac devices and the initial timer interval has therefore been increased |
| 26 // from 1 second to 5 seconds. | 29 // from 1 second to 5 seconds. |
| 27 const int kTimerInitialIntervalSeconds = 5; | 30 const int kTimerInitialIntervalSeconds = 5; |
| 31 | |
| 32 // Time constant for AudioPowerMonitor. | |
| 33 // The utilized smoothing factor (alpha) in the exponential filter is given | |
| 34 // by 1-exp(-1/(fs*ts)), where fs is the sample rate in Hz and ts is the time | |
| 35 // constant given by |kPowerMeasurementTimeConstantMilliseconds|. | |
| 36 // Example: fs=44100, ts=10e-3 => alpha~0.022420 | |
| 37 // fs=44100, ts=20e-3 => alpha~0.165903 | |
| 38 // A large smoothing factor corresponds to a faster filter response to input | |
| 39 // changes since y(n)=alpha*x(n)+(1-alpha)*y(n-1), where x(n) is the input | |
| 40 // and y(n) is the output. | |
| 41 const int kPowerMeasurementTimeConstantMilliseconds = 10; | |
| 42 | |
| 43 // Time between two successive measurements of audio power levels. | |
| 44 const int kPowerMonitorLogIntervalMilliseconds = 1000; | |
| 28 } | 45 } |
| 29 | 46 |
| 30 namespace media { | 47 namespace media { |
| 31 | 48 |
| 32 // static | 49 // static |
| 33 AudioInputController::Factory* AudioInputController::factory_ = NULL; | 50 AudioInputController::Factory* AudioInputController::factory_ = NULL; |
| 34 | 51 |
| 52 #if defined(AUDIO_POWER_MONITORING) | |
| 53 // Calculate and log the audible level in the range [0.0,1.0], where 0.0 | |
| 54 // means the audio signal is silent and 1.0 means it is at maximum volume. | |
| 55 // TODO(henrika): we should call MediaStreamManager::SendMessageToNativeLog() | |
| 56 // here as well. | |
| 57 static void AddPowerLevelToLog(float level_dbfs) { | |
|
no longer working on chromium
2014/05/23 08:29:56
shouldn't you hook it up to the native log?
henrika (OOO until Aug 14)
2014/05/23 08:42:45
Yes, just wanted OK about general stuff first. Wil
henrika (OOO until Aug 14)
2014/05/26 11:02:26
I removed this part and log in dBFS instead. Easie
| |
| 58 float level = 0; | |
| 59 static const float kSilenceThresholdDBFS = -72.24719896f; | |
| 60 if (level_dbfs < kSilenceThresholdDBFS) | |
| 61 level = 0.0f; | |
| 62 else if (level_dbfs > 0.0f) | |
| 63 level = 1.0f; | |
| 64 else | |
| 65 level = 1.0f - level_dbfs / kSilenceThresholdDBFS; | |
| 66 DVLOG(1) << "audio_level: " << level; | |
| 67 } | |
| 68 #endif | |
| 69 | |
| 35 AudioInputController::AudioInputController(EventHandler* handler, | 70 AudioInputController::AudioInputController(EventHandler* handler, |
| 36 SyncWriter* sync_writer, | 71 SyncWriter* sync_writer, |
| 37 UserInputMonitor* user_input_monitor) | 72 UserInputMonitor* user_input_monitor) |
| 38 : creator_task_runner_(base::MessageLoopProxy::current()), | 73 : creator_task_runner_(base::MessageLoopProxy::current()), |
| 39 handler_(handler), | 74 handler_(handler), |
| 40 stream_(NULL), | 75 stream_(NULL), |
| 41 data_is_active_(false), | 76 data_is_active_(false), |
| 42 state_(CLOSED), | 77 state_(CLOSED), |
| 43 sync_writer_(sync_writer), | 78 sync_writer_(sync_writer), |
| 44 max_volume_(0.0), | 79 max_volume_(0.0), |
| 45 user_input_monitor_(user_input_monitor), | 80 user_input_monitor_(user_input_monitor), |
| 46 prev_key_down_count_(0) { | 81 prev_key_down_count_(0) { |
| 47 DCHECK(creator_task_runner_.get()); | 82 DCHECK(creator_task_runner_.get()); |
| 48 } | 83 } |
| 49 | 84 |
| 50 AudioInputController::~AudioInputController() { | 85 AudioInputController::~AudioInputController() { |
| 51 DCHECK_EQ(state_, CLOSED); | 86 DCHECK_EQ(state_, CLOSED); |
| 52 } | 87 } |
| 53 | 88 |
| 54 // static | 89 // static |
| 55 scoped_refptr<AudioInputController> AudioInputController::Create( | 90 scoped_refptr<AudioInputController> AudioInputController::Create( |
| 56 AudioManager* audio_manager, | 91 AudioManager* audio_manager, |
| 57 EventHandler* event_handler, | 92 EventHandler* event_handler, |
| 58 const AudioParameters& params, | 93 const AudioParameters& params, |
| 59 const std::string& device_id, | 94 const std::string& device_id, |
| 60 UserInputMonitor* user_input_monitor) { | 95 UserInputMonitor* user_input_monitor) { |
| 61 DCHECK(audio_manager); | 96 DCHECK(audio_manager); |
| 97 DVLOG(1) << "AudioInputController::Create"; | |
| 62 | 98 |
| 63 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) | 99 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) |
| 64 return NULL; | 100 return NULL; |
| 65 | 101 |
| 66 if (factory_) { | 102 if (factory_) { |
| 67 return factory_->Create( | 103 return factory_->Create( |
| 68 audio_manager, event_handler, params, user_input_monitor); | 104 audio_manager, event_handler, params, user_input_monitor); |
| 69 } | 105 } |
| 70 scoped_refptr<AudioInputController> controller( | 106 scoped_refptr<AudioInputController> controller( |
| 71 new AudioInputController(event_handler, NULL, user_input_monitor)); | 107 new AudioInputController(event_handler, NULL, user_input_monitor)); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 86 // static | 122 // static |
| 87 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( | 123 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( |
| 88 AudioManager* audio_manager, | 124 AudioManager* audio_manager, |
| 89 EventHandler* event_handler, | 125 EventHandler* event_handler, |
| 90 const AudioParameters& params, | 126 const AudioParameters& params, |
| 91 const std::string& device_id, | 127 const std::string& device_id, |
| 92 SyncWriter* sync_writer, | 128 SyncWriter* sync_writer, |
| 93 UserInputMonitor* user_input_monitor) { | 129 UserInputMonitor* user_input_monitor) { |
| 94 DCHECK(audio_manager); | 130 DCHECK(audio_manager); |
| 95 DCHECK(sync_writer); | 131 DCHECK(sync_writer); |
| 132 DVLOG(1) << "AudioInputController::CreateLowLatency"; | |
| 96 | 133 |
| 97 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) | 134 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) |
| 98 return NULL; | 135 return NULL; |
| 99 | 136 |
| 100 // Create the AudioInputController object and ensure that it runs on | 137 // Create the AudioInputController object and ensure that it runs on |
| 101 // the audio-manager thread. | 138 // the audio-manager thread. |
| 102 scoped_refptr<AudioInputController> controller( | 139 scoped_refptr<AudioInputController> controller( |
| 103 new AudioInputController(event_handler, sync_writer, user_input_monitor)); | 140 new AudioInputController(event_handler, sync_writer, user_input_monitor)); |
| 104 controller->task_runner_ = audio_manager->GetTaskRunner(); | 141 controller->task_runner_ = audio_manager->GetTaskRunner(); |
| 105 | 142 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 166 void AudioInputController::SetAutomaticGainControl(bool enabled) { | 203 void AudioInputController::SetAutomaticGainControl(bool enabled) { |
| 167 task_runner_->PostTask(FROM_HERE, base::Bind( | 204 task_runner_->PostTask(FROM_HERE, base::Bind( |
| 168 &AudioInputController::DoSetAutomaticGainControl, this, enabled)); | 205 &AudioInputController::DoSetAutomaticGainControl, this, enabled)); |
| 169 } | 206 } |
| 170 | 207 |
| 171 void AudioInputController::DoCreate(AudioManager* audio_manager, | 208 void AudioInputController::DoCreate(AudioManager* audio_manager, |
| 172 const AudioParameters& params, | 209 const AudioParameters& params, |
| 173 const std::string& device_id) { | 210 const std::string& device_id) { |
| 174 DCHECK(task_runner_->BelongsToCurrentThread()); | 211 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 175 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime"); | 212 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime"); |
| 213 DVLOG(1) << "AudioInputController::DoCreate"; | |
| 214 | |
| 215 #if defined(AUDIO_POWER_MONITORING) | |
| 216 // Create the audio (power) level meter given the provided audio parameters. | |
| 217 // An AudioBus is also needed to wrap the raw data buffer from the native | |
| 218 // layer to match AudioPowerMonitor::Scan(). | |
| 219 // TODO(henrika): Remove use of extra AudioBus. See http://crbug.com/375155. | |
| 220 audio_level_.reset(new media::AudioPowerMonitor(params.sample_rate(), | |
| 221 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMilliseconds))); | |
| 222 audio_bus_ = AudioBus::Create(params); | |
| 223 audio_params_ = params; | |
| 224 #endif | |
| 225 | |
| 176 // TODO(miu): See TODO at top of file. Until that's resolved, assume all | 226 // TODO(miu): See TODO at top of file. Until that's resolved, assume all |
| 177 // platform audio input requires the |no_data_timer_| be used to auto-detect | 227 // platform audio input requires the |no_data_timer_| be used to auto-detect |
| 178 // errors. In reality, probably only Windows needs to be treated as | 228 // errors. In reality, probably only Windows needs to be treated as |
| 179 // unreliable here. | 229 // unreliable here. |
| 180 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id), | 230 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id), |
| 181 true); | 231 true); |
| 182 } | 232 } |
| 183 | 233 |
| 184 void AudioInputController::DoCreateForStream( | 234 void AudioInputController::DoCreateForStream( |
| 185 AudioInputStream* stream_to_control, bool enable_nodata_timer) { | 235 AudioInputStream* stream_to_control, bool enable_nodata_timer) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 259 void AudioInputController::DoClose() { | 309 void AudioInputController::DoClose() { |
| 260 DCHECK(task_runner_->BelongsToCurrentThread()); | 310 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 261 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); | 311 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); |
| 262 | 312 |
| 263 if (state_ == CLOSED) | 313 if (state_ == CLOSED) |
| 264 return; | 314 return; |
| 265 | 315 |
| 266 // Delete the timer on the same thread that created it. | 316 // Delete the timer on the same thread that created it. |
| 267 no_data_timer_.reset(); | 317 no_data_timer_.reset(); |
| 268 | 318 |
| 319 #if defined(AUDIO_POWER_MONITORING) | |
| 320 if (audio_level_) | |
| 321 audio_level_->Reset(); | |
|
no longer working on chromium
2014/05/23 08:29:56
I realized I was confused with Reset() and reset()
henrika (OOO until Aug 14)
2014/05/23 08:42:45
Good point. I can do that.
henrika (OOO until Aug 14)
2014/05/26 11:02:26
Done.
| |
| 322 #endif | |
| 323 | |
| 269 DoStopCloseAndClearStream(); | 324 DoStopCloseAndClearStream(); |
| 270 SetDataIsActive(false); | 325 SetDataIsActive(false); |
| 271 | 326 |
| 272 if (SharedMemoryAndSyncSocketMode()) | 327 if (SharedMemoryAndSyncSocketMode()) |
| 273 sync_writer_->Close(); | 328 sync_writer_->Close(); |
| 274 | 329 |
| 275 if (user_input_monitor_) | 330 if (user_input_monitor_) |
| 276 user_input_monitor_->DisableKeyPressMonitoring(); | 331 user_input_monitor_->DisableKeyPressMonitoring(); |
| 277 | 332 |
| 278 state_ = CLOSED; | 333 state_ = CLOSED; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 370 key_pressed = current_count != prev_key_down_count_; | 425 key_pressed = current_count != prev_key_down_count_; |
| 371 prev_key_down_count_ = current_count; | 426 prev_key_down_count_ = current_count; |
| 372 DVLOG_IF(6, key_pressed) << "Detected keypress."; | 427 DVLOG_IF(6, key_pressed) << "Detected keypress."; |
| 373 } | 428 } |
| 374 | 429 |
| 375 // Use SharedMemory and SyncSocket if the client has created a SyncWriter. | 430 // Use SharedMemory and SyncSocket if the client has created a SyncWriter. |
| 376 // Used by all low-latency clients except WebSpeech. | 431 // Used by all low-latency clients except WebSpeech. |
| 377 if (SharedMemoryAndSyncSocketMode()) { | 432 if (SharedMemoryAndSyncSocketMode()) { |
| 378 sync_writer_->Write(data, size, volume, key_pressed); | 433 sync_writer_->Write(data, size, volume, key_pressed); |
| 379 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); | 434 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); |
| 435 | |
| 436 #if defined(AUDIO_POWER_MONITORING) | |
| 437 { | |
| 438 // Only do power-level measurements if an AudioPowerMonitor object has | |
| 439 // been created. Done in DoCreate() but not DoCreateForStream(), hence | |
| 440 // logging will mainly be done for WebRTC and WebSpeech clients. | |
| 441 base::AutoLock auto_lock(lock_); | |
| 442 if (!audio_level_) | |
|
no longer working on chromium
2014/05/23 08:29:56
why this needs to be under the lock?
henrika (OOO until Aug 14)
2014/05/23 08:42:45
The callback is called on a native audio thread an
no longer working on chromium
2014/05/26 14:20:16
not sure I follow here. In DoCreate(), the creatio
| |
| 443 return; | |
| 444 } | |
| 445 | |
| 446 // Perform periodic audio (power) level measurements. | |
| 447 if ((base::TimeTicks::Now() - last_audio_level_log_time_).InMilliseconds() > | |
| 448 kPowerMonitorLogIntervalMilliseconds) { | |
|
no longer working on chromium
2014/05/23 08:29:56
indentation
henrika (OOO until Aug 14)
2014/05/23 08:42:45
Done.
henrika (OOO until Aug 14)
2014/05/26 11:02:26
Actually; this is what I get when using git cl for
| |
| 449 // Wrap data into and AudioBus to match AudioPowerMonitor::Scan. | |
| 450 audio_bus_->FromInterleaved( | |
|
no longer working on chromium
2014/05/23 08:29:56
please add a todo here to remind switching to Audi
henrika (OOO until Aug 14)
2014/05/23 08:42:45
Will do.
| |
| 451 data, audio_bus_->frames(), audio_params_.bits_per_sample() / 8); | |
| 452 audio_level_->Scan(*audio_bus_, audio_bus_->frames()); | |
| 453 | |
| 454 // Get current average power level and add it to the log. | |
| 455 std::pair<float, bool> result = audio_level_->ReadCurrentPowerAndClip(); | |
| 456 AddPowerLevelToLog(result.first); | |
| 457 | |
| 458 // Reset the average power level (since we don't log continuously). | |
| 459 audio_level_->Reset(); | |
|
no longer working on chromium
2014/05/23 08:29:56
I am not familiar with AudioPowerMonitor, do you k
henrika (OOO until Aug 14)
2014/05/23 08:42:45
Yes it works. The smoothing factor controls how fa
| |
| 460 last_audio_level_log_time_ = base::TimeTicks::Now(); | |
| 461 } | |
| 462 #endif | |
| 463 | |
| 380 return; | 464 return; |
| 381 } | 465 } |
| 382 | 466 |
| 383 // TODO(henrika): Investigate if we can avoid the extra copy here. | 467 // TODO(henrika): Investigate if we can avoid the extra copy here. |
| 384 // (see http://crbug.com/249316 for details). AFAIK, this scope is only | 468 // (see http://crbug.com/249316 for details). AFAIK, this scope is only |
| 385 // active for WebSpeech clients. | 469 // active for WebSpeech clients. |
| 386 scoped_ptr<uint8[]> audio_data(new uint8[size]); | 470 scoped_ptr<uint8[]> audio_data(new uint8[size]); |
| 387 memcpy(audio_data.get(), data, size); | 471 memcpy(audio_data.get(), data, size); |
| 388 | 472 |
| 389 // Ownership of the audio buffer will be with the callback until it is run, | 473 // Ownership of the audio buffer will be with the callback until it is run, |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 420 | 504 |
| 421 void AudioInputController::SetDataIsActive(bool enabled) { | 505 void AudioInputController::SetDataIsActive(bool enabled) { |
| 422 base::subtle::Release_Store(&data_is_active_, enabled); | 506 base::subtle::Release_Store(&data_is_active_, enabled); |
| 423 } | 507 } |
| 424 | 508 |
| 425 bool AudioInputController::GetDataIsActive() { | 509 bool AudioInputController::GetDataIsActive() { |
| 426 return (base::subtle::Acquire_Load(&data_is_active_) != false); | 510 return (base::subtle::Acquire_Load(&data_is_active_) != false); |
| 427 } | 511 } |
| 428 | 512 |
| 429 } // namespace media | 513 } // namespace media |
| OLD | NEW |