Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / speech / speech_recognition_manager_impl.cc
blob1a054204c4477a7e6c4c09abfd11a54aeea7443c
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
3 // found in the LICENSE file.
5 #include "content/browser/speech/speech_recognition_manager_impl.h"
7 #include "base/bind.h"
8 #include "content/browser/browser_main_loop.h"
9 #include "content/browser/renderer_host/media/media_stream_manager.h"
10 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
11 #include "content/browser/speech/google_one_shot_remote_engine.h"
12 #include "content/browser/speech/google_streaming_remote_engine.h"
13 #include "content/browser/speech/speech_recognition_engine.h"
14 #include "content/browser/speech/speech_recognizer_impl.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/content_browser_client.h"
17 #include "content/public/browser/resource_context.h"
18 #include "content/public/browser/speech_recognition_event_listener.h"
19 #include "content/public/browser/speech_recognition_manager_delegate.h"
20 #include "content/public/browser/speech_recognition_session_config.h"
21 #include "content/public/browser/speech_recognition_session_context.h"
22 #include "content/public/common/speech_recognition_error.h"
23 #include "content/public/common/speech_recognition_result.h"
24 #include "media/audio/audio_manager.h"
25 #include "media/audio/audio_manager_base.h"
27 #if defined(OS_ANDROID)
28 #include "content/browser/speech/speech_recognizer_impl_android.h"
29 #endif
31 using base::Callback;
33 namespace content {
35 SpeechRecognitionManager* SpeechRecognitionManager::manager_for_tests_;
37 namespace {
39 SpeechRecognitionManagerImpl* g_speech_recognition_manager_impl;
41 void ShowAudioInputSettingsOnFileThread(media::AudioManager* audio_manager) {
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
43 audio_manager->ShowAudioInputSettings();
46 } // namespace
48 SpeechRecognitionManager* SpeechRecognitionManager::GetInstance() {
49 if (manager_for_tests_)
50 return manager_for_tests_;
51 return SpeechRecognitionManagerImpl::GetInstance();
54 void SpeechRecognitionManager::SetManagerForTesting(
55 SpeechRecognitionManager* manager) {
56 manager_for_tests_ = manager;
59 SpeechRecognitionManagerImpl* SpeechRecognitionManagerImpl::GetInstance() {
60 return g_speech_recognition_manager_impl;
63 SpeechRecognitionManagerImpl::SpeechRecognitionManagerImpl(
64 media::AudioManager* audio_manager,
65 MediaStreamManager* media_stream_manager)
66 : audio_manager_(audio_manager),
67 media_stream_manager_(media_stream_manager),
68 primary_session_id_(kSessionIDInvalid),
69 last_session_id_(kSessionIDInvalid),
70 is_dispatching_event_(false),
71 delegate_(GetContentClient()->browser()->
72 GetSpeechRecognitionManagerDelegate()),
73 weak_factory_(this) {
74 DCHECK(!g_speech_recognition_manager_impl);
75 g_speech_recognition_manager_impl = this;
78 SpeechRecognitionManagerImpl::~SpeechRecognitionManagerImpl() {
79 DCHECK(g_speech_recognition_manager_impl);
80 g_speech_recognition_manager_impl = NULL;
82 for (SessionsTable::iterator it = sessions_.begin(); it != sessions_.end();
83 ++it) {
84 // MediaStreamUIProxy must be deleted on the IO thread.
85 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE,
86 it->second->ui.release());
87 delete it->second;
89 sessions_.clear();
92 int SpeechRecognitionManagerImpl::CreateSession(
93 const SpeechRecognitionSessionConfig& config) {
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
96 const int session_id = GetNextSessionID();
97 DCHECK(!SessionExists(session_id));
98 // Set-up the new session.
99 Session* session = new Session();
100 sessions_[session_id] = session;
101 session->id = session_id;
102 session->config = config;
103 session->context = config.initial_context;
105 std::string hardware_info;
106 bool can_report_metrics = false;
107 if (delegate_)
108 delegate_->GetDiagnosticInformation(&can_report_metrics, &hardware_info);
110 // The legacy api cannot use continuous mode.
111 DCHECK(!config.is_legacy_api || !config.continuous);
113 #if !defined(OS_ANDROID)
114 // A SpeechRecognitionEngine (and corresponding Config) is required only
115 // when using SpeechRecognizerImpl, which performs the audio capture and
116 // endpointing in the browser. This is not the case of Android where, not
117 // only the speech recognition, but also the audio capture and endpointing
118 // activities performed outside of the browser (delegated via JNI to the
119 // Android API implementation).
121 SpeechRecognitionEngineConfig remote_engine_config;
122 remote_engine_config.language = config.language;
123 remote_engine_config.grammars = config.grammars;
124 remote_engine_config.audio_sample_rate =
125 SpeechRecognizerImpl::kAudioSampleRate;
126 remote_engine_config.audio_num_bits_per_sample =
127 SpeechRecognizerImpl::kNumBitsPerAudioSample;
128 remote_engine_config.filter_profanities = config.filter_profanities;
129 remote_engine_config.continuous = config.continuous;
130 remote_engine_config.interim_results = config.interim_results;
131 remote_engine_config.max_hypotheses = config.max_hypotheses;
132 remote_engine_config.hardware_info = hardware_info;
133 remote_engine_config.origin_url =
134 can_report_metrics ? config.origin_url : std::string();
136 SpeechRecognitionEngine* google_remote_engine;
137 if (config.is_legacy_api) {
138 google_remote_engine =
139 new GoogleOneShotRemoteEngine(config.url_request_context_getter.get());
140 } else {
141 google_remote_engine = new GoogleStreamingRemoteEngine(
142 config.url_request_context_getter.get());
145 google_remote_engine->SetConfig(remote_engine_config);
147 session->recognizer = new SpeechRecognizerImpl(
148 this,
149 session_id,
150 config.continuous,
151 config.interim_results,
152 google_remote_engine);
153 #else
154 session->recognizer = new SpeechRecognizerImplAndroid(this, session_id);
155 #endif
156 return session_id;
159 void SpeechRecognitionManagerImpl::StartSession(int session_id) {
160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
161 if (!SessionExists(session_id))
162 return;
164 // If there is another active session, abort that.
165 if (primary_session_id_ != kSessionIDInvalid &&
166 primary_session_id_ != session_id) {
167 AbortSession(primary_session_id_);
170 primary_session_id_ = session_id;
172 if (delegate_) {
173 delegate_->CheckRecognitionIsAllowed(
174 session_id,
175 base::Bind(&SpeechRecognitionManagerImpl::RecognitionAllowedCallback,
176 weak_factory_.GetWeakPtr(),
177 session_id));
181 void SpeechRecognitionManagerImpl::RecognitionAllowedCallback(int session_id,
182 bool ask_user,
183 bool is_allowed) {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
185 if (!SessionExists(session_id))
186 return;
188 SessionsTable::iterator iter = sessions_.find(session_id);
189 DCHECK(iter != sessions_.end());
190 Session* session = iter->second;
192 if (session->abort_requested)
193 return;
195 if (ask_user) {
196 SpeechRecognitionSessionContext& context = session->context;
197 context.label = media_stream_manager_->MakeMediaAccessRequest(
198 context.render_process_id,
199 context.render_frame_id,
200 context.request_id,
201 StreamOptions(true, false),
202 GURL(context.context_name),
203 base::Bind(
204 &SpeechRecognitionManagerImpl::MediaRequestPermissionCallback,
205 weak_factory_.GetWeakPtr(), session_id));
206 return;
209 if (is_allowed) {
210 base::MessageLoop::current()->PostTask(
211 FROM_HERE,
212 base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent,
213 weak_factory_.GetWeakPtr(),
214 session_id,
215 EVENT_START));
216 } else {
217 OnRecognitionError(session_id, SpeechRecognitionError(
218 SPEECH_RECOGNITION_ERROR_NOT_ALLOWED));
219 base::MessageLoop::current()->PostTask(
220 FROM_HERE,
221 base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent,
222 weak_factory_.GetWeakPtr(),
223 session_id,
224 EVENT_ABORT));
228 void SpeechRecognitionManagerImpl::MediaRequestPermissionCallback(
229 int session_id,
230 const MediaStreamDevices& devices,
231 scoped_ptr<MediaStreamUIProxy> stream_ui) {
232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
234 SessionsTable::iterator iter = sessions_.find(session_id);
235 if (iter == sessions_.end())
236 return;
238 bool is_allowed = !devices.empty();
239 if (is_allowed) {
240 // Copy the approved devices array to the context for UI indication.
241 iter->second->context.devices = devices;
243 // Save the UI object.
244 iter->second->ui = stream_ui.Pass();
247 // Clear the label to indicate the request has been done.
248 iter->second->context.label.clear();
250 // Notify the recognition about the request result.
251 RecognitionAllowedCallback(iter->first, false, is_allowed);
254 void SpeechRecognitionManagerImpl::AbortSession(int session_id) {
255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
256 if (!SessionExists(session_id))
257 return;
259 SessionsTable::iterator iter = sessions_.find(session_id);
260 iter->second->ui.reset();
262 if (iter->second->abort_requested)
263 return;
265 iter->second->abort_requested = true;
267 base::MessageLoop::current()->PostTask(
268 FROM_HERE,
269 base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent,
270 weak_factory_.GetWeakPtr(),
271 session_id,
272 EVENT_ABORT));
275 void SpeechRecognitionManagerImpl::StopAudioCaptureForSession(int session_id) {
276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
277 if (!SessionExists(session_id))
278 return;
280 SessionsTable::iterator iter = sessions_.find(session_id);
281 iter->second->ui.reset();
283 base::MessageLoop::current()->PostTask(
284 FROM_HERE,
285 base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent,
286 weak_factory_.GetWeakPtr(),
287 session_id,
288 EVENT_STOP_CAPTURE));
291 // Here begins the SpeechRecognitionEventListener interface implementation,
292 // which will simply relay the events to the proper listener registered for the
293 // particular session and to the catch-all listener provided by the delegate
294 // (if any).
296 void SpeechRecognitionManagerImpl::OnRecognitionStart(int session_id) {
297 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
298 if (!SessionExists(session_id))
299 return;
301 SessionsTable::iterator iter = sessions_.find(session_id);
302 if (iter->second->ui) {
303 // Notify the UI that the devices are being used.
304 iter->second->ui->OnStarted(base::Closure(),
305 MediaStreamUIProxy::WindowIdCallback());
308 DCHECK_EQ(primary_session_id_, session_id);
309 if (SpeechRecognitionEventListener* delegate_listener = GetDelegateListener())
310 delegate_listener->OnRecognitionStart(session_id);
311 if (SpeechRecognitionEventListener* listener = GetListener(session_id))
312 listener->OnRecognitionStart(session_id);
315 void SpeechRecognitionManagerImpl::OnAudioStart(int session_id) {
316 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
317 if (!SessionExists(session_id))
318 return;
320 DCHECK_EQ(primary_session_id_, session_id);
321 if (SpeechRecognitionEventListener* delegate_listener = GetDelegateListener())
322 delegate_listener->OnAudioStart(session_id);
323 if (SpeechRecognitionEventListener* listener = GetListener(session_id))
324 listener->OnAudioStart(session_id);
327 void SpeechRecognitionManagerImpl::OnEnvironmentEstimationComplete(
328 int session_id) {
329 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
330 if (!SessionExists(session_id))
331 return;
333 DCHECK_EQ(primary_session_id_, session_id);
334 if (SpeechRecognitionEventListener* delegate_listener = GetDelegateListener())
335 delegate_listener->OnEnvironmentEstimationComplete(session_id);
336 if (SpeechRecognitionEventListener* listener = GetListener(session_id))
337 listener->OnEnvironmentEstimationComplete(session_id);
340 void SpeechRecognitionManagerImpl::OnSoundStart(int session_id) {
341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
342 if (!SessionExists(session_id))
343 return;
345 DCHECK_EQ(primary_session_id_, session_id);
346 if (SpeechRecognitionEventListener* delegate_listener = GetDelegateListener())
347 delegate_listener->OnSoundStart(session_id);
348 if (SpeechRecognitionEventListener* listener = GetListener(session_id))
349 listener->OnSoundStart(session_id);
352 void SpeechRecognitionManagerImpl::OnSoundEnd(int session_id) {
353 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
354 if (!SessionExists(session_id))
355 return;
357 if (SpeechRecognitionEventListener* delegate_listener = GetDelegateListener())
358 delegate_listener->OnSoundEnd(session_id);
359 if (SpeechRecognitionEventListener* listener = GetListener(session_id))
360 listener->OnSoundEnd(session_id);
363 void SpeechRecognitionManagerImpl::OnAudioEnd(int session_id) {
364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
365 if (!SessionExists(session_id))
366 return;
368 if (SpeechRecognitionEventListener* delegate_listener = GetDelegateListener())
369 delegate_listener->OnAudioEnd(session_id);
370 if (SpeechRecognitionEventListener* listener = GetListener(session_id))
371 listener->OnAudioEnd(session_id);
372 base::MessageLoop::current()->PostTask(
373 FROM_HERE,
374 base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent,
375 weak_factory_.GetWeakPtr(),
376 session_id,
377 EVENT_AUDIO_ENDED));
380 void SpeechRecognitionManagerImpl::OnRecognitionResults(
381 int session_id, const SpeechRecognitionResults& results) {
382 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
383 if (!SessionExists(session_id))
384 return;
386 if (SpeechRecognitionEventListener* delegate_listener = GetDelegateListener())
387 delegate_listener->OnRecognitionResults(session_id, results);
388 if (SpeechRecognitionEventListener* listener = GetListener(session_id))
389 listener->OnRecognitionResults(session_id, results);
392 void SpeechRecognitionManagerImpl::OnRecognitionError(
393 int session_id, const SpeechRecognitionError& error) {
394 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
395 if (!SessionExists(session_id))
396 return;
398 if (SpeechRecognitionEventListener* delegate_listener = GetDelegateListener())
399 delegate_listener->OnRecognitionError(session_id, error);
400 if (SpeechRecognitionEventListener* listener = GetListener(session_id))
401 listener->OnRecognitionError(session_id, error);
404 void SpeechRecognitionManagerImpl::OnAudioLevelsChange(
405 int session_id, float volume, float noise_volume) {
406 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
407 if (!SessionExists(session_id))
408 return;
410 if (SpeechRecognitionEventListener* delegate_listener = GetDelegateListener())
411 delegate_listener->OnAudioLevelsChange(session_id, volume, noise_volume);
412 if (SpeechRecognitionEventListener* listener = GetListener(session_id))
413 listener->OnAudioLevelsChange(session_id, volume, noise_volume);
416 void SpeechRecognitionManagerImpl::OnRecognitionEnd(int session_id) {
417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
418 if (!SessionExists(session_id))
419 return;
421 if (SpeechRecognitionEventListener* delegate_listener = GetDelegateListener())
422 delegate_listener->OnRecognitionEnd(session_id);
423 if (SpeechRecognitionEventListener* listener = GetListener(session_id))
424 listener->OnRecognitionEnd(session_id);
425 base::MessageLoop::current()->PostTask(
426 FROM_HERE,
427 base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent,
428 weak_factory_.GetWeakPtr(),
429 session_id,
430 EVENT_RECOGNITION_ENDED));
433 int SpeechRecognitionManagerImpl::GetSession(
434 int render_process_id, int render_view_id, int request_id) const {
435 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
436 SessionsTable::const_iterator iter;
437 for(iter = sessions_.begin(); iter != sessions_.end(); ++iter) {
438 const int session_id = iter->first;
439 const SpeechRecognitionSessionContext& context = iter->second->context;
440 if (context.render_process_id == render_process_id &&
441 context.render_view_id == render_view_id &&
442 context.request_id == request_id) {
443 return session_id;
446 return kSessionIDInvalid;
449 SpeechRecognitionSessionContext
450 SpeechRecognitionManagerImpl::GetSessionContext(int session_id) const {
451 return GetSession(session_id)->context;
454 void SpeechRecognitionManagerImpl::AbortAllSessionsForRenderProcess(
455 int render_process_id) {
456 // This method gracefully destroys sessions for the listener. However, since
457 // the listener itself is likely to be destroyed after this call, we avoid
458 // dispatching further events to it, marking the |listener_is_active| flag.
459 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
460 for (SessionsTable::iterator it = sessions_.begin(); it != sessions_.end();
461 ++it) {
462 Session* session = it->second;
463 if (session->context.render_process_id == render_process_id) {
464 AbortSession(session->id);
465 session->listener_is_active = false;
470 void SpeechRecognitionManagerImpl::AbortAllSessionsForRenderView(
471 int render_process_id,
472 int render_view_id) {
473 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
474 for (SessionsTable::iterator it = sessions_.begin(); it != sessions_.end();
475 ++it) {
476 Session* session = it->second;
477 if (session->context.render_process_id == render_process_id &&
478 session->context.render_view_id == render_view_id) {
479 AbortSession(session->id);
484 // ----------------------- Core FSM implementation ---------------------------
485 void SpeechRecognitionManagerImpl::DispatchEvent(int session_id,
486 FSMEvent event) {
487 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
489 // There are some corner cases in which the session might be deleted (due to
490 // an EndRecognition event) between a request (e.g. Abort) and its dispatch.
491 if (!SessionExists(session_id))
492 return;
494 Session* session = GetSession(session_id);
495 FSMState session_state = GetSessionState(session_id);
496 DCHECK_LE(session_state, SESSION_STATE_MAX_VALUE);
497 DCHECK_LE(event, EVENT_MAX_VALUE);
499 // Event dispatching must be sequential, otherwise it will break all the rules
500 // and the assumptions of the finite state automata model.
501 DCHECK(!is_dispatching_event_);
502 is_dispatching_event_ = true;
503 ExecuteTransitionAndGetNextState(session, session_state, event);
504 is_dispatching_event_ = false;
507 // This FSM handles the evolution of each session, from the viewpoint of the
508 // interaction with the user (that may be either the browser end-user which
509 // interacts with UI bubbles, or JS developer intracting with JS methods).
510 // All the events received by the SpeechRecognizer instances (one for each
511 // session) are always routed to the SpeechRecognitionEventListener(s)
512 // regardless the choices taken in this FSM.
513 void SpeechRecognitionManagerImpl::ExecuteTransitionAndGetNextState(
514 Session* session, FSMState session_state, FSMEvent event) {
515 // Note: since we're not tracking the state of the recognizer object, rather
516 // we're directly retrieving it (through GetSessionState), we see its events
517 // (that are AUDIO_ENDED and RECOGNITION_ENDED) after its state evolution
518 // (e.g., when we receive the AUDIO_ENDED event, the recognizer has just
519 // completed the transition from CAPTURING_AUDIO to WAITING_FOR_RESULT, thus
520 // we perceive the AUDIO_ENDED event in WAITING_FOR_RESULT).
521 // This makes the code below a bit tricky but avoids a lot of code for
522 // tracking and reconstructing asynchronously the state of the recognizer.
523 switch (session_state) {
524 case SESSION_STATE_IDLE:
525 switch (event) {
526 case EVENT_START:
527 return SessionStart(*session);
528 case EVENT_ABORT:
529 return SessionAbort(*session);
530 case EVENT_RECOGNITION_ENDED:
531 return SessionDelete(session);
532 case EVENT_STOP_CAPTURE:
533 return SessionStopAudioCapture(*session);
534 case EVENT_AUDIO_ENDED:
535 return;
537 break;
538 case SESSION_STATE_CAPTURING_AUDIO:
539 switch (event) {
540 case EVENT_STOP_CAPTURE:
541 return SessionStopAudioCapture(*session);
542 case EVENT_ABORT:
543 return SessionAbort(*session);
544 case EVENT_START:
545 return;
546 case EVENT_AUDIO_ENDED:
547 case EVENT_RECOGNITION_ENDED:
548 return NotFeasible(*session, event);
550 break;
551 case SESSION_STATE_WAITING_FOR_RESULT:
552 switch (event) {
553 case EVENT_ABORT:
554 return SessionAbort(*session);
555 case EVENT_AUDIO_ENDED:
556 return ResetCapturingSessionId(*session);
557 case EVENT_START:
558 case EVENT_STOP_CAPTURE:
559 return;
560 case EVENT_RECOGNITION_ENDED:
561 return NotFeasible(*session, event);
563 break;
565 return NotFeasible(*session, event);
568 SpeechRecognitionManagerImpl::FSMState
569 SpeechRecognitionManagerImpl::GetSessionState(int session_id) const {
570 Session* session = GetSession(session_id);
571 if (!session->recognizer.get() || !session->recognizer->IsActive())
572 return SESSION_STATE_IDLE;
573 if (session->recognizer->IsCapturingAudio())
574 return SESSION_STATE_CAPTURING_AUDIO;
575 return SESSION_STATE_WAITING_FOR_RESULT;
578 // ----------- Contract for all the FSM evolution functions below -------------
579 // - Are guaranteed to be executed in the IO thread;
580 // - Are guaranteed to be not reentrant (themselves and each other);
582 void SpeechRecognitionManagerImpl::SessionStart(const Session& session) {
583 DCHECK_EQ(primary_session_id_, session.id);
584 const MediaStreamDevices& devices = session.context.devices;
585 std::string device_id;
586 if (devices.empty()) {
587 // From the ask_user=false path, use the default device.
588 // TODO(xians): Abort the session after we do not need to support this path
589 // anymore.
590 device_id = media::AudioManagerBase::kDefaultDeviceId;
591 } else {
592 // From the ask_user=true path, use the selected device.
593 DCHECK_EQ(1u, devices.size());
594 DCHECK_EQ(MEDIA_DEVICE_AUDIO_CAPTURE, devices.front().type);
595 device_id = devices.front().id;
598 session.recognizer->StartRecognition(device_id);
601 void SpeechRecognitionManagerImpl::SessionAbort(const Session& session) {
602 if (primary_session_id_ == session.id)
603 primary_session_id_ = kSessionIDInvalid;
604 DCHECK(session.recognizer.get());
605 session.recognizer->AbortRecognition();
608 void SpeechRecognitionManagerImpl::SessionStopAudioCapture(
609 const Session& session) {
610 DCHECK(session.recognizer.get());
611 session.recognizer->StopAudioCapture();
614 void SpeechRecognitionManagerImpl::ResetCapturingSessionId(
615 const Session& session) {
616 DCHECK_EQ(primary_session_id_, session.id);
617 primary_session_id_ = kSessionIDInvalid;
620 void SpeechRecognitionManagerImpl::SessionDelete(Session* session) {
621 DCHECK(session->recognizer.get() == NULL || !session->recognizer->IsActive());
622 if (primary_session_id_ == session->id)
623 primary_session_id_ = kSessionIDInvalid;
624 if (!session->context.label.empty())
625 media_stream_manager_->CancelRequest(session->context.label);
626 sessions_.erase(session->id);
627 delete session;
630 void SpeechRecognitionManagerImpl::NotFeasible(const Session& session,
631 FSMEvent event) {
632 NOTREACHED() << "Unfeasible event " << event
633 << " in state " << GetSessionState(session.id)
634 << " for session " << session.id;
637 int SpeechRecognitionManagerImpl::GetNextSessionID() {
638 ++last_session_id_;
639 // Deal with wrapping of last_session_id_. (How civilized).
640 if (last_session_id_ <= 0)
641 last_session_id_ = 1;
642 return last_session_id_;
645 bool SpeechRecognitionManagerImpl::SessionExists(int session_id) const {
646 return sessions_.find(session_id) != sessions_.end();
649 SpeechRecognitionManagerImpl::Session*
650 SpeechRecognitionManagerImpl::GetSession(int session_id) const {
651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
652 SessionsTable::const_iterator iter = sessions_.find(session_id);
653 DCHECK(iter != sessions_.end());
654 return iter->second;
657 SpeechRecognitionEventListener* SpeechRecognitionManagerImpl::GetListener(
658 int session_id) const {
659 Session* session = GetSession(session_id);
660 if (session->listener_is_active && session->config.event_listener)
661 return session->config.event_listener.get();
662 return NULL;
665 SpeechRecognitionEventListener*
666 SpeechRecognitionManagerImpl::GetDelegateListener() const {
667 return delegate_.get() ? delegate_->GetEventListener() : NULL;
670 const SpeechRecognitionSessionConfig&
671 SpeechRecognitionManagerImpl::GetSessionConfig(int session_id) const {
672 return GetSession(session_id)->config;
675 bool SpeechRecognitionManagerImpl::HasAudioInputDevices() {
676 return audio_manager_->HasAudioInputDevices();
679 base::string16 SpeechRecognitionManagerImpl::GetAudioInputDeviceModel() {
680 return audio_manager_->GetAudioInputDeviceModel();
683 void SpeechRecognitionManagerImpl::ShowAudioInputSettings() {
684 // Since AudioManager::ShowAudioInputSettings can potentially launch external
685 // processes, do that in the FILE thread to not block the calling threads.
686 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
687 base::Bind(&ShowAudioInputSettingsOnFileThread,
688 audio_manager_));
691 SpeechRecognitionManagerImpl::Session::Session()
692 : id(kSessionIDInvalid),
693 abort_requested(false),
694 listener_is_active(true) {
697 SpeechRecognitionManagerImpl::Session::~Session() {
700 } // namespace content