Index: media/audio/audio_input_controller.cc |
diff --git a/media/audio/audio_input_controller.cc b/media/audio/audio_input_controller.cc |
index 3bdec149bfc3c3605bdb7234edf522199fedb783..c9287449a5db10f54d1fbd56ff93294f9027fa16 100644 |
--- a/media/audio/audio_input_controller.cc |
+++ b/media/audio/audio_input_controller.cc |
@@ -5,11 +5,15 @@ |
#include "media/audio/audio_input_controller.h" |
#include "base/bind.h" |
+#include "base/strings/stringprintf.h" |
#include "base/threading/thread_restrictions.h" |
+#include "base/time/time.h" |
#include "media/base/limits.h" |
#include "media/base/scoped_histogram_timer.h" |
#include "media/base/user_input_monitor.h" |
+using base::TimeDelta; |
+ |
namespace { |
const int kMaxInputChannels = 3; |
@@ -25,6 +29,20 @@ const int kTimerResetIntervalSeconds = 1; |
// Mac devices and the initial timer interval has therefore been increased |
// from 1 second to 5 seconds. |
const int kTimerInitialIntervalSeconds = 5; |
+ |
+// Time constant for AudioPowerMonitor. |
+// The utilized smoothing factor (alpha) in the exponential filter is given |
+// by 1-exp(-1/(fs*ts)), where fs is the sample rate in Hz and ts is the time |
+// constant given by |kPowerMeasurementTimeConstantMilliseconds|. |
+// Example: fs=44100, ts=10e-3 => alpha~0.022420 |
+// fs=44100, ts=20e-3 => alpha~0.165903 |
+// A large smoothing factor corresponds to a faster filter response to input |
+// changes since y(n)=alpha*x(n)+(1-alpha)*y(n-1), where x(n) is the input |
+// and y(n) is the output. |
+const int kPowerMeasurementTimeConstantMilliseconds = 10; |
+ |
+// Time in seconds between two successive measurements of audio power levels. |
+const int kPowerMonitorLogIntervalSeconds = 5; |
} |
namespace media { |
@@ -59,6 +77,7 @@ scoped_refptr<AudioInputController> AudioInputController::Create( |
const std::string& device_id, |
UserInputMonitor* user_input_monitor) { |
DCHECK(audio_manager); |
+ DVLOG(1) << "AudioInputController::Create"; |
if (!params.IsValid() || (params.channels() > kMaxInputChannels)) |
return NULL; |
@@ -93,6 +112,7 @@ scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( |
UserInputMonitor* user_input_monitor) { |
DCHECK(audio_manager); |
DCHECK(sync_writer); |
+ DVLOG(1) << "AudioInputController::CreateLowLatency"; |
if (!params.IsValid() || (params.channels() > kMaxInputChannels)) |
return NULL; |
@@ -173,6 +193,20 @@ void AudioInputController::DoCreate(AudioManager* audio_manager, |
const std::string& device_id) { |
DCHECK(task_runner_->BelongsToCurrentThread()); |
SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime"); |
+ DVLOG(1) << "AudioInputController::DoCreate"; |
+ |
+#if defined(AUDIO_POWER_MONITORING) |
+ // Create the audio (power) level meter given the provided audio parameters. |
+ // An AudioBus is also needed to wrap the raw data buffer from the native |
+ // layer to match AudioPowerMonitor::Scan(). |
+ // TODO(henrika): Remove use of extra AudioBus. See http://crbug.com/375155. |
+ audio_level_.reset(new media::AudioPowerMonitor( |
+ params.sample_rate(), |
+ TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMilliseconds))); |
+ audio_bus_ = AudioBus::Create(params); |
+ audio_params_ = params; |
+#endif |
+ |
// TODO(miu): See TODO at top of file. Until that's resolved, assume all |
// platform audio input requires the |no_data_timer_| be used to auto-detect |
// errors. In reality, probably only Windows needs to be treated as |
@@ -266,6 +300,14 @@ void AudioInputController::DoClose() { |
// Delete the timer on the same thread that created it. |
no_data_timer_.reset(); |
+#if defined(AUDIO_POWER_MONITORING) |
+ std::string log_string("AIC::DoClose: closing input stream"); |
no longer working on chromium
2014/05/26 14:20:16
nit, const
henrika (OOO until Aug 14)
2014/05/26 15:01:17
Removed.
|
+ if (handler_) |
+ handler_->OnLog(this, log_string); |
+ if (audio_level_) |
+ audio_level_->Reset(); |
+#endif |
+ |
DoStopCloseAndClearStream(); |
SetDataIsActive(false); |
@@ -377,6 +419,34 @@ void AudioInputController::OnData(AudioInputStream* stream, |
if (SharedMemoryAndSyncSocketMode()) { |
sync_writer_->Write(data, size, volume, key_pressed); |
sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); |
+ |
+#if defined(AUDIO_POWER_MONITORING) |
+ { |
+ // Only do power-level measurements if an AudioPowerMonitor object has |
+ // been created. Done in DoCreate() but not DoCreateForStream(), hence |
+ // logging will mainly be done for WebRTC and WebSpeech clients. |
+ base::AutoLock auto_lock(lock_); |
+ if (!audio_level_) |
+ return; |
+ } |
+ |
+ // Perform periodic audio (power) level measurements. |
+ if ((base::TimeTicks::Now() - last_audio_level_log_time_).InSeconds() > |
+ kPowerMonitorLogIntervalSeconds) { |
+ // Wrap data into an AudioBus to match AudioPowerMonitor::Scan. |
+ // TODO(henrika): remove this section when capture side uses AudioBus. |
+ // See http://crbug.com/375155 for details. |
+ audio_bus_->FromInterleaved( |
+ data, audio_bus_->frames(), audio_params_.bits_per_sample() / 8); |
+ audio_level_->Scan(*audio_bus_, audio_bus_->frames()); |
+ |
+ task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&AudioInputController::DoLogAudioLevel, this)); |
+ |
+ last_audio_level_log_time_ = base::TimeTicks::Now(); |
+ } |
+#endif |
+ |
return; |
} |
@@ -398,6 +468,24 @@ void AudioInputController::DoOnData(scoped_ptr<uint8[]> data, uint32 size) { |
handler_->OnData(this, data.get(), size); |
} |
+void AudioInputController::DoLogAudioLevel() { |
+ DCHECK(task_runner_->BelongsToCurrentThread()); |
+ |
+ // Get current average power level and add it to the log. |
+ // Possible range is given by [-inf, 0] dBFS. |
+ std::pair<float, bool> result = audio_level_->ReadCurrentPowerAndClip(); |
no longer working on chromium
2014/05/26 14:20:16
this introduces a race here. audio_level_ is chang
henrika (OOO until Aug 14)
2014/05/26 15:01:17
Will fix.
|
+ std::string log_string = base::StringPrintf( |
+ "AIC::OnData: average audio level=%.2f dBFS", result.first); |
+ static const float kSilenceThresholdDBFS = -72.24719896f; |
+ if (result.first < kSilenceThresholdDBFS) |
+ log_string += " <=> no audio input!"; |
+ if (handler_) |
+ handler_->OnLog(this, log_string); |
+ |
+ // Reset the average power level (since we don't log continuously). |
+ audio_level_->Reset(); |
+} |
+ |
void AudioInputController::OnError(AudioInputStream* stream) { |
// Handle error on the audio-manager thread. |
task_runner_->PostTask(FROM_HERE, base::Bind( |