summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorsatish@chromium.org <satish@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-01 18:38:36 +0000
committersatish@chromium.org <satish@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-01 18:38:36 +0000
commit3b283d6e8c6285efde6a1a34273a3bdb9061bd44 (patch)
tree9c221cc4d11dacf4f20e9c05287fde698d6721c6 /content
parent229fa74de71e0771f734cc788063515da62f30b4 (diff)
downloadchromium_src-3b283d6e8c6285efde6a1a34273a3bdb9061bd44.zip
chromium_src-3b283d6e8c6285efde6a1a34273a3bdb9061bd44.tar.gz
chromium_src-3b283d6e8c6285efde6a1a34273a3bdb9061bd44.tar.bz2
Add a noise indicator to the speech bubble volume indicator.
The noise indicator is drawn as a light blue area at the beginning and if there was clipping that is denoted with a red area at the end of the meter. The noise level comes from the endpointer -> SpeechRecognizer -> SpeechInputBubbleController -> SpeechInputBubble hence a bunch of volume setting methods are updated with the new parameter. I have also added a new utility method to SpeechInputManager to invoke the platform provided microphone settings UI, this will be used in the next CL which contains windows, mac and linux specific UI changes. BUG=69886 TEST=manual, invoke speech input and check the bubble volume indicator to see background noise and clipping. Review URL: http://codereview.chromium.org/6597071 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@76395 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/browser/speech/endpointer/endpointer.h3
-rw-r--r--content/browser/speech/endpointer/energy_endpointer.cc18
-rw-r--r--content/browser/speech/endpointer/energy_endpointer.h3
-rw-r--r--content/browser/speech/speech_input_manager.h4
-rw-r--r--content/browser/speech/speech_recognizer.cc43
-rw-r--r--content/browser/speech/speech_recognizer.h5
-rw-r--r--content/browser/speech/speech_recognizer_unittest.cc19
7 files changed, 78 insertions, 17 deletions
diff --git a/content/browser/speech/endpointer/endpointer.h b/content/browser/speech/endpointer/endpointer.h
index be4bd65..c8cf80a 100644
--- a/content/browser/speech/endpointer/endpointer.h
+++ b/content/browser/speech/endpointer/endpointer.h
@@ -96,6 +96,9 @@ class Endpointer {
return speech_input_complete_;
}
+ // RMS background noise level in dB.
+ float NoiseLevelDb() const { return energy_endpointer_.GetNoiseLevelDb(); }
+
private:
// Reset internal states. Helper method common to initial input utterance
// and following input utternaces.
diff --git a/content/browser/speech/endpointer/energy_endpointer.cc b/content/browser/speech/endpointer/energy_endpointer.cc
index c806aed..edf3edd 100644
--- a/content/browser/speech/endpointer/energy_endpointer.cc
+++ b/content/browser/speech/endpointer/energy_endpointer.cc
@@ -33,6 +33,13 @@ int64 Secs2Usecs(float seconds) {
return static_cast<int64>(0.5 + (1.0e6 * seconds));
}
+float GetDecibel(float value) {
+ const float kVerySmallValue = 1.0e-100f;
+ if (value < kVerySmallValue)
+ value = kVerySmallValue;
+ return 20 * log10(value);
+}
+
} // namespace
namespace speech_input {
@@ -326,11 +333,12 @@ void EnergyEndpointer::ProcessAudioFrame(int64 time_us,
UpdateLevels(rms);
++frame_counter_;
- if (rms_out) {
- *rms_out = -120.0;
- if ((noise_level_ > 0.0) && ((rms / noise_level_ ) > 0.000001))
- *rms_out = static_cast<float>(20.0 * log10(rms / noise_level_));
- }
+ if (rms_out)
+ *rms_out = GetDecibel(rms);
+}
+
+float EnergyEndpointer::GetNoiseLevelDb() const {
+ return GetDecibel(noise_level_);
}
void EnergyEndpointer::UpdateLevels(float rms) {
diff --git a/content/browser/speech/endpointer/energy_endpointer.h b/content/browser/speech/endpointer/energy_endpointer.h
index b10d8b7..77ccc55 100644
--- a/content/browser/speech/endpointer/energy_endpointer.h
+++ b/content/browser/speech/endpointer/energy_endpointer.h
@@ -91,6 +91,9 @@ class EnergyEndpointer {
return estimating_environment_;
}
+ // Returns estimated noise level in dB.
+ float GetNoiseLevelDb() const;
+
private:
class HistoryRing;
diff --git a/content/browser/speech/speech_input_manager.h b/content/browser/speech/speech_input_manager.h
index a6ba61f..9415910 100644
--- a/content/browser/speech/speech_input_manager.h
+++ b/content/browser/speech/speech_input_manager.h
@@ -35,6 +35,10 @@ class SpeechInputManager {
// information and command line flags.
static bool IsFeatureEnabled();
+ // Invokes the platform provided microphone settings UI in a non-blocking way,
+ // via the BrowserThread::PROCESS_LAUNCHER thread.
+ static void ShowAudioInputSettings();
+
// Factory method to access the singleton. We have this method here instead of
// using Singleton directly in the calling code to aid tests in injection
// mocks.
diff --git a/content/browser/speech/speech_recognizer.cc b/content/browser/speech/speech_recognizer.cc
index fdc1a4c..b23f4b0 100644
--- a/content/browser/speech/speech_recognizer.cc
+++ b/content/browser/speech/speech_recognizer.cc
@@ -17,11 +17,32 @@ namespace {
// The following constants are related to the volume level indicator shown in
// the UI for recorded audio.
// Multiplier used when new volume is greater than previous level.
-const float kUpSmoothingFactor = 0.9f;
+const float kUpSmoothingFactor = 1.0f;
// Multiplier used when new volume is lesser than previous level.
-const float kDownSmoothingFactor = 0.4f;
-const float kAudioMeterMinDb = 10.0f; // Lower bar for volume meter.
-const float kAudioMeterDbRange = 25.0f;
+const float kDownSmoothingFactor = 0.7f;
+// RMS dB value of a maximum (unclipped) sine wave for int16 samples.
+const float kAudioMeterMaxDb = 90.31f;
+// This value corresponds to RMS dB for int16 with 6 most-significant-bits = 0.
+// Values lower than this will display as empty level-meter.
+const float kAudioMeterMinDb = 60.21f;
+const float kAudioMeterDbRange = kAudioMeterMaxDb - kAudioMeterMinDb;
+
+// Maximum level to draw to display unclipped meter. (1.0f displays clipping.)
+const float kAudioMeterRangeMaxUnclipped = 47.0f / 48.0f;
+
+// Returns true if more than 5% of the samples are at min or max value.
+bool Clipping(const int16* samples, int num_samples) {
+ int clipping_samples = 0;
+ const int kThreshold = num_samples / 20;
+ for (int i = 0; i < num_samples; ++i) {
+ if (samples[i] <= -32767 || samples[i] >= 32767) {
+ if (++clipping_samples > kThreshold)
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace
namespace speech_input {
@@ -220,14 +241,22 @@ void SpeechRecognizer::HandleOnData(string* data) {
// Calculate the input volume to display in the UI, smoothing towards the
// new level.
- float level = (rms - kAudioMeterMinDb) / kAudioMeterDbRange;
- level = std::min(std::max(0.0f, level), 1.0f);
+ float level = (rms - kAudioMeterMinDb) /
+ (kAudioMeterDbRange / kAudioMeterRangeMaxUnclipped);
+ level = std::min(std::max(0.0f, level), kAudioMeterRangeMaxUnclipped);
if (level > audio_level_) {
audio_level_ += (level - audio_level_) * kUpSmoothingFactor;
} else {
audio_level_ += (level - audio_level_) * kDownSmoothingFactor;
}
- delegate_->SetInputVolume(caller_id_, audio_level_);
+
+ float noise_level = (endpointer_.NoiseLevelDb() - kAudioMeterMinDb) /
+ (kAudioMeterDbRange / kAudioMeterRangeMaxUnclipped);
+ noise_level = std::min(std::max(0.0f, noise_level),
+ kAudioMeterRangeMaxUnclipped);
+
+ delegate_->SetInputVolume(caller_id_,
+ Clipping(samples, num_samples) ? 1.0f : audio_level_, noise_level);
if (endpointer_.speech_input_complete()) {
StopRecording();
diff --git a/content/browser/speech/speech_recognizer.h b/content/browser/speech/speech_recognizer.h
index a54a59d..f8df0c2 100644
--- a/content/browser/speech/speech_recognizer.h
+++ b/content/browser/speech/speech_recognizer.h
@@ -65,8 +65,9 @@ class SpeechRecognizer
// Informs of a change in the captured audio level, useful if displaying
// a microphone volume indicator while recording.
- // The value of |volume| is in the [0.0, 1.0] range.
- virtual void SetInputVolume(int caller_id, float volume) = 0;
+ // The value of |volume| and |noise_volume| is in the [0.0, 1.0] range.
+ virtual void SetInputVolume(int caller_id, float volume,
+ float noise_volume) = 0;
protected:
virtual ~Delegate() {}
diff --git a/content/browser/speech/speech_recognizer_unittest.cc b/content/browser/speech/speech_recognizer_unittest.cc
index 8365396..4b16259 100644
--- a/content/browser/speech/speech_recognizer_unittest.cc
+++ b/content/browser/speech/speech_recognizer_unittest.cc
@@ -62,8 +62,9 @@ class SpeechRecognizerTest : public SpeechRecognizerDelegate,
error_ = error;
}
- virtual void SetInputVolume(int caller_id, float volume) {
+ virtual void SetInputVolume(int caller_id, float volume, float noise_volume) {
volume_ = volume;
+ noise_volume_ = noise_volume;
}
// testing::Test methods.
@@ -83,6 +84,15 @@ class SpeechRecognizerTest : public SpeechRecognizerDelegate,
audio_packet_[i] = static_cast<uint8>(i);
}
+ void FillPacketWithNoise() {
+ int value = 0;
+ int factor = 175;
+ for (size_t i = 0; i < audio_packet_.size(); ++i) {
+ value += factor;
+ audio_packet_[i] = value % 100;
+ }
+ }
+
protected:
MessageLoopForIO message_loop_;
BrowserThread io_thread_;
@@ -95,6 +105,7 @@ class SpeechRecognizerTest : public SpeechRecognizerDelegate,
TestAudioInputControllerFactory audio_input_controller_factory_;
std::vector<uint8> audio_packet_;
float volume_;
+ float noise_volume_;
};
TEST_F(SpeechRecognizerTest, StopNoData) {
@@ -272,6 +283,7 @@ TEST_F(SpeechRecognizerTest, SetInputVolumeCallback) {
// Feed some samples to begin with for the endpointer to do noise estimation.
int num_packets = SpeechRecognizer::kEndpointerEstimationTimeMs /
SpeechRecognizer::kAudioPacketIntervalMs;
+ FillPacketWithNoise();
for (int i = 0; i < num_packets; ++i) {
controller->event_handler()->OnData(controller, &audio_packet_[0],
audio_packet_.size());
@@ -283,13 +295,14 @@ TEST_F(SpeechRecognizerTest, SetInputVolumeCallback) {
controller->event_handler()->OnData(controller, &audio_packet_[0],
audio_packet_.size());
MessageLoop::current()->RunAllPending();
- EXPECT_EQ(0, volume_);
+ EXPECT_FLOAT_EQ(0.51877826f, volume_);
FillPacketWithTestWaveform();
controller->event_handler()->OnData(controller, &audio_packet_[0],
audio_packet_.size());
MessageLoop::current()->RunAllPending();
- EXPECT_FLOAT_EQ(0.9f, volume_);
+ EXPECT_FLOAT_EQ(0.81907868f, volume_);
+ EXPECT_FLOAT_EQ(0.52143687f, noise_volume_);
EXPECT_EQ(SpeechRecognizer::RECOGNIZER_NO_ERROR, error_);
EXPECT_FALSE(recording_complete_);