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/strings/stringprintf.h" |
8 #include "base/threading/thread_restrictions.h" | 9 #include "base/threading/thread_restrictions.h" |
| 10 #include "base/time/time.h" |
9 #include "media/base/limits.h" | 11 #include "media/base/limits.h" |
10 #include "media/base/scoped_histogram_timer.h" | 12 #include "media/base/scoped_histogram_timer.h" |
11 #include "media/base/user_input_monitor.h" | 13 #include "media/base/user_input_monitor.h" |
12 | 14 |
| 15 using base::TimeDelta; |
| 16 |
13 namespace { | 17 namespace { |
14 const int kMaxInputChannels = 3; | 18 const int kMaxInputChannels = 3; |
15 | 19 |
16 // TODO(henrika): remove usage of timers and add support for proper | 20 // TODO(henrika): remove usage of timers and add support for proper |
17 // notification of when the input device is removed. This was originally added | 21 // 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 | 22 // to resolve http://crbug.com/79936 for Windows platforms. This then caused |
19 // breakage (very hard to repro bugs!) on other platforms: See | 23 // breakage (very hard to repro bugs!) on other platforms: See |
20 // http://crbug.com/226327 and http://crbug.com/230972. | 24 // http://crbug.com/226327 and http://crbug.com/230972. |
21 // See also that the timer has been disabled on Mac now due to | 25 // See also that the timer has been disabled on Mac now due to |
22 // crbug.com/357501. | 26 // crbug.com/357501. |
23 const int kTimerResetIntervalSeconds = 1; | 27 const int kTimerResetIntervalSeconds = 1; |
24 // We have received reports that the timer can be too trigger happy on some | 28 // 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 | 29 // Mac devices and the initial timer interval has therefore been increased |
26 // from 1 second to 5 seconds. | 30 // from 1 second to 5 seconds. |
27 const int kTimerInitialIntervalSeconds = 5; | 31 const int kTimerInitialIntervalSeconds = 5; |
| 32 |
| 33 #if defined(AUDIO_POWER_MONITORING) |
| 34 // Time constant for AudioPowerMonitor. |
| 35 // The utilized smoothing factor (alpha) in the exponential filter is given |
| 36 // by 1-exp(-1/(fs*ts)), where fs is the sample rate in Hz and ts is the time |
| 37 // constant given by |kPowerMeasurementTimeConstantMilliseconds|. |
| 38 // Example: fs=44100, ts=10e-3 => alpha~0.022420 |
| 39 // fs=44100, ts=20e-3 => alpha~0.165903 |
| 40 // A large smoothing factor corresponds to a faster filter response to input |
| 41 // changes since y(n)=alpha*x(n)+(1-alpha)*y(n-1), where x(n) is the input |
| 42 // and y(n) is the output. |
| 43 const int kPowerMeasurementTimeConstantMilliseconds = 10; |
| 44 |
| 45 // Time in seconds between two successive measurements of audio power levels. |
| 46 const int kPowerMonitorLogIntervalSeconds = 5; |
| 47 #endif |
28 } | 48 } |
29 | 49 |
30 namespace media { | 50 namespace media { |
31 | 51 |
32 // static | 52 // static |
33 AudioInputController::Factory* AudioInputController::factory_ = NULL; | 53 AudioInputController::Factory* AudioInputController::factory_ = NULL; |
34 | 54 |
35 AudioInputController::AudioInputController(EventHandler* handler, | 55 AudioInputController::AudioInputController(EventHandler* handler, |
36 SyncWriter* sync_writer, | 56 SyncWriter* sync_writer, |
37 UserInputMonitor* user_input_monitor) | 57 UserInputMonitor* user_input_monitor) |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 void AudioInputController::SetAutomaticGainControl(bool enabled) { | 186 void AudioInputController::SetAutomaticGainControl(bool enabled) { |
167 task_runner_->PostTask(FROM_HERE, base::Bind( | 187 task_runner_->PostTask(FROM_HERE, base::Bind( |
168 &AudioInputController::DoSetAutomaticGainControl, this, enabled)); | 188 &AudioInputController::DoSetAutomaticGainControl, this, enabled)); |
169 } | 189 } |
170 | 190 |
171 void AudioInputController::DoCreate(AudioManager* audio_manager, | 191 void AudioInputController::DoCreate(AudioManager* audio_manager, |
172 const AudioParameters& params, | 192 const AudioParameters& params, |
173 const std::string& device_id) { | 193 const std::string& device_id) { |
174 DCHECK(task_runner_->BelongsToCurrentThread()); | 194 DCHECK(task_runner_->BelongsToCurrentThread()); |
175 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime"); | 195 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime"); |
| 196 |
| 197 #if defined(AUDIO_POWER_MONITORING) |
| 198 // Create the audio (power) level meter given the provided audio parameters. |
| 199 // An AudioBus is also needed to wrap the raw data buffer from the native |
| 200 // layer to match AudioPowerMonitor::Scan(). |
| 201 // TODO(henrika): Remove use of extra AudioBus. See http://crbug.com/375155. |
| 202 audio_level_.reset(new media::AudioPowerMonitor( |
| 203 params.sample_rate(), |
| 204 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMilliseconds))); |
| 205 audio_bus_ = AudioBus::Create(params); |
| 206 audio_params_ = params; |
| 207 #endif |
| 208 |
176 // TODO(miu): See TODO at top of file. Until that's resolved, assume all | 209 // 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 | 210 // 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 | 211 // errors. In reality, probably only Windows needs to be treated as |
179 // unreliable here. | 212 // unreliable here. |
180 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id), | 213 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id), |
181 true); | 214 true); |
182 } | 215 } |
183 | 216 |
184 void AudioInputController::DoCreateForStream( | 217 void AudioInputController::DoCreateForStream( |
185 AudioInputStream* stream_to_control, bool enable_nodata_timer) { | 218 AudioInputStream* stream_to_control, bool enable_nodata_timer) { |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 key_pressed = current_count != prev_key_down_count_; | 403 key_pressed = current_count != prev_key_down_count_; |
371 prev_key_down_count_ = current_count; | 404 prev_key_down_count_ = current_count; |
372 DVLOG_IF(6, key_pressed) << "Detected keypress."; | 405 DVLOG_IF(6, key_pressed) << "Detected keypress."; |
373 } | 406 } |
374 | 407 |
375 // Use SharedMemory and SyncSocket if the client has created a SyncWriter. | 408 // Use SharedMemory and SyncSocket if the client has created a SyncWriter. |
376 // Used by all low-latency clients except WebSpeech. | 409 // Used by all low-latency clients except WebSpeech. |
377 if (SharedMemoryAndSyncSocketMode()) { | 410 if (SharedMemoryAndSyncSocketMode()) { |
378 sync_writer_->Write(data, size, volume, key_pressed); | 411 sync_writer_->Write(data, size, volume, key_pressed); |
379 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); | 412 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); |
| 413 |
| 414 #if defined(AUDIO_POWER_MONITORING) |
| 415 // Only do power-level measurements if an AudioPowerMonitor object has |
| 416 // been created. Done in DoCreate() but not DoCreateForStream(), hence |
| 417 // logging will mainly be done for WebRTC and WebSpeech clients. |
| 418 if (!audio_level_) |
| 419 return; |
| 420 |
| 421 // Perform periodic audio (power) level measurements. |
| 422 if ((base::TimeTicks::Now() - last_audio_level_log_time_).InSeconds() > |
| 423 kPowerMonitorLogIntervalSeconds) { |
| 424 // Wrap data into an AudioBus to match AudioPowerMonitor::Scan. |
| 425 // TODO(henrika): remove this section when capture side uses AudioBus. |
| 426 // See http://crbug.com/375155 for details. |
| 427 audio_bus_->FromInterleaved( |
| 428 data, audio_bus_->frames(), audio_params_.bits_per_sample() / 8); |
| 429 audio_level_->Scan(*audio_bus_, audio_bus_->frames()); |
| 430 |
| 431 // Get current average power level and add it to the log. |
| 432 // Possible range is given by [-inf, 0] dBFS. |
| 433 std::pair<float, bool> result = audio_level_->ReadCurrentPowerAndClip(); |
| 434 |
| 435 // Use event handler on the audio thread to relay a message to the ARIH |
| 436 // in content which does the actual logging on the IO thread. |
| 437 task_runner_->PostTask( |
| 438 FROM_HERE, |
| 439 base::Bind( |
| 440 &AudioInputController::DoLogAudioLevel, this, result.first)); |
| 441 |
| 442 last_audio_level_log_time_ = base::TimeTicks::Now(); |
| 443 |
| 444 // Reset the average power level (since we don't log continuously). |
| 445 audio_level_->Reset(); |
| 446 } |
| 447 #endif |
| 448 |
380 return; | 449 return; |
381 } | 450 } |
382 | 451 |
383 // TODO(henrika): Investigate if we can avoid the extra copy here. | 452 // TODO(henrika): Investigate if we can avoid the extra copy here. |
384 // (see http://crbug.com/249316 for details). AFAIK, this scope is only | 453 // (see http://crbug.com/249316 for details). AFAIK, this scope is only |
385 // active for WebSpeech clients. | 454 // active for WebSpeech clients. |
386 scoped_ptr<uint8[]> audio_data(new uint8[size]); | 455 scoped_ptr<uint8[]> audio_data(new uint8[size]); |
387 memcpy(audio_data.get(), data, size); | 456 memcpy(audio_data.get(), data, size); |
388 | 457 |
389 // Ownership of the audio buffer will be with the callback until it is run, | 458 // Ownership of the audio buffer will be with the callback until it is run, |
390 // when ownership is passed to the callback function. | 459 // when ownership is passed to the callback function. |
391 task_runner_->PostTask(FROM_HERE, base::Bind( | 460 task_runner_->PostTask(FROM_HERE, base::Bind( |
392 &AudioInputController::DoOnData, this, base::Passed(&audio_data), size)); | 461 &AudioInputController::DoOnData, this, base::Passed(&audio_data), size)); |
393 } | 462 } |
394 | 463 |
395 void AudioInputController::DoOnData(scoped_ptr<uint8[]> data, uint32 size) { | 464 void AudioInputController::DoOnData(scoped_ptr<uint8[]> data, uint32 size) { |
396 DCHECK(task_runner_->BelongsToCurrentThread()); | 465 DCHECK(task_runner_->BelongsToCurrentThread()); |
397 if (handler_) | 466 if (handler_) |
398 handler_->OnData(this, data.get(), size); | 467 handler_->OnData(this, data.get(), size); |
399 } | 468 } |
400 | 469 |
| 470 void AudioInputController::DoLogAudioLevel(float level_dbfs) { |
| 471 #if defined(AUDIO_POWER_MONITORING) |
| 472 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 473 if (!handler_) |
| 474 return; |
| 475 |
| 476 std::string log_string = base::StringPrintf( |
| 477 "AIC::OnData: average audio level=%.2f dBFS", level_dbfs); |
| 478 static const float kSilenceThresholdDBFS = -72.24719896f; |
| 479 if (level_dbfs < kSilenceThresholdDBFS) |
| 480 log_string += " <=> no audio input!"; |
| 481 |
| 482 handler_->OnLog(this, log_string); |
| 483 #endif |
| 484 } |
| 485 |
401 void AudioInputController::OnError(AudioInputStream* stream) { | 486 void AudioInputController::OnError(AudioInputStream* stream) { |
402 // Handle error on the audio-manager thread. | 487 // Handle error on the audio-manager thread. |
403 task_runner_->PostTask(FROM_HERE, base::Bind( | 488 task_runner_->PostTask(FROM_HERE, base::Bind( |
404 &AudioInputController::DoReportError, this)); | 489 &AudioInputController::DoReportError, this)); |
405 } | 490 } |
406 | 491 |
407 void AudioInputController::DoStopCloseAndClearStream() { | 492 void AudioInputController::DoStopCloseAndClearStream() { |
408 DCHECK(task_runner_->BelongsToCurrentThread()); | 493 DCHECK(task_runner_->BelongsToCurrentThread()); |
409 | 494 |
410 // Allow calling unconditionally and bail if we don't have a stream to close. | 495 // Allow calling unconditionally and bail if we don't have a stream to close. |
411 if (stream_ != NULL) { | 496 if (stream_ != NULL) { |
412 stream_->Stop(); | 497 stream_->Stop(); |
413 stream_->Close(); | 498 stream_->Close(); |
414 stream_ = NULL; | 499 stream_ = NULL; |
415 } | 500 } |
416 | 501 |
417 // The event handler should not be touched after the stream has been closed. | 502 // The event handler should not be touched after the stream has been closed. |
418 handler_ = NULL; | 503 handler_ = NULL; |
419 } | 504 } |
420 | 505 |
421 void AudioInputController::SetDataIsActive(bool enabled) { | 506 void AudioInputController::SetDataIsActive(bool enabled) { |
422 base::subtle::Release_Store(&data_is_active_, enabled); | 507 base::subtle::Release_Store(&data_is_active_, enabled); |
423 } | 508 } |
424 | 509 |
425 bool AudioInputController::GetDataIsActive() { | 510 bool AudioInputController::GetDataIsActive() { |
426 return (base::subtle::Acquire_Load(&data_is_active_) != false); | 511 return (base::subtle::Acquire_Load(&data_is_active_) != false); |
427 } | 512 } |
428 | 513 |
429 } // namespace media | 514 } // namespace media |
OLD | NEW |