summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-06 10:16:03 +0000
committertommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-06 10:16:03 +0000
commit1a32c8fca79780edaead58a8a0906aa42c373e0e (patch)
treee190bb894a466d8973ff4dc02f6f46bdbf600fc9
parent7ced1e5f9fbe5bf63b1b19fd9b42d6bfdccc1370 (diff)
downloadchromium_src-1a32c8fca79780edaead58a8a0906aa42c373e0e.zip
chromium_src-1a32c8fca79780edaead58a8a0906aa42c373e0e.tar.gz
chromium_src-1a32c8fca79780edaead58a8a0906aa42c373e0e.tar.bz2
Merge 272961 "Adds volume level measurements to the AudioInputCo..."
> Adds volume level measurements to the AudioInputController for low-latency clients > > BUG= > R=xians@chromium.org > > Review URL: https://codereview.chromium.org/287873004 TBR=henrika@chromium.org BUG=381070 Review URL: https://codereview.chromium.org/317363002 git-svn-id: svn://svn.chromium.org/chrome/branches/1985/src@275370 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/speech/speech_recognizer_impl.h2
-rw-r--r--media/audio/audio_input_controller.cc85
-rw-r--r--media/audio/audio_input_controller.h21
-rw-r--r--media/audio/audio_input_controller_unittest.cc3
4 files changed, 111 insertions, 0 deletions
diff --git a/content/browser/speech/speech_recognizer_impl.h b/content/browser/speech/speech_recognizer_impl.h
index 6c8a0932..abd3ab4 100644
--- a/content/browser/speech/speech_recognizer_impl.h
+++ b/content/browser/speech/speech_recognizer_impl.h
@@ -133,6 +133,8 @@ class CONTENT_EXPORT SpeechRecognizerImpl
media::AudioInputController::ErrorCode error_code) OVERRIDE;
virtual void OnData(media::AudioInputController* controller,
const uint8* data, uint32 size) OVERRIDE;
+ virtual void OnLog(media::AudioInputController* controller,
+ const std::string& message) OVERRIDE {}
// SpeechRecognitionEngineDelegate methods.
virtual void OnSpeechRecognitionEngineResults(
diff --git a/media/audio/audio_input_controller.cc b/media/audio/audio_input_controller.cc
index 4cf948b..ccd3062 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,22 @@ 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;
+
+#if defined(AUDIO_POWER_MONITORING)
+// 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;
+#endif
}
namespace media {
@@ -173,6 +193,19 @@ void AudioInputController::DoCreate(AudioManager* audio_manager,
const std::string& device_id) {
DCHECK(task_runner_->BelongsToCurrentThread());
SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime");
+
+#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
@@ -370,6 +403,42 @@ 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.
+ 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());
+
+ // 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();
+
+ // Use event handler on the audio thread to relay a message to the ARIH
+ // in content which does the actual logging on the IO thread.
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &AudioInputController::DoLogAudioLevel, this, result.first));
+
+ last_audio_level_log_time_ = base::TimeTicks::Now();
+
+ // Reset the average power level (since we don't log continuously).
+ audio_level_->Reset();
+ }
+#endif
+
return;
}
@@ -391,6 +460,22 @@ void AudioInputController::DoOnData(scoped_ptr<uint8[]> data, uint32 size) {
handler_->OnData(this, data.get(), size);
}
+void AudioInputController::DoLogAudioLevel(float level_dbfs) {
+#if defined(AUDIO_POWER_MONITORING)
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ if (!handler_)
+ return;
+
+ std::string log_string = base::StringPrintf(
+ "AIC::OnData: average audio level=%.2f dBFS", level_dbfs);
+ static const float kSilenceThresholdDBFS = -72.24719896f;
+ if (level_dbfs < kSilenceThresholdDBFS)
+ log_string += " <=> no audio input!";
+
+ handler_->OnLog(this, log_string);
+#endif
+}
+
void AudioInputController::OnError(AudioInputStream* stream) {
// Handle error on the audio-manager thread.
task_runner_->PostTask(FROM_HERE, base::Bind(
diff --git a/media/audio/audio_input_controller.h b/media/audio/audio_input_controller.h
index ac1a690..fba0e40 100644
--- a/media/audio/audio_input_controller.h
+++ b/media/audio/audio_input_controller.h
@@ -16,6 +16,9 @@
#include "base/timer/timer.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_manager_base.h"
+#include "media/audio/audio_parameters.h"
+#include "media/audio/audio_power_monitor.h"
+#include "media/base/audio_bus.h"
// An AudioInputController controls an AudioInputStream and records data
// from this input stream. The two main methods are Record() and Close() and
@@ -72,6 +75,11 @@
//
namespace media {
+// Only do power monitoring for non-mobile platforms to save resources.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#define AUDIO_POWER_MONITORING
+#endif
+
class UserInputMonitor;
class MEDIA_EXPORT AudioInputController
@@ -111,6 +119,8 @@ class MEDIA_EXPORT AudioInputController
ErrorCode error_code) = 0;
virtual void OnData(AudioInputController* controller, const uint8* data,
uint32 size) = 0;
+ virtual void OnLog(AudioInputController* controller,
+ const std::string& message) = 0;
protected:
virtual ~EventHandler() {}
@@ -252,6 +262,7 @@ class MEDIA_EXPORT AudioInputController
void DoSetVolume(double volume);
void DoSetAutomaticGainControl(bool enabled);
void DoOnData(scoped_ptr<uint8[]> data, uint32 size);
+ void DoLogAudioLevel(float level_dbfs);
// Method which ensures that OnError() is triggered when data recording
// times out. Called on the audio thread.
@@ -305,6 +316,16 @@ class MEDIA_EXPORT AudioInputController
UserInputMonitor* user_input_monitor_;
+#if defined(AUDIO_POWER_MONITORING)
+ // Scans audio samples from OnData() as input to compute audio levels.
+ scoped_ptr<AudioPowerMonitor> audio_level_;
+
+ // We need these to be able to feed data to the AudioPowerMonitor.
+ scoped_ptr<AudioBus> audio_bus_;
+ media::AudioParameters audio_params_;
+ base::TimeTicks last_audio_level_log_time_;
+#endif
+
size_t prev_key_down_count_;
DISALLOW_COPY_AND_ASSIGN(AudioInputController);
diff --git a/media/audio/audio_input_controller_unittest.cc b/media/audio/audio_input_controller_unittest.cc
index f101835..4e11e35 100644
--- a/media/audio/audio_input_controller_unittest.cc
+++ b/media/audio/audio_input_controller_unittest.cc
@@ -55,6 +55,9 @@ class MockAudioInputControllerEventHandler
AudioInputController::ErrorCode error_code));
MOCK_METHOD3(OnData, void(AudioInputController* controller,
const uint8* data, uint32 size));
+ MOCK_METHOD2(OnLog,
+ void(AudioInputController* controller,
+ const std::string& message));
private:
DISALLOW_COPY_AND_ASSIGN(MockAudioInputControllerEventHandler);