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 |