OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "content/browser/speech/speech_recognizer.h" | 5 #include "content/browser/speech/speech_recognizer.h" |
6 | 6 |
7 #include "base/time.h" | 7 #include "base/time.h" |
8 #include "chrome/browser/profiles/profile.h" | 8 #include "chrome/browser/profiles/profile.h" |
9 #include "chrome/common/net/url_request_context_getter.h" | 9 #include "chrome/common/net/url_request_context_getter.h" |
10 #include "content/browser/browser_thread.h" | 10 #include "content/browser/browser_thread.h" |
11 | 11 |
12 using media::AudioInputController; | 12 using media::AudioInputController; |
13 using std::string; | 13 using std::string; |
14 | 14 |
15 namespace { | 15 namespace { |
16 | 16 |
17 // The following constants are related to the volume level indicator shown in | 17 // The following constants are related to the volume level indicator shown in |
18 // the UI for recorded audio. | 18 // the UI for recorded audio. |
19 // Multiplier used when new volume is greater than previous level. | 19 // Multiplier used when new volume is greater than previous level. |
20 const float kUpSmoothingFactor = 0.9f; | 20 const float kUpSmoothingFactor = 1.0f; |
21 // Multiplier used when new volume is lesser than previous level. | 21 // Multiplier used when new volume is lesser than previous level. |
22 const float kDownSmoothingFactor = 0.4f; | 22 const float kDownSmoothingFactor = 0.7f; |
23 const float kAudioMeterMinDb = 10.0f; // Lower bar for volume meter. | 23 // RMS dB value of a maximum (unclipped) sine wave for int16 samples. |
24 const float kAudioMeterDbRange = 25.0f; | 24 const float kAudioMeterMaxDb = 90.31f; |
25 // This value corresponds to RMS dB for int16 with 6 most-significant-bits = 0. | |
26 // Values lower than this will display as empty level-meter. | |
27 const float kAudioMeterMinDb = 60.21f; | |
28 const float kAudioMeterDbRange = kAudioMeterMaxDb - kAudioMeterMinDb; | |
29 | |
30 // Maximum level to draw to display unclipped meter. (1.0f displays clipping.) | |
31 const float kAudioMeterRangeMaxUnclipped = 47.0f / 48.0f; | |
32 | |
33 // Returns true if more than 5% of the samples are at min or max value. | |
34 bool Clipping(const int16* samples, int num_samples) { | |
35 int clipping_samples = 0; | |
36 for (int i = 0; i < num_samples; ++i) { | |
37 if (samples[i] <= -32767 || samples[i] >= 32767) { | |
38 ++clipping_samples; | |
bulach
2011/03/01 17:39:04
you may want to short circuit rather than traverse
| |
39 } | |
40 } | |
41 return clipping_samples > (num_samples / 20); | |
42 } | |
43 | |
25 } // namespace | 44 } // namespace |
26 | 45 |
27 namespace speech_input { | 46 namespace speech_input { |
28 | 47 |
29 const int SpeechRecognizer::kAudioSampleRate = 16000; | 48 const int SpeechRecognizer::kAudioSampleRate = 16000; |
30 const int SpeechRecognizer::kAudioPacketIntervalMs = 100; | 49 const int SpeechRecognizer::kAudioPacketIntervalMs = 100; |
31 const int SpeechRecognizer::kNumAudioChannels = 1; | 50 const int SpeechRecognizer::kNumAudioChannels = 1; |
32 const int SpeechRecognizer::kNumBitsPerAudioSample = 16; | 51 const int SpeechRecognizer::kNumBitsPerAudioSample = 16; |
33 const int SpeechRecognizer::kNoSpeechTimeoutSec = 8; | 52 const int SpeechRecognizer::kNoSpeechTimeoutSec = 8; |
34 const int SpeechRecognizer::kEndpointerEstimationTimeMs = 300; | 53 const int SpeechRecognizer::kEndpointerEstimationTimeMs = 300; |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
213 | 232 |
214 // Check if we have waited too long without hearing any speech. | 233 // Check if we have waited too long without hearing any speech. |
215 if (!endpointer_.DidStartReceivingSpeech() && | 234 if (!endpointer_.DidStartReceivingSpeech() && |
216 num_samples_recorded_ >= kNoSpeechTimeoutSec * kAudioSampleRate) { | 235 num_samples_recorded_ >= kNoSpeechTimeoutSec * kAudioSampleRate) { |
217 InformErrorAndCancelRecognition(RECOGNIZER_ERROR_NO_SPEECH); | 236 InformErrorAndCancelRecognition(RECOGNIZER_ERROR_NO_SPEECH); |
218 return; | 237 return; |
219 } | 238 } |
220 | 239 |
221 // Calculate the input volume to display in the UI, smoothing towards the | 240 // Calculate the input volume to display in the UI, smoothing towards the |
222 // new level. | 241 // new level. |
223 float level = (rms - kAudioMeterMinDb) / kAudioMeterDbRange; | 242 float level = (rms - kAudioMeterMinDb) / |
224 level = std::min(std::max(0.0f, level), 1.0f); | 243 (kAudioMeterDbRange / kAudioMeterRangeMaxUnclipped); |
244 level = std::min(std::max(0.0f, level), kAudioMeterRangeMaxUnclipped); | |
225 if (level > audio_level_) { | 245 if (level > audio_level_) { |
226 audio_level_ += (level - audio_level_) * kUpSmoothingFactor; | 246 audio_level_ += (level - audio_level_) * kUpSmoothingFactor; |
227 } else { | 247 } else { |
228 audio_level_ += (level - audio_level_) * kDownSmoothingFactor; | 248 audio_level_ += (level - audio_level_) * kDownSmoothingFactor; |
229 } | 249 } |
230 delegate_->SetInputVolume(caller_id_, audio_level_); | 250 |
251 float noise_level = (endpointer_.NoiseLevelDB() - kAudioMeterMinDb) / | |
252 (kAudioMeterDbRange / kAudioMeterRangeMaxUnclipped); | |
253 noise_level = std::min(std::max(0.0f, noise_level), | |
254 kAudioMeterRangeMaxUnclipped); | |
255 | |
256 delegate_->SetInputVolume(caller_id_, | |
257 Clipping(samples, num_samples) ? 1.0f : audio_level_, noise_level); | |
231 | 258 |
232 if (endpointer_.speech_input_complete()) { | 259 if (endpointer_.speech_input_complete()) { |
233 StopRecording(); | 260 StopRecording(); |
234 } | 261 } |
235 | 262 |
236 // TODO(satish): Once we have streaming POST, start sending the data received | 263 // TODO(satish): Once we have streaming POST, start sending the data received |
237 // here as POST chunks. | 264 // here as POST chunks. |
238 } | 265 } |
239 | 266 |
240 void SpeechRecognizer::SetRecognitionResult( | 267 void SpeechRecognizer::SetRecognitionResult( |
(...skipping 12 matching lines...) Expand all Loading... | |
253 | 280 |
254 void SpeechRecognizer::InformErrorAndCancelRecognition(ErrorCode error) { | 281 void SpeechRecognizer::InformErrorAndCancelRecognition(ErrorCode error) { |
255 CancelRecognition(); | 282 CancelRecognition(); |
256 | 283 |
257 // Guard against the delegate freeing us until we finish our job. | 284 // Guard against the delegate freeing us until we finish our job. |
258 scoped_refptr<SpeechRecognizer> me(this); | 285 scoped_refptr<SpeechRecognizer> me(this); |
259 delegate_->OnRecognizerError(caller_id_, error); | 286 delegate_->OnRecognizerError(caller_id_, error); |
260 } | 287 } |
261 | 288 |
262 } // namespace speech_input | 289 } // namespace speech_input |
OLD | NEW |