| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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_impl.h" | 5 #include "content/browser/speech/speech_recognizer_impl.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/memory/shared_memory.h" |
| 10 #include "base/threading/thread.h" |
| 11 #include "base/threading/thread_restrictions.h" |
| 9 #include "base/time/time.h" | 12 #include "base/time/time.h" |
| 10 #include "content/browser/browser_main_loop.h" | 13 #include "content/browser/browser_main_loop.h" |
| 11 #include "content/browser/media/media_internals.h" | 14 #include "content/browser/media/media_internals.h" |
| 12 #include "content/browser/speech/audio_buffer.h" | 15 #include "content/browser/speech/audio_buffer.h" |
| 13 #include "content/browser/speech/google_one_shot_remote_engine.h" | 16 #include "content/browser/speech/google_one_shot_remote_engine.h" |
| 17 #include "content/browser/speech/speech_recognition_audio_receiver.h" |
| 18 #include "content/public/browser/browser_message_filter.h" |
| 14 #include "content/public/browser/speech_recognition_event_listener.h" | 19 #include "content/public/browser/speech_recognition_event_listener.h" |
| 15 #include "media/base/audio_converter.h" | 20 #include "media/base/audio_converter.h" |
| 16 #include "net/url_request/url_request_context_getter.h" | 21 #include "net/url_request/url_request_context_getter.h" |
| 17 | 22 |
| 18 #if defined(OS_WIN) | 23 #if defined(OS_WIN) |
| 19 #include "media/audio/win/core_audio_util_win.h" | 24 #include "media/audio/win/core_audio_util_win.h" |
| 20 #endif | 25 #endif |
| 21 | 26 |
| 22 using media::AudioBus; | 27 using media::AudioBus; |
| 23 using media::AudioConverter; | 28 using media::AudioConverter; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 34 class SpeechRecognizerImpl::OnDataConverter | 39 class SpeechRecognizerImpl::OnDataConverter |
| 35 : public media::AudioConverter::InputCallback { | 40 : public media::AudioConverter::InputCallback { |
| 36 public: | 41 public: |
| 37 OnDataConverter(const AudioParameters& input_params, | 42 OnDataConverter(const AudioParameters& input_params, |
| 38 const AudioParameters& output_params); | 43 const AudioParameters& output_params); |
| 39 ~OnDataConverter() override; | 44 ~OnDataConverter() override; |
| 40 | 45 |
| 41 // Converts input audio |data| bus into an AudioChunk where the input format | 46 // Converts input audio |data| bus into an AudioChunk where the input format |
| 42 // is given by |input_parameters_| and the output format by | 47 // is given by |input_parameters_| and the output format by |
| 43 // |output_parameters_|. | 48 // |output_parameters_|. |
| 49 // Skips conversion on |audio_converter_| when input and output formats match. |
| 44 scoped_refptr<AudioChunk> Convert(const AudioBus* data); | 50 scoped_refptr<AudioChunk> Convert(const AudioBus* data); |
| 45 | 51 |
| 46 private: | 52 private: |
| 47 // media::AudioConverter::InputCallback implementation. | 53 // media::AudioConverter::InputCallback implementation. |
| 48 double ProvideInput(AudioBus* dest, base::TimeDelta buffer_delay) override; | 54 double ProvideInput(AudioBus* dest, base::TimeDelta buffer_delay) override; |
| 49 | 55 |
| 50 // Handles resampling, buffering, and channel mixing between input and output | 56 // Handles resampling, buffering, and channel mixing between input and output |
| 51 // parameters. | 57 // parameters. |
| 52 AudioConverter audio_converter_; | 58 scoped_ptr<AudioConverter> audio_converter_; |
| 53 | 59 |
| 54 scoped_ptr<AudioBus> input_bus_; | 60 scoped_ptr<AudioBus> input_bus_; |
| 55 scoped_ptr<AudioBus> output_bus_; | 61 scoped_ptr<AudioBus> output_bus_; |
| 56 const AudioParameters input_parameters_; | 62 const AudioParameters input_parameters_; |
| 57 const AudioParameters output_parameters_; | 63 const AudioParameters output_parameters_; |
| 58 bool waiting_for_input_; | 64 bool waiting_for_input_; |
| 65 bool need_conversion_; |
| 59 scoped_ptr<uint8[]> converted_data_; | 66 scoped_ptr<uint8[]> converted_data_; |
| 60 | 67 |
| 61 DISALLOW_COPY_AND_ASSIGN(OnDataConverter); | 68 DISALLOW_COPY_AND_ASSIGN(OnDataConverter); |
| 62 }; | 69 }; |
| 63 | 70 |
| 64 namespace { | 71 namespace { |
| 65 | 72 |
| 66 // The following constants are related to the volume level indicator shown in | 73 // The following constants are related to the volume level indicator shown in |
| 67 // the UI for recorded audio. | 74 // the UI for recorded audio. |
| 68 // Multiplier used when new volume is greater than previous level. | 75 // Multiplier used when new volume is greater than previous level. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 const int SpeechRecognizerImpl::kEndpointerEstimationTimeMs = 300; | 115 const int SpeechRecognizerImpl::kEndpointerEstimationTimeMs = 300; |
| 109 media::AudioManager* SpeechRecognizerImpl::audio_manager_for_tests_ = NULL; | 116 media::AudioManager* SpeechRecognizerImpl::audio_manager_for_tests_ = NULL; |
| 110 | 117 |
| 111 COMPILE_ASSERT(SpeechRecognizerImpl::kNumBitsPerAudioSample % 8 == 0, | 118 COMPILE_ASSERT(SpeechRecognizerImpl::kNumBitsPerAudioSample % 8 == 0, |
| 112 kNumBitsPerAudioSample_must_be_a_multiple_of_8); | 119 kNumBitsPerAudioSample_must_be_a_multiple_of_8); |
| 113 | 120 |
| 114 // SpeechRecognizerImpl::OnDataConverter implementation | 121 // SpeechRecognizerImpl::OnDataConverter implementation |
| 115 | 122 |
| 116 SpeechRecognizerImpl::OnDataConverter::OnDataConverter( | 123 SpeechRecognizerImpl::OnDataConverter::OnDataConverter( |
| 117 const AudioParameters& input_params, const AudioParameters& output_params) | 124 const AudioParameters& input_params, const AudioParameters& output_params) |
| 118 : audio_converter_(input_params, output_params, false), | 125 : input_bus_(AudioBus::Create(input_params)), |
| 119 input_bus_(AudioBus::Create(input_params)), | |
| 120 output_bus_(AudioBus::Create(output_params)), | 126 output_bus_(AudioBus::Create(output_params)), |
| 121 input_parameters_(input_params), | 127 input_parameters_(input_params), |
| 122 output_parameters_(output_params), | 128 output_parameters_(output_params), |
| 123 waiting_for_input_(false), | 129 waiting_for_input_(false), |
| 124 converted_data_(new uint8[output_parameters_.GetBytesPerBuffer()]) { | 130 converted_data_(new uint8[output_parameters_.GetBytesPerBuffer()]) { |
| 125 audio_converter_.AddInput(this); | 131 if (!input_parameters_.Equals(output_parameters_)) { |
| 132 audio_converter_.reset(new AudioConverter(input_params, |
| 133 output_params, |
| 134 false)); |
| 135 audio_converter_->AddInput(this); |
| 136 } |
| 126 } | 137 } |
| 127 | 138 |
| 128 SpeechRecognizerImpl::OnDataConverter::~OnDataConverter() { | 139 SpeechRecognizerImpl::OnDataConverter::~OnDataConverter() { |
| 129 // It should now be safe to unregister the converter since no more OnData() | 140 // It should now be safe to unregister the converter since no more OnData() |
| 130 // callbacks are outstanding at this point. | 141 // callbacks are outstanding at this point. |
| 131 audio_converter_.RemoveInput(this); | 142 if (audio_converter_.get()) |
| 143 audio_converter_->RemoveInput(this); |
| 132 } | 144 } |
| 133 | 145 |
| 134 scoped_refptr<AudioChunk> SpeechRecognizerImpl::OnDataConverter::Convert( | 146 scoped_refptr<AudioChunk> SpeechRecognizerImpl::OnDataConverter::Convert( |
| 135 const AudioBus* data) { | 147 const AudioBus* data) { |
| 136 CHECK_EQ(data->frames(), input_parameters_.frames_per_buffer()); | 148 CHECK_EQ(data->frames(), input_parameters_.frames_per_buffer()); |
| 137 | 149 |
| 138 data->CopyTo(input_bus_.get()); | 150 // Do conversion if needed - only when |input_parameters_| differ from |
| 139 | 151 // |output_parameters_|. |
| 140 waiting_for_input_ = true; | 152 if (audio_converter_.get()) { |
| 141 audio_converter_.Convert(output_bus_.get()); | 153 data->CopyTo(input_bus_.get()); |
| 154 waiting_for_input_ = true; |
| 155 audio_converter_->Convert(output_bus_.get()); |
| 156 } else { |
| 157 data->CopyTo(output_bus_.get()); |
| 158 } |
| 142 | 159 |
| 143 output_bus_->ToInterleaved( | 160 output_bus_->ToInterleaved( |
| 144 output_bus_->frames(), output_parameters_.bits_per_sample() / 8, | 161 output_bus_->frames(), output_parameters_.bits_per_sample() / 8, |
| 145 converted_data_.get()); | 162 converted_data_.get()); |
| 146 | 163 |
| 147 // TODO(primiano): Refactor AudioChunk to avoid the extra-copy here | 164 // TODO(primiano): Refactor AudioChunk to avoid the extra-copy here |
| 148 // (see http://crbug.com/249316 for details). | 165 // (see http://crbug.com/249316 for details). |
| 149 return scoped_refptr<AudioChunk>(new AudioChunk( | 166 return scoped_refptr<AudioChunk>(new AudioChunk( |
| 150 converted_data_.get(), | 167 converted_data_.get(), |
| 151 output_parameters_.GetBytesPerBuffer(), | 168 output_parameters_.GetBytesPerBuffer(), |
| (...skipping 15 matching lines...) Expand all Loading... |
| 167 return 1; | 184 return 1; |
| 168 } | 185 } |
| 169 | 186 |
| 170 // SpeechRecognizerImpl implementation | 187 // SpeechRecognizerImpl implementation |
| 171 | 188 |
| 172 SpeechRecognizerImpl::SpeechRecognizerImpl( | 189 SpeechRecognizerImpl::SpeechRecognizerImpl( |
| 173 SpeechRecognitionEventListener* listener, | 190 SpeechRecognitionEventListener* listener, |
| 174 int session_id, | 191 int session_id, |
| 175 bool continuous, | 192 bool continuous, |
| 176 bool provisional_results, | 193 bool provisional_results, |
| 194 bool using_audio_receiver, |
| 195 const base::ProcessHandle peer_process_handle, |
| 177 SpeechRecognitionEngine* engine) | 196 SpeechRecognitionEngine* engine) |
| 178 : SpeechRecognizer(listener, session_id), | 197 : SpeechRecognizer(listener, session_id), |
| 179 recognition_engine_(engine), | 198 recognition_engine_(engine), |
| 180 endpointer_(kAudioSampleRate), | 199 endpointer_(kAudioSampleRate), |
| 181 audio_log_(MediaInternals::GetInstance()->CreateAudioLog( | 200 audio_log_(MediaInternals::GetInstance()->CreateAudioLog( |
| 182 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)), | 201 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)), |
| 183 is_dispatching_event_(false), | 202 is_dispatching_event_(false), |
| 184 provisional_results_(provisional_results), | 203 provisional_results_(provisional_results), |
| 204 using_audio_receiver_(using_audio_receiver), |
| 205 peer_process_handle_(peer_process_handle), |
| 185 state_(STATE_IDLE) { | 206 state_(STATE_IDLE) { |
| 186 DCHECK(recognition_engine_ != NULL); | 207 DCHECK(recognition_engine_ != NULL); |
| 187 if (!continuous) { | 208 if (!continuous) { |
| 188 // In single shot (non-continous) recognition, | 209 // In single shot (non-continous) recognition, |
| 189 // the session is automatically ended after: | 210 // the session is automatically ended after: |
| 190 // - 0.5 seconds of silence if time < 3 seconds | 211 // - 0.5 seconds of silence if time < 3 seconds |
| 191 // - 1 seconds of silence if time >= 3 seconds | 212 // - 1 seconds of silence if time >= 3 seconds |
| 192 endpointer_.set_speech_input_complete_silence_length( | 213 endpointer_.set_speech_input_complete_silence_length( |
| 193 base::Time::kMicrosecondsPerSecond / 2); | 214 base::Time::kMicrosecondsPerSecond / 2); |
| 194 endpointer_.set_long_speech_input_complete_silence_length( | 215 endpointer_.set_long_speech_input_complete_silence_length( |
| (...skipping 11 matching lines...) Expand all Loading... |
| 206 } | 227 } |
| 207 | 228 |
| 208 // ------- Methods that trigger Finite State Machine (FSM) events ------------ | 229 // ------- Methods that trigger Finite State Machine (FSM) events ------------ |
| 209 | 230 |
| 210 // NOTE:all the external events and requests should be enqueued (PostTask), even | 231 // NOTE:all the external events and requests should be enqueued (PostTask), even |
| 211 // if they come from the same (IO) thread, in order to preserve the relationship | 232 // if they come from the same (IO) thread, in order to preserve the relationship |
| 212 // of causality between events and avoid interleaved event processing due to | 233 // of causality between events and avoid interleaved event processing due to |
| 213 // synchronous callbacks. | 234 // synchronous callbacks. |
| 214 | 235 |
| 215 void SpeechRecognizerImpl::StartRecognition(const std::string& device_id) { | 236 void SpeechRecognizerImpl::StartRecognition(const std::string& device_id) { |
| 216 DCHECK(!device_id.empty()); | 237 DCHECK(!device_id.empty() ^ using_audio_receiver_); |
| 217 device_id_ = device_id; | 238 device_id_ = device_id; |
| 218 | 239 |
| 219 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 240 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 220 base::Bind(&SpeechRecognizerImpl::DispatchEvent, | 241 base::Bind(&SpeechRecognizerImpl::DispatchEvent, |
| 221 this, FSMEventArgs(EVENT_START))); | 242 this, FSMEventArgs(EVENT_START))); |
| 222 } | 243 } |
| 223 | 244 |
| 224 void SpeechRecognizerImpl::AbortRecognition() { | 245 void SpeechRecognizerImpl::AbortRecognition() { |
| 225 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 246 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 226 base::Bind(&SpeechRecognizerImpl::DispatchEvent, | 247 base::Bind(&SpeechRecognizerImpl::DispatchEvent, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 237 // Checking the FSM state from another thread (thus, while the FSM is | 258 // Checking the FSM state from another thread (thus, while the FSM is |
| 238 // potentially concurrently evolving) is meaningless. | 259 // potentially concurrently evolving) is meaningless. |
| 239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 240 return state_ != STATE_IDLE && state_ != STATE_ENDED; | 261 return state_ != STATE_IDLE && state_ != STATE_ENDED; |
| 241 } | 262 } |
| 242 | 263 |
| 243 bool SpeechRecognizerImpl::IsCapturingAudio() const { | 264 bool SpeechRecognizerImpl::IsCapturingAudio() const { |
| 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); // See IsActive(). | 265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); // See IsActive(). |
| 245 const bool is_capturing_audio = state_ >= STATE_STARTING && | 266 const bool is_capturing_audio = state_ >= STATE_STARTING && |
| 246 state_ <= STATE_RECOGNIZING; | 267 state_ <= STATE_RECOGNIZING; |
| 247 DCHECK((is_capturing_audio && (audio_controller_.get() != NULL)) || | 268 DCHECK((is_capturing_audio && |
| 269 (using_audio_receiver_ || (audio_controller_.get() != NULL))) || |
| 248 (!is_capturing_audio && audio_controller_.get() == NULL)); | 270 (!is_capturing_audio && audio_controller_.get() == NULL)); |
| 249 return is_capturing_audio; | 271 return is_capturing_audio; |
| 250 } | 272 } |
| 251 | 273 |
| 252 const SpeechRecognitionEngine& | 274 const SpeechRecognitionEngine& |
| 253 SpeechRecognizerImpl::recognition_engine() const { | 275 SpeechRecognizerImpl::recognition_engine() const { |
| 254 return *(recognition_engine_.get()); | 276 return *(recognition_engine_.get()); |
| 255 } | 277 } |
| 256 | 278 |
| 257 SpeechRecognizerImpl::~SpeechRecognizerImpl() { | 279 SpeechRecognizerImpl::~SpeechRecognizerImpl() { |
| 258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 259 endpointer_.EndSession(); | 281 endpointer_.EndSession(); |
| 260 if (audio_controller_.get()) { | 282 if (audio_controller_.get()) { |
| 261 audio_controller_->Close( | 283 audio_controller_->Close( |
| 262 base::Bind(&KeepAudioControllerRefcountedForDtor, audio_controller_)); | 284 base::Bind(&KeepAudioControllerRefcountedForDtor, audio_controller_)); |
| 263 audio_log_->OnClosed(0); | 285 audio_log_->OnClosed(0); |
| 286 } else if (audio_receiver_.get()) { |
| 287 ResetAudioReceiver(); |
| 264 } | 288 } |
| 265 } | 289 } |
| 266 | 290 |
| 267 // Invoked in the audio thread. | 291 // Invoked in the audio thread. |
| 268 void SpeechRecognizerImpl::OnError(AudioInputController* controller, | 292 void SpeechRecognizerImpl::OnError(AudioInputController* controller, |
| 269 media::AudioInputController::ErrorCode error_code) { | 293 media::AudioInputController::ErrorCode error_code) { |
| 270 FSMEventArgs event_args(EVENT_AUDIO_ERROR); | 294 FSMEventArgs event_args(EVENT_AUDIO_ERROR); |
| 271 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 295 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 272 base::Bind(&SpeechRecognizerImpl::DispatchEvent, | 296 base::Bind(&SpeechRecognizerImpl::DispatchEvent, |
| 273 this, event_args)); | 297 this, event_args)); |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 state_ <= STATE_RECOGNIZING; | 498 state_ <= STATE_RECOGNIZING; |
| 475 const bool clip_detected = DetectClipping(raw_audio); | 499 const bool clip_detected = DetectClipping(raw_audio); |
| 476 float rms = 0.0f; | 500 float rms = 0.0f; |
| 477 | 501 |
| 478 num_samples_recorded_ += raw_audio.NumSamples(); | 502 num_samples_recorded_ += raw_audio.NumSamples(); |
| 479 | 503 |
| 480 if (route_to_endpointer) | 504 if (route_to_endpointer) |
| 481 endpointer_.ProcessAudio(raw_audio, &rms); | 505 endpointer_.ProcessAudio(raw_audio, &rms); |
| 482 | 506 |
| 483 if (route_to_vumeter) { | 507 if (route_to_vumeter) { |
| 484 DCHECK(route_to_endpointer); // Depends on endpointer due to |rms|. | 508 DCHECK(route_to_endpointer); // Depends on endpointer due to |rms|. |
| 485 UpdateSignalAndNoiseLevels(rms, clip_detected); | 509 UpdateSignalAndNoiseLevels(rms, clip_detected); |
| 486 } | 510 } |
| 487 if (route_to_sr_engine) { | 511 if (route_to_sr_engine) { |
| 488 DCHECK(recognition_engine_.get() != NULL); | 512 DCHECK(recognition_engine_.get() != NULL); |
| 489 recognition_engine_->TakeAudioChunk(raw_audio); | 513 recognition_engine_->TakeAudioChunk(raw_audio); |
| 490 } | 514 } |
| 491 } | 515 } |
| 492 | 516 |
| 493 SpeechRecognizerImpl::FSMState | 517 SpeechRecognizerImpl::FSMState |
| 494 SpeechRecognizerImpl::StartRecording(const FSMEventArgs&) { | 518 SpeechRecognizerImpl::StartRecording(const FSMEventArgs&) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 521 return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO)); | 545 return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO)); |
| 522 } | 546 } |
| 523 | 547 |
| 524 // Audio converter shall provide audio based on these parameters as output. | 548 // Audio converter shall provide audio based on these parameters as output. |
| 525 // Hard coded, WebSpeech specific parameters are utilized here. | 549 // Hard coded, WebSpeech specific parameters are utilized here. |
| 526 int frames_per_buffer = (kAudioSampleRate * chunk_duration_ms) / 1000; | 550 int frames_per_buffer = (kAudioSampleRate * chunk_duration_ms) / 1000; |
| 527 AudioParameters output_parameters = AudioParameters( | 551 AudioParameters output_parameters = AudioParameters( |
| 528 AudioParameters::AUDIO_PCM_LOW_LATENCY, kChannelLayout, kAudioSampleRate, | 552 AudioParameters::AUDIO_PCM_LOW_LATENCY, kChannelLayout, kAudioSampleRate, |
| 529 kNumBitsPerAudioSample, frames_per_buffer); | 553 kNumBitsPerAudioSample, frames_per_buffer); |
| 530 | 554 |
| 555 // Check if using audio receiver as source (audio data processed on renderer). |
| 556 // If |StartRecordingUsingAudioReceiver()| fails, we abort the recognition. |
| 557 if (using_audio_receiver_) { |
| 558 return StartRecordingUsingAudioReceiver(output_parameters) ? |
| 559 STATE_STARTING : |
| 560 Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO)); |
| 561 } |
| 562 |
| 563 // Get audio data from microphone on the browser. |
| 564 |
| 531 // Audio converter will receive audio based on these parameters as input. | 565 // Audio converter will receive audio based on these parameters as input. |
| 532 // On Windows we start by verifying that Core Audio is supported. If not, | 566 // On Windows we start by verifying that Core Audio is supported. If not, |
| 533 // the WaveIn API is used and we might as well avoid all audio conversations | 567 // the WaveIn API is used and we might as well avoid all audio conversations |
| 534 // since WaveIn does the conversion for us. | 568 // since WaveIn does the conversion for us. |
| 535 // TODO(henrika): this code should be moved to platform dependent audio | 569 // TODO(henrika): this code should be moved to platform dependent audio |
| 536 // managers. | 570 // managers. |
| 537 bool use_native_audio_params = true; | 571 bool use_native_audio_params = true; |
| 538 #if defined(OS_WIN) | 572 #if defined(OS_WIN) |
| 539 use_native_audio_params = media::CoreAudioUtil::IsSupported(); | 573 use_native_audio_params = media::CoreAudioUtil::IsSupported(); |
| 540 DVLOG_IF(1, !use_native_audio_params) << "Reverting to WaveIn for WebSpeech"; | 574 DVLOG_IF(1, !use_native_audio_params) << "Reverting to WaveIn for WebSpeech"; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 577 // The endpointer needs to estimate the environment/background noise before | 611 // The endpointer needs to estimate the environment/background noise before |
| 578 // starting to treat the audio as user input. We wait in the state | 612 // starting to treat the audio as user input. We wait in the state |
| 579 // ESTIMATING_ENVIRONMENT until such interval has elapsed before switching | 613 // ESTIMATING_ENVIRONMENT until such interval has elapsed before switching |
| 580 // to user input mode. | 614 // to user input mode. |
| 581 endpointer_.SetEnvironmentEstimationMode(); | 615 endpointer_.SetEnvironmentEstimationMode(); |
| 582 audio_controller_->Record(); | 616 audio_controller_->Record(); |
| 583 audio_log_->OnStarted(0); | 617 audio_log_->OnStarted(0); |
| 584 return STATE_STARTING; | 618 return STATE_STARTING; |
| 585 } | 619 } |
| 586 | 620 |
| 621 bool SpeechRecognizerImpl::StartRecordingUsingAudioReceiver( |
| 622 const media::AudioParameters& params) { |
| 623 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 624 DCHECK(!audio_thread_.get()); |
| 625 DCHECK(!audio_receiver_.get()); |
| 626 |
| 627 audio_thread_.reset(new base::Thread("AudioReceiverThread")); |
| 628 if (!audio_thread_->Start()) { |
| 629 DLOG(ERROR) << "Cannot start new audio thread"; |
| 630 audio_thread_.reset(); |
| 631 return false; |
| 632 } |
| 633 |
| 634 // Start receiving audio, incoming data will be posted to |OnAudioTrackData|. |
| 635 base::SharedMemoryHandle foreign_memory_handle; |
| 636 base::SyncSocket::TransitDescriptor foreign_socket_descriptor; |
| 637 audio_receiver_ = SpeechRecognitionAudioReceiver::Create( |
| 638 params, |
| 639 peer_process_handle_, |
| 640 this, // Trigger OnData() and OnError() events here. |
| 641 audio_thread_->task_runner().get(), |
| 642 &foreign_memory_handle, |
| 643 &foreign_socket_descriptor); |
| 644 |
| 645 if (!audio_receiver_.get()) { |
| 646 ResetAudioReceiver(); |
| 647 return false; |
| 648 } |
| 649 |
| 650 // Reusing the audio converter only to create chunks from the bus. |
| 651 // Same input and output format indicate no additional conversion here. |
| 652 audio_converter_.reset(new OnDataConverter(params, params)); |
| 653 |
| 654 // The endpointer needs to estimate the environment/background noise before |
| 655 // starting to treat the audio as user input. We wait in the state |
| 656 // ESTIMATING_ENVIRONMENT until such interval has elapsed before switching |
| 657 // to user input mode. |
| 658 endpointer_.SetEnvironmentEstimationMode(); |
| 659 |
| 660 listener()->OnAudioReceiverReady(session_id(), |
| 661 params, |
| 662 foreign_memory_handle, |
| 663 foreign_socket_descriptor); |
| 664 |
| 665 // Start listening on the receiver's audio thread. |
| 666 audio_receiver_->StartListening(); |
| 667 |
| 668 return true; |
| 669 } |
| 670 |
| 671 void SpeechRecognizerImpl::ResetAudioReceiver() { |
| 672 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 673 |
| 674 // We stop listening not to post any new tasks to the audio thread. |
| 675 if (audio_receiver_.get()) |
| 676 audio_receiver_->Stop(); |
| 677 |
| 678 if (!audio_thread_.get()) |
| 679 return; |
| 680 |
| 681 // This synchronous operation is usually instantaneous since the receiver |
| 682 // closes the socket on Stop() and no new tasks will be posted to the |
| 683 // |audio_thread_|. |
| 684 const bool previous_io_allowed = base::ThreadRestrictions::SetIOAllowed(true); |
| 685 audio_thread_->Stop(); |
| 686 base::ThreadRestrictions::SetIOAllowed(previous_io_allowed); |
| 687 |
| 688 audio_thread_.reset(); |
| 689 audio_receiver_.reset(); |
| 690 } |
| 691 |
| 587 SpeechRecognizerImpl::FSMState | 692 SpeechRecognizerImpl::FSMState |
| 588 SpeechRecognizerImpl::StartRecognitionEngine(const FSMEventArgs& event_args) { | 693 SpeechRecognizerImpl::StartRecognitionEngine(const FSMEventArgs& event_args) { |
| 589 // This is the first audio packet captured, so the recognition engine is | 694 // This is the first audio packet captured, so the recognition engine is |
| 590 // started and the delegate notified about the event. | 695 // started and the delegate notified about the event. |
| 591 DCHECK(recognition_engine_.get() != NULL); | 696 DCHECK(recognition_engine_.get() != NULL); |
| 592 recognition_engine_->StartRecognition(); | 697 recognition_engine_->StartRecognition(); |
| 593 listener()->OnAudioStart(session_id()); | 698 listener()->OnAudioStart(session_id()); |
| 594 | 699 |
| 595 // This is a little hack, since TakeAudioChunk() is already called by | 700 // This is a little hack, since TakeAudioChunk() is already called by |
| 596 // ProcessAudioPipeline(). It is the best tradeoff, unless we allow dropping | 701 // ProcessAudioPipeline(). It is the best tradeoff, unless we allow dropping |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 762 | 867 |
| 763 SpeechRecognizerImpl::FSMState | 868 SpeechRecognizerImpl::FSMState |
| 764 SpeechRecognizerImpl::NotFeasible(const FSMEventArgs& event_args) { | 869 SpeechRecognizerImpl::NotFeasible(const FSMEventArgs& event_args) { |
| 765 NOTREACHED() << "Unfeasible event " << event_args.event | 870 NOTREACHED() << "Unfeasible event " << event_args.event |
| 766 << " in state " << state_; | 871 << " in state " << state_; |
| 767 return state_; | 872 return state_; |
| 768 } | 873 } |
| 769 | 874 |
| 770 void SpeechRecognizerImpl::CloseAudioControllerAsynchronously() { | 875 void SpeechRecognizerImpl::CloseAudioControllerAsynchronously() { |
| 771 DCHECK(IsCapturingAudio()); | 876 DCHECK(IsCapturingAudio()); |
| 877 |
| 878 if (using_audio_receiver_) { |
| 879 ResetAudioReceiver(); |
| 880 return; |
| 881 } |
| 882 |
| 772 DVLOG(1) << "SpeechRecognizerImpl closing audio controller."; | 883 DVLOG(1) << "SpeechRecognizerImpl closing audio controller."; |
| 773 // Issues a Close on the audio controller, passing an empty callback. The only | 884 // Issues a Close on the audio controller, passing an empty callback. The only |
| 774 // purpose of such callback is to keep the audio controller refcounted until | 885 // purpose of such callback is to keep the audio controller refcounted until |
| 775 // Close has completed (in the audio thread) and automatically destroy it | 886 // Close has completed (in the audio thread) and automatically destroy it |
| 776 // afterwards (upon return from OnAudioClosed). | 887 // afterwards (upon return from OnAudioClosed). |
| 777 audio_controller_->Close(base::Bind(&SpeechRecognizerImpl::OnAudioClosed, | 888 audio_controller_->Close(base::Bind(&SpeechRecognizerImpl::OnAudioClosed, |
| 778 this, audio_controller_)); | 889 this, audio_controller_)); |
| 779 audio_controller_ = NULL; // The controller is still refcounted by Bind. | 890 audio_controller_ = NULL; // The controller is still refcounted by Bind. |
| 780 audio_log_->OnClosed(0); | 891 audio_log_->OnClosed(0); |
| 781 } | 892 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 814 SpeechRecognizerImpl::FSMEventArgs::FSMEventArgs(FSMEvent event_value) | 925 SpeechRecognizerImpl::FSMEventArgs::FSMEventArgs(FSMEvent event_value) |
| 815 : event(event_value), | 926 : event(event_value), |
| 816 audio_data(NULL), | 927 audio_data(NULL), |
| 817 engine_error(SPEECH_RECOGNITION_ERROR_NONE) { | 928 engine_error(SPEECH_RECOGNITION_ERROR_NONE) { |
| 818 } | 929 } |
| 819 | 930 |
| 820 SpeechRecognizerImpl::FSMEventArgs::~FSMEventArgs() { | 931 SpeechRecognizerImpl::FSMEventArgs::~FSMEventArgs() { |
| 821 } | 932 } |
| 822 | 933 |
| 823 } // namespace content | 934 } // namespace content |
| OLD | NEW |