Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(426)

Unified Diff: media/audio/audio_input_controller.cc

Issue 287873004: Adds volume level measurements to the AudioInputController for low-latency clients (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removed dependency of content in media Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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(
« media/audio/audio_input_controller.h ('K') | « media/audio/audio_input_controller.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698