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

Side by Side Diff: content/browser/speech/speech_recognizer_impl.cc

Issue 594063002: Example use case for AudioSharedBuffer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Using AudioSharedBuffer instead of AudioInputBuffer Created 6 years, 2 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 unified diff | Download patch
« no previous file with comments | « no previous file | content/renderer/media/speech_recognition_audio_source_provider.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/process/process_handle.h"
11 #include "base/threading/thread.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/public/browser/browser_message_filter.h"
14 #include "content/public/browser/speech_recognition_event_listener.h" 18 #include "content/public/browser/speech_recognition_event_listener.h"
15 #include "media/base/audio_converter.h" 19 #include "media/base/audio_converter.h"
16 #include "net/url_request/url_request_context_getter.h" 20 #include "net/url_request/url_request_context_getter.h"
17 21
18 #if defined(OS_WIN) 22 #if defined(OS_WIN)
19 #include "media/audio/win/core_audio_util_win.h" 23 #include "media/audio/win/core_audio_util_win.h"
20 #endif 24 #endif
21 25
22 using media::AudioBus; 26 using media::AudioBus;
23 using media::AudioConverter; 27 using media::AudioConverter;
28 using media::AudioInputBufferParameters;
24 using media::AudioInputController; 29 using media::AudioInputController;
25 using media::AudioManager; 30 using media::AudioManager;
26 using media::AudioParameters; 31 using media::AudioParameters;
27 using media::ChannelLayout; 32 using media::ChannelLayout;
28 33
29 namespace content { 34 namespace content {
30 35
31 // Private class which encapsulates the audio converter and the 36 // Private class which encapsulates the audio converter and the
32 // AudioConverter::InputCallback. It handles resampling, buffering and 37 // AudioConverter::InputCallback. It handles resampling, buffering and
33 // channel mixing between input and output parameters. 38 // channel mixing between input and output parameters.
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 virtual ~OnDataConverter(); 44 virtual ~OnDataConverter();
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 virtual double ProvideInput(AudioBus* dest, 54 virtual double ProvideInput(AudioBus* dest,
49 base::TimeDelta buffer_delay) OVERRIDE; 55 base::TimeDelta buffer_delay) OVERRIDE;
50 56
51 // Handles resampling, buffering, and channel mixing between input and output 57 // Handles resampling, buffering, and channel mixing between input and output
52 // parameters. 58 // parameters.
53 AudioConverter audio_converter_; 59 AudioConverter audio_converter_;
54 60
55 scoped_ptr<AudioBus> input_bus_; 61 scoped_ptr<AudioBus> input_bus_;
56 scoped_ptr<AudioBus> output_bus_; 62 scoped_ptr<AudioBus> output_bus_;
57 const AudioParameters input_parameters_; 63 const AudioParameters input_parameters_;
58 const AudioParameters output_parameters_; 64 const AudioParameters output_parameters_;
59 bool waiting_for_input_; 65 bool waiting_for_input_;
66 bool need_conversion_;
60 scoped_ptr<uint8[]> converted_data_; 67 scoped_ptr<uint8[]> converted_data_;
61 68
62 DISALLOW_COPY_AND_ASSIGN(OnDataConverter); 69 DISALLOW_COPY_AND_ASSIGN(OnDataConverter);
63 }; 70 };
64 71
65 namespace { 72 namespace {
66 73
67 // The following constants are related to the volume level indicator shown in 74 // The following constants are related to the volume level indicator shown in
68 // the UI for recorded audio. 75 // the UI for recorded audio.
69 // Multiplier used when new volume is greater than previous level. 76 // Multiplier used when new volume is greater than previous level.
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
117 SpeechRecognizerImpl::OnDataConverter::OnDataConverter( 124 SpeechRecognizerImpl::OnDataConverter::OnDataConverter(
118 const AudioParameters& input_params, const AudioParameters& output_params) 125 const AudioParameters& input_params, const AudioParameters& output_params)
119 : audio_converter_(input_params, output_params, false), 126 : audio_converter_(input_params, output_params, false),
120 input_bus_(AudioBus::Create(input_params)), 127 input_bus_(AudioBus::Create(input_params)),
121 output_bus_(AudioBus::Create(output_params)), 128 output_bus_(AudioBus::Create(output_params)),
122 input_parameters_(input_params), 129 input_parameters_(input_params),
123 output_parameters_(output_params), 130 output_parameters_(output_params),
124 waiting_for_input_(false), 131 waiting_for_input_(false),
125 converted_data_(new uint8[output_parameters_.GetBytesPerBuffer()]) { 132 converted_data_(new uint8[output_parameters_.GetBytesPerBuffer()]) {
126 audio_converter_.AddInput(this); 133 audio_converter_.AddInput(this);
134 need_conversion_ = !(input_parameters_ == output_parameters_);
127 } 135 }
128 136
129 SpeechRecognizerImpl::OnDataConverter::~OnDataConverter() { 137 SpeechRecognizerImpl::OnDataConverter::~OnDataConverter() {
130 // It should now be safe to unregister the converter since no more OnData() 138 // It should now be safe to unregister the converter since no more OnData()
131 // callbacks are outstanding at this point. 139 // callbacks are outstanding at this point.
132 audio_converter_.RemoveInput(this); 140 audio_converter_.RemoveInput(this);
133 } 141 }
134 142
135 scoped_refptr<AudioChunk> SpeechRecognizerImpl::OnDataConverter::Convert( 143 scoped_refptr<AudioChunk> SpeechRecognizerImpl::OnDataConverter::Convert(
136 const AudioBus* data) { 144 const AudioBus* data) {
137 CHECK_EQ(data->frames(), input_parameters_.frames_per_buffer()); 145 CHECK_EQ(data->frames(), input_parameters_.frames_per_buffer());
138 146
139 data->CopyTo(input_bus_.get()); 147 // Do conversion if needed - only when |input_parameters_| differ from
140 148 // |output_parameters_|.
141 waiting_for_input_ = true; 149 if (need_conversion_) {
142 audio_converter_.Convert(output_bus_.get()); 150 data->CopyTo(input_bus_.get());
151 waiting_for_input_ = true;
152 audio_converter_.Convert(output_bus_.get());
153 } else {
154 data->CopyTo(output_bus_.get());
155 }
143 156
144 output_bus_->ToInterleaved( 157 output_bus_->ToInterleaved(
145 output_bus_->frames(), output_parameters_.bits_per_sample() / 8, 158 output_bus_->frames(), output_parameters_.bits_per_sample() / 8,
146 converted_data_.get()); 159 converted_data_.get());
147 160
148 // TODO(primiano): Refactor AudioChunk to avoid the extra-copy here 161 // TODO(primiano): Refactor AudioChunk to avoid the extra-copy here
149 // (see http://crbug.com/249316 for details). 162 // (see http://crbug.com/249316 for details).
150 return scoped_refptr<AudioChunk>(new AudioChunk( 163 return scoped_refptr<AudioChunk>(new AudioChunk(
151 converted_data_.get(), 164 converted_data_.get(),
152 output_parameters_.GetBytesPerBuffer(), 165 output_parameters_.GetBytesPerBuffer(),
(...skipping 15 matching lines...) Expand all
168 return 1; 181 return 1;
169 } 182 }
170 183
171 // SpeechRecognizerImpl implementation 184 // SpeechRecognizerImpl implementation
172 185
173 SpeechRecognizerImpl::SpeechRecognizerImpl( 186 SpeechRecognizerImpl::SpeechRecognizerImpl(
174 SpeechRecognitionEventListener* listener, 187 SpeechRecognitionEventListener* listener,
175 int session_id, 188 int session_id,
176 bool continuous, 189 bool continuous,
177 bool provisional_results, 190 bool provisional_results,
191 bool using_audio_track,
192 base::ProcessHandle peer_process_handle,
178 SpeechRecognitionEngine* engine) 193 SpeechRecognitionEngine* engine)
179 : SpeechRecognizer(listener, session_id), 194 : SpeechRecognizer(listener, session_id),
180 recognition_engine_(engine), 195 recognition_engine_(engine),
181 endpointer_(kAudioSampleRate), 196 endpointer_(kAudioSampleRate),
182 audio_log_(MediaInternals::GetInstance()->CreateAudioLog( 197 audio_log_(MediaInternals::GetInstance()->CreateAudioLog(
183 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)), 198 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)),
184 is_dispatching_event_(false), 199 is_dispatching_event_(false),
185 provisional_results_(provisional_results), 200 provisional_results_(provisional_results),
201 using_audio_track_(using_audio_track),
202 peer_process_handle_(peer_process_handle),
186 state_(STATE_IDLE) { 203 state_(STATE_IDLE) {
187 DCHECK(recognition_engine_ != NULL); 204 DCHECK(recognition_engine_ != NULL);
188 if (!continuous) { 205 if (!continuous) {
189 // In single shot (non-continous) recognition, 206 // In single shot (non-continous) recognition,
190 // the session is automatically ended after: 207 // the session is automatically ended after:
191 // - 0.5 seconds of silence if time < 3 seconds 208 // - 0.5 seconds of silence if time < 3 seconds
192 // - 1 seconds of silence if time >= 3 seconds 209 // - 1 seconds of silence if time >= 3 seconds
193 endpointer_.set_speech_input_complete_silence_length( 210 endpointer_.set_speech_input_complete_silence_length(
194 base::Time::kMicrosecondsPerSecond / 2); 211 base::Time::kMicrosecondsPerSecond / 2);
195 endpointer_.set_long_speech_input_complete_silence_length( 212 endpointer_.set_long_speech_input_complete_silence_length(
(...skipping 11 matching lines...) Expand all
207 } 224 }
208 225
209 // ------- Methods that trigger Finite State Machine (FSM) events ------------ 226 // ------- Methods that trigger Finite State Machine (FSM) events ------------
210 227
211 // NOTE:all the external events and requests should be enqueued (PostTask), even 228 // NOTE:all the external events and requests should be enqueued (PostTask), even
212 // if they come from the same (IO) thread, in order to preserve the relationship 229 // if they come from the same (IO) thread, in order to preserve the relationship
213 // of causality between events and avoid interleaved event processing due to 230 // of causality between events and avoid interleaved event processing due to
214 // synchronous callbacks. 231 // synchronous callbacks.
215 232
216 void SpeechRecognizerImpl::StartRecognition(const std::string& device_id) { 233 void SpeechRecognizerImpl::StartRecognition(const std::string& device_id) {
217 DCHECK(!device_id.empty()); 234 DCHECK(!device_id.empty() ^ using_audio_track_);
218 device_id_ = device_id; 235 device_id_ = device_id;
219 236
220 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 237 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
221 base::Bind(&SpeechRecognizerImpl::DispatchEvent, 238 base::Bind(&SpeechRecognizerImpl::DispatchEvent,
222 this, FSMEventArgs(EVENT_START))); 239 this, FSMEventArgs(EVENT_START)));
223 } 240 }
224 241
225 void SpeechRecognizerImpl::AbortRecognition() { 242 void SpeechRecognizerImpl::AbortRecognition() {
226 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 243 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
227 base::Bind(&SpeechRecognizerImpl::DispatchEvent, 244 base::Bind(&SpeechRecognizerImpl::DispatchEvent,
(...skipping 10 matching lines...) Expand all
238 // Checking the FSM state from another thread (thus, while the FSM is 255 // Checking the FSM state from another thread (thus, while the FSM is
239 // potentially concurrently evolving) is meaningless. 256 // potentially concurrently evolving) is meaningless.
240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
241 return state_ != STATE_IDLE && state_ != STATE_ENDED; 258 return state_ != STATE_IDLE && state_ != STATE_ENDED;
242 } 259 }
243 260
244 bool SpeechRecognizerImpl::IsCapturingAudio() const { 261 bool SpeechRecognizerImpl::IsCapturingAudio() const {
245 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); // See IsActive(). 262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); // See IsActive().
246 const bool is_capturing_audio = state_ >= STATE_STARTING && 263 const bool is_capturing_audio = state_ >= STATE_STARTING &&
247 state_ <= STATE_RECOGNIZING; 264 state_ <= STATE_RECOGNIZING;
248 DCHECK((is_capturing_audio && (audio_controller_.get() != NULL)) || 265 DCHECK((is_capturing_audio &&
266 (using_audio_track_ || (audio_controller_.get() != NULL))) ||
249 (!is_capturing_audio && audio_controller_.get() == NULL)); 267 (!is_capturing_audio && audio_controller_.get() == NULL));
250 return is_capturing_audio; 268 return is_capturing_audio;
251 } 269 }
252 270
253 const SpeechRecognitionEngine& 271 const SpeechRecognitionEngine&
254 SpeechRecognizerImpl::recognition_engine() const { 272 SpeechRecognizerImpl::recognition_engine() const {
255 return *(recognition_engine_.get()); 273 return *(recognition_engine_.get());
256 } 274 }
257 275
258 SpeechRecognizerImpl::~SpeechRecognizerImpl() { 276 SpeechRecognizerImpl::~SpeechRecognizerImpl() {
259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
260 endpointer_.EndSession(); 278 endpointer_.EndSession();
261 if (audio_controller_.get()) { 279 if (audio_controller_.get()) {
262 audio_controller_->Close( 280 audio_controller_->Close(
263 base::Bind(&KeepAudioControllerRefcountedForDtor, audio_controller_)); 281 base::Bind(&KeepAudioControllerRefcountedForDtor, audio_controller_));
264 audio_log_->OnClosed(0); 282 audio_log_->OnClosed(0);
265 } 283 }
284
285 if (audio_sync_thread_.get()) {
286 base::ThreadRestrictions::SetIOAllowed(true);
287 audio_sync_socket_->Shutdown();
288 audio_sync_thread_->Stop();
289 }
266 } 290 }
267 291
268 // Invoked in the audio thread. 292 // Invoked in the audio thread.
269 void SpeechRecognizerImpl::OnError(AudioInputController* controller, 293 void SpeechRecognizerImpl::OnError(AudioInputController* controller,
270 media::AudioInputController::ErrorCode error_code) { 294 media::AudioInputController::ErrorCode error_code) {
271 FSMEventArgs event_args(EVENT_AUDIO_ERROR); 295 FSMEventArgs event_args(EVENT_AUDIO_ERROR);
272 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 296 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
273 base::Bind(&SpeechRecognizerImpl::DispatchEvent, 297 base::Bind(&SpeechRecognizerImpl::DispatchEvent,
274 this, event_args)); 298 this, event_args));
275 } 299 }
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 state_ <= STATE_RECOGNIZING; 499 state_ <= STATE_RECOGNIZING;
476 const bool clip_detected = DetectClipping(raw_audio); 500 const bool clip_detected = DetectClipping(raw_audio);
477 float rms = 0.0f; 501 float rms = 0.0f;
478 502
479 num_samples_recorded_ += raw_audio.NumSamples(); 503 num_samples_recorded_ += raw_audio.NumSamples();
480 504
481 if (route_to_endpointer) 505 if (route_to_endpointer)
482 endpointer_.ProcessAudio(raw_audio, &rms); 506 endpointer_.ProcessAudio(raw_audio, &rms);
483 507
484 if (route_to_vumeter) { 508 if (route_to_vumeter) {
485 DCHECK(route_to_endpointer); // Depends on endpointer due to |rms|. 509 DCHECK(route_to_endpointer); // Depends on endpointer due to |rms|.
486 UpdateSignalAndNoiseLevels(rms, clip_detected); 510 UpdateSignalAndNoiseLevels(rms, clip_detected);
487 } 511 }
488 if (route_to_sr_engine) { 512 if (route_to_sr_engine) {
489 DCHECK(recognition_engine_.get() != NULL); 513 DCHECK(recognition_engine_.get() != NULL);
490 recognition_engine_->TakeAudioChunk(raw_audio); 514 recognition_engine_->TakeAudioChunk(raw_audio);
491 } 515 }
492 } 516 }
493 517
494 SpeechRecognizerImpl::FSMState 518 SpeechRecognizerImpl::FSMState
495 SpeechRecognizerImpl::StartRecording(const FSMEventArgs&) { 519 SpeechRecognizerImpl::StartRecording(const FSMEventArgs&) {
(...skipping 26 matching lines...) Expand all
522 return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO)); 546 return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO));
523 } 547 }
524 548
525 // Audio converter shall provide audio based on these parameters as output. 549 // Audio converter shall provide audio based on these parameters as output.
526 // Hard coded, WebSpeech specific parameters are utilized here. 550 // Hard coded, WebSpeech specific parameters are utilized here.
527 int frames_per_buffer = (kAudioSampleRate * chunk_duration_ms) / 1000; 551 int frames_per_buffer = (kAudioSampleRate * chunk_duration_ms) / 1000;
528 AudioParameters output_parameters = AudioParameters( 552 AudioParameters output_parameters = AudioParameters(
529 AudioParameters::AUDIO_PCM_LOW_LATENCY, kChannelLayout, kAudioSampleRate, 553 AudioParameters::AUDIO_PCM_LOW_LATENCY, kChannelLayout, kAudioSampleRate,
530 kNumBitsPerAudioSample, frames_per_buffer); 554 kNumBitsPerAudioSample, frames_per_buffer);
531 555
556 // Check if using audio track as source (audio data processed on renderer).
557 // If |StartRecordingUsingAudioTrack()| fails, we abort the recognition.
558 if (using_audio_track_)
559 return StartRecordingUsingAudioTrack(output_parameters)
560 ? STATE_STARTING
561 : Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO));
562
563 // Get audio data from microphone on the browser.
564
532 // Audio converter will receive audio based on these parameters as input. 565 // Audio converter will receive audio based on these parameters as input.
533 // 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,
534 // 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
535 // since WaveIn does the conversion for us. 568 // since WaveIn does the conversion for us.
536 // TODO(henrika): this code should be moved to platform dependent audio 569 // TODO(henrika): this code should be moved to platform dependent audio
537 // managers. 570 // managers.
538 bool use_native_audio_params = true; 571 bool use_native_audio_params = true;
539 #if defined(OS_WIN) 572 #if defined(OS_WIN)
540 use_native_audio_params = media::CoreAudioUtil::IsSupported(); 573 use_native_audio_params = media::CoreAudioUtil::IsSupported();
541 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
578 // The endpointer needs to estimate the environment/background noise before 611 // The endpointer needs to estimate the environment/background noise before
579 // 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
580 // ESTIMATING_ENVIRONMENT until such interval has elapsed before switching 613 // ESTIMATING_ENVIRONMENT until such interval has elapsed before switching
581 // to user input mode. 614 // to user input mode.
582 endpointer_.SetEnvironmentEstimationMode(); 615 endpointer_.SetEnvironmentEstimationMode();
583 audio_controller_->Record(); 616 audio_controller_->Record();
584 audio_log_->OnStarted(0); 617 audio_log_->OnStarted(0);
585 return STATE_STARTING; 618 return STATE_STARTING;
586 } 619 }
587 620
621 bool SpeechRecognizerImpl::StartRecordingUsingAudioTrack(
622 const media::AudioParameters& params) {
623 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
624 // Create the shared memory and share with the renderer process.
625 uint32 shared_memory_size = sizeof(uint32) +
626 AudioBus::CalculateMemorySize(params);
627 shared_memory_.reset(new base::SharedMemory());
628 if (!shared_memory_->CreateAndMapAnonymous(shared_memory_size)) {
629 DLOG(ERROR) << "Failed to create shared memory for the speech recognizer";
630 return false;
631 }
632 base::SharedMemoryHandle foreign_memory_handle;
633 if (!shared_memory_->ShareToProcess(base::GetCurrentProcessHandle(),
634 &foreign_memory_handle)) {
635 DLOG(ERROR) << "Failed to map and share the shared memory";
636 return false;
637 }
638 media::AudioSharedBuffer* buffer =
639 static_cast<media::AudioSharedBuffer*>(shared_memory_->memory());
640 audio_track_bus_ = AudioBus::WrapMemory(params, buffer->audio);
641 // Use |buffer->params.size| from shared memory to synchronize by counting
642 // audio buffers when receiving audio data from the renderer.
643 buffer_index_ = &(buffer->buffer_index);
644 *buffer_index_ = 0U;
645 // Reusing the audio converter only to create chunks from the bus.
646 // Same input and output format indicate no additional conversion here.
647 audio_converter_.reset(new OnDataConverter(params, params));
648
649 // The endpointer needs to estimate the environment/background noise before
650 // starting to treat the audio as user input. We wait in the state
651 // ESTIMATING_ENVIRONMENT until such interval has elapsed before switching
652 // to user input mode.
653 endpointer_.SetEnvironmentEstimationMode();
654
655 foreign_sync_socket_.reset(new base::CancelableSyncSocket());
656 audio_sync_socket_.reset(new base::CancelableSyncSocket());
657 if (!base::SyncSocket::CreatePair(audio_sync_socket_.get(),
658 foreign_sync_socket_.get())) {
659 DLOG(ERROR) << "Cannot create SyncSocket pair";
660 return false;
661 }
662
663 base::SyncSocket::TransitDescriptor foreign_socket_descriptor;
664 if (!foreign_sync_socket_->PrepareTransitDescriptor(
665 peer_process_handle_, &foreign_socket_descriptor)) {
666 DLOG(ERROR) << "Cannot prepare syncsocket transit descriptor";
667 return false;
668 }
669
670 // The thread check will be first invoked in |OnAudioTrackData()|.
671 audio_sync_thread_checker_.DetachFromThread();
672 audio_sync_thread_.reset(
673 new base::Thread("SpeechRecognitionAudioTrackThread"));
674 audio_sync_thread_->Start();
675
676 DCHECK_EQ(0U, *buffer_index_);
677 if (!audio_sync_thread_->message_loop_proxy()
678 ->PostTask(FROM_HERE,
679 base::Bind(&SpeechRecognizerImpl::OnAudioTrackData,
680 base::Unretained(this)))) {
681 DLOG(ERROR) << "Cannot post audio sync thread task";
682 return false;
683 }
684
685 listener()->OnAudioTrackReady(session_id(), params, foreign_memory_handle,
686 foreign_socket_descriptor);
687
688 return true;
689 }
690
691 void SpeechRecognizerImpl::OnAudioTrackData() {
692 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
693 DCHECK(audio_sync_thread_checker_.CalledOnValidThread());
694 base::ThreadRestrictions::SetIOAllowed(true);
695
696 // TODO(burnik): We should receive with a timeout here. And when it occurs,
697 // we should stop the recognition assuming there is no more audio data.
698 size_t bytes_received =
699 audio_sync_socket_->Receive(buffer_index_, sizeof(*buffer_index_));
700
701 if (bytes_received != sizeof(*buffer_index_)) {
702 DCHECK_EQ(bytes_received, 0U);
703 return;
704 }
705
706 FSMEventArgs event_args(EVENT_AUDIO_DATA);
707 // Convert audio from native format to fixed format used by WebSpeech.
708 event_args.audio_data = audio_converter_->Convert(audio_track_bus_.get());
709 // Process on browser thread.
710 BrowserThread::PostTask(
711 BrowserThread::IO, FROM_HERE,
712 base::Bind(&SpeechRecognizerImpl::DispatchEvent, this, event_args));
713
714 // Notify host that the buffer was consumed via shared memory.
715 (*buffer_index_)++;
716
717 // Post this task for next round of data.
718 audio_sync_thread_->message_loop_proxy()->PostTask(
719 FROM_HERE, base::Bind(&SpeechRecognizerImpl::OnAudioTrackData,
720 base::Unretained(this)));
721 }
722
588 SpeechRecognizerImpl::FSMState 723 SpeechRecognizerImpl::FSMState
589 SpeechRecognizerImpl::StartRecognitionEngine(const FSMEventArgs& event_args) { 724 SpeechRecognizerImpl::StartRecognitionEngine(const FSMEventArgs& event_args) {
590 // This is the first audio packet captured, so the recognition engine is 725 // This is the first audio packet captured, so the recognition engine is
591 // started and the delegate notified about the event. 726 // started and the delegate notified about the event.
592 DCHECK(recognition_engine_.get() != NULL); 727 DCHECK(recognition_engine_.get() != NULL);
593 recognition_engine_->StartRecognition(); 728 recognition_engine_->StartRecognition();
594 listener()->OnAudioStart(session_id()); 729 listener()->OnAudioStart(session_id());
595 730
596 // This is a little hack, since TakeAudioChunk() is already called by 731 // This is a little hack, since TakeAudioChunk() is already called by
597 // ProcessAudioPipeline(). It is the best tradeoff, unless we allow dropping 732 // ProcessAudioPipeline(). It is the best tradeoff, unless we allow dropping
(...skipping 30 matching lines...) Expand all
628 if (endpointer_.speech_input_complete()) 763 if (endpointer_.speech_input_complete())
629 return StopCaptureAndWaitForResult(event_args); 764 return StopCaptureAndWaitForResult(event_args);
630 return STATE_RECOGNIZING; 765 return STATE_RECOGNIZING;
631 } 766 }
632 767
633 SpeechRecognizerImpl::FSMState 768 SpeechRecognizerImpl::FSMState
634 SpeechRecognizerImpl::StopCaptureAndWaitForResult(const FSMEventArgs&) { 769 SpeechRecognizerImpl::StopCaptureAndWaitForResult(const FSMEventArgs&) {
635 DCHECK(state_ >= STATE_ESTIMATING_ENVIRONMENT && state_ <= STATE_RECOGNIZING); 770 DCHECK(state_ >= STATE_ESTIMATING_ENVIRONMENT && state_ <= STATE_RECOGNIZING);
636 771
637 DVLOG(1) << "Concluding recognition"; 772 DVLOG(1) << "Concluding recognition";
638 CloseAudioControllerAsynchronously(); 773 if (!using_audio_track_) CloseAudioControllerAsynchronously();
639 recognition_engine_->AudioChunksEnded(); 774 recognition_engine_->AudioChunksEnded();
640 775
641 if (state_ > STATE_WAITING_FOR_SPEECH) 776 if (state_ > STATE_WAITING_FOR_SPEECH)
642 listener()->OnSoundEnd(session_id()); 777 listener()->OnSoundEnd(session_id());
643 778
644 listener()->OnAudioEnd(session_id()); 779 listener()->OnAudioEnd(session_id());
645 return STATE_WAITING_FINAL_RESULT; 780 return STATE_WAITING_FINAL_RESULT;
646 } 781 }
647 782
648 SpeechRecognizerImpl::FSMState 783 SpeechRecognizerImpl::FSMState
649 SpeechRecognizerImpl::AbortSilently(const FSMEventArgs& event_args) { 784 SpeechRecognizerImpl::AbortSilently(const FSMEventArgs& event_args) {
650 DCHECK_NE(event_args.event, EVENT_AUDIO_ERROR); 785 DCHECK_NE(event_args.event, EVENT_AUDIO_ERROR);
651 DCHECK_NE(event_args.event, EVENT_ENGINE_ERROR); 786 DCHECK_NE(event_args.event, EVENT_ENGINE_ERROR);
652 return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_NONE)); 787 return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_NONE));
653 } 788 }
654 789
655 SpeechRecognizerImpl::FSMState 790 SpeechRecognizerImpl::FSMState
656 SpeechRecognizerImpl::AbortWithError(const FSMEventArgs& event_args) { 791 SpeechRecognizerImpl::AbortWithError(const FSMEventArgs& event_args) {
657 if (event_args.event == EVENT_AUDIO_ERROR) { 792 if (event_args.event == EVENT_AUDIO_ERROR) {
658 return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO)); 793 return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO));
659 } else if (event_args.event == EVENT_ENGINE_ERROR) { 794 } else if (event_args.event == EVENT_ENGINE_ERROR) {
660 return Abort(event_args.engine_error); 795 return Abort(event_args.engine_error);
661 } 796 }
662 return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_ABORTED)); 797 return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_ABORTED));
663 } 798 }
664 799
665 SpeechRecognizerImpl::FSMState SpeechRecognizerImpl::Abort( 800 SpeechRecognizerImpl::FSMState SpeechRecognizerImpl::Abort(
666 const SpeechRecognitionError& error) { 801 const SpeechRecognitionError& error) {
667 if (IsCapturingAudio()) 802 if (IsCapturingAudio() && !using_audio_track_)
668 CloseAudioControllerAsynchronously(); 803 CloseAudioControllerAsynchronously();
669 804
670 DVLOG(1) << "SpeechRecognizerImpl canceling recognition. "; 805 DVLOG(1) << "SpeechRecognizerImpl canceling recognition. ";
671 806
672 // The recognition engine is initialized only after STATE_STARTING. 807 // The recognition engine is initialized only after STATE_STARTING.
673 if (state_ > STATE_STARTING) { 808 if (state_ > STATE_STARTING) {
674 DCHECK(recognition_engine_.get() != NULL); 809 DCHECK(recognition_engine_.get() != NULL);
675 recognition_engine_->EndRecognition(); 810 recognition_engine_->EndRecognition();
676 } 811 }
677 812
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 898
764 SpeechRecognizerImpl::FSMState 899 SpeechRecognizerImpl::FSMState
765 SpeechRecognizerImpl::NotFeasible(const FSMEventArgs& event_args) { 900 SpeechRecognizerImpl::NotFeasible(const FSMEventArgs& event_args) {
766 NOTREACHED() << "Unfeasible event " << event_args.event 901 NOTREACHED() << "Unfeasible event " << event_args.event
767 << " in state " << state_; 902 << " in state " << state_;
768 return state_; 903 return state_;
769 } 904 }
770 905
771 void SpeechRecognizerImpl::CloseAudioControllerAsynchronously() { 906 void SpeechRecognizerImpl::CloseAudioControllerAsynchronously() {
772 DCHECK(IsCapturingAudio()); 907 DCHECK(IsCapturingAudio());
908 DCHECK(!using_audio_track_);
773 DVLOG(1) << "SpeechRecognizerImpl closing audio controller."; 909 DVLOG(1) << "SpeechRecognizerImpl closing audio controller.";
774 // Issues a Close on the audio controller, passing an empty callback. The only 910 // Issues a Close on the audio controller, passing an empty callback. The only
775 // purpose of such callback is to keep the audio controller refcounted until 911 // purpose of such callback is to keep the audio controller refcounted until
776 // Close has completed (in the audio thread) and automatically destroy it 912 // Close has completed (in the audio thread) and automatically destroy it
777 // afterwards (upon return from OnAudioClosed). 913 // afterwards (upon return from OnAudioClosed).
914
778 audio_controller_->Close(base::Bind(&SpeechRecognizerImpl::OnAudioClosed, 915 audio_controller_->Close(base::Bind(&SpeechRecognizerImpl::OnAudioClosed,
779 this, audio_controller_)); 916 this, audio_controller_));
780 audio_controller_ = NULL; // The controller is still refcounted by Bind. 917 audio_controller_ = NULL; // The controller is still refcounted by Bind.
781 audio_log_->OnClosed(0); 918 audio_log_->OnClosed(0);
782 } 919 }
783 920
784 int SpeechRecognizerImpl::GetElapsedTimeMs() const { 921 int SpeechRecognizerImpl::GetElapsedTimeMs() const {
785 return (num_samples_recorded_ * 1000) / kAudioSampleRate; 922 return (num_samples_recorded_ * 1000) / kAudioSampleRate;
786 } 923 }
787 924
(...skipping 27 matching lines...) Expand all
815 SpeechRecognizerImpl::FSMEventArgs::FSMEventArgs(FSMEvent event_value) 952 SpeechRecognizerImpl::FSMEventArgs::FSMEventArgs(FSMEvent event_value)
816 : event(event_value), 953 : event(event_value),
817 audio_data(NULL), 954 audio_data(NULL),
818 engine_error(SPEECH_RECOGNITION_ERROR_NONE) { 955 engine_error(SPEECH_RECOGNITION_ERROR_NONE) {
819 } 956 }
820 957
821 SpeechRecognizerImpl::FSMEventArgs::~FSMEventArgs() { 958 SpeechRecognizerImpl::FSMEventArgs::~FSMEventArgs() {
822 } 959 }
823 960
824 } // namespace content 961 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | content/renderer/media/speech_recognition_audio_source_provider.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698