Index: chrome/browser/speech/speech_input_extension_manager.cc |
=================================================================== |
--- chrome/browser/speech/speech_input_extension_manager.cc (revision 195413) |
+++ chrome/browser/speech/speech_input_extension_manager.cc (working copy) |
@@ -1,719 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/speech/speech_input_extension_manager.h" |
- |
-#include "base/bind.h" |
-#include "base/json/json_writer.h" |
-#include "base/lazy_instance.h" |
-#include "base/utf_string_conversions.h" |
-#include "base/values.h" |
-#include "chrome/browser/extensions/event_router.h" |
-#include "chrome/browser/extensions/extension_function_registry.h" |
-#include "chrome/browser/extensions/extension_host.h" |
-#include "chrome/browser/extensions/extension_process_manager.h" |
-#include "chrome/browser/extensions/extension_service.h" |
-#include "chrome/browser/extensions/extension_system.h" |
-#include "chrome/browser/profiles/profile.h" |
-#include "chrome/browser/profiles/profile_dependency_manager.h" |
-#include "chrome/browser/profiles/profile_keyed_service.h" |
-#include "chrome/browser/profiles/profile_keyed_service_factory.h" |
-#include "chrome/browser/speech/speech_input_extension_api.h" |
-#include "chrome/common/chrome_notification_types.h" |
-#include "chrome/common/extensions/extension.h" |
-#include "content/public/browser/browser_thread.h" |
-#include "content/public/browser/notification_registrar.h" |
-#include "content/public/browser/notification_service.h" |
-#include "content/public/browser/render_process_host.h" |
-#include "content/public/browser/speech_recognition_manager.h" |
-#include "content/public/browser/speech_recognition_session_config.h" |
-#include "content/public/browser/speech_recognition_session_context.h" |
-#include "content/public/common/speech_recognition_error.h" |
-#include "content/public/common/speech_recognition_result.h" |
-#include "net/url_request/url_request_context_getter.h" |
- |
-using content::BrowserThread; |
-using content::SpeechRecognitionHypothesis; |
-using content::SpeechRecognitionManager; |
- |
-namespace { |
- |
-const char kErrorNoRecordingDeviceFound[] = "noRecordingDeviceFound"; |
-const char kErrorRecordingDeviceInUse[] = "recordingDeviceInUse"; |
-const char kErrorUnableToStart[] = "unableToStart"; |
-const char kErrorRequestDenied[] = "requestDenied"; |
-const char kErrorRequestInProgress[] = "requestInProgress"; |
-const char kErrorInvalidOperation[] = "invalidOperation"; |
- |
-const char kErrorCodeKey[] = "code"; |
-const char kErrorCaptureError[] = "captureError"; |
-const char kErrorNetworkError[] = "networkError"; |
-const char kErrorNoSpeechHeard[] = "noSpeechHeard"; |
-const char kErrorNoResults[] = "noResults"; |
- |
-const char kUtteranceKey[] = "utterance"; |
-const char kConfidenceKey[] = "confidence"; |
-const char kHypothesesKey[] = "hypotheses"; |
- |
-const char kOnErrorEvent[] = "experimental.speechInput.onError"; |
-const char kOnResultEvent[] = "experimental.speechInput.onResult"; |
-const char kOnSoundStartEvent[] = "experimental.speechInput.onSoundStart"; |
-const char kOnSoundEndEvent[] = "experimental.speechInput.onSoundEnd"; |
- |
-} |
- |
-SpeechInputExtensionInterface::SpeechInputExtensionInterface() { |
-} |
- |
-SpeechInputExtensionInterface::~SpeechInputExtensionInterface() { |
-} |
- |
-SpeechInputExtensionManager::SpeechInputExtensionManager(Profile* profile) |
- : profile_(profile), |
- state_(kIdle), |
- registrar_(new content::NotificationRegistrar), |
- speech_interface_(NULL), |
- is_recognition_in_progress_(false), |
- speech_recognition_session_id_( |
- SpeechRecognitionManager::kSessionIDInvalid) { |
- registrar_->Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
- content::Source<Profile>(profile_)); |
-} |
- |
-SpeechInputExtensionManager::~SpeechInputExtensionManager() { |
-} |
- |
-SpeechInputExtensionManager* SpeechInputExtensionManager::GetForProfile( |
- Profile* profile) { |
- extensions::SpeechInputAPI* speech_input_api = |
- extensions::ProfileKeyedAPIFactory<extensions::SpeechInputAPI>:: |
- GetForProfile(profile); |
- if (!speech_input_api) |
- return NULL; |
- return speech_input_api->manager(); |
-} |
- |
-void SpeechInputExtensionManager::Observe(int type, |
- const content::NotificationSource& source, |
- const content::NotificationDetails& details) { |
- if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) { |
- ExtensionUnloaded( |
- content::Details<extensions::UnloadedExtensionInfo>(details)-> |
- extension->id()); |
- } else { |
- NOTREACHED(); |
- } |
-} |
- |
-void SpeechInputExtensionManager::ShutdownOnUIThread() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- VLOG(1) << "Profile shutting down."; |
- |
- // Note: Unretained(this) is safe, also if we are freed in the meanwhile. |
- // It is used by the SR manager just for comparing the raw pointer and remove |
- // the associated sessions. |
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::AbortAllSessionsOnIOThread, |
- base::Unretained(this))); |
- |
- base::AutoLock auto_lock(state_lock_); |
- DCHECK(state_ != kShutdown); |
- if (state_ != kIdle) { |
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); |
- } |
- state_ = kShutdown; |
- VLOG(1) << "Entering the shutdown sink state."; |
- registrar_.reset(); |
- profile_ = NULL; |
-} |
- |
-void SpeechInputExtensionManager::AbortAllSessionsOnIOThread() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- // TODO(primiano): The following check should not be really needed if the |
- // SpeechRecognitionManager and this class are destroyed in the correct order |
- // (this class first), as it is in current chrome implementation. |
- // However, it seems the some ChromiumOS tests violate the destruction order |
- // envisaged by browser_main_loop, so SpeechRecognitionmanager could have been |
- // freed by now. |
- if (SpeechRecognitionManager* mgr = SpeechRecognitionManager::GetInstance()) |
- mgr->AbortAllSessionsForListener(this); |
-} |
- |
-void SpeechInputExtensionManager::ExtensionUnloaded( |
- const std::string& extension_id) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- |
- base::AutoLock auto_lock(state_lock_); |
- if (state_ == kShutdown) |
- return; |
- |
- VLOG(1) << "Extension unloaded. Requesting to enforce stop..."; |
- if (extension_id_in_use_ == extension_id) { |
- if (state_ != kIdle) { |
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); |
- } |
- } |
-} |
- |
-void SpeechInputExtensionManager::SetSpeechInputExtensionInterface( |
- SpeechInputExtensionInterface* speech_interface) { |
- speech_interface_ = speech_interface; |
-} |
- |
-SpeechInputExtensionInterface* |
- SpeechInputExtensionManager::GetSpeechInputExtensionInterface() { |
- return speech_interface_ ? speech_interface_ : this; |
-} |
- |
-void SpeechInputExtensionManager::ResetToIdleState() { |
- VLOG(1) << "State changed to idle. Deassociating any extensions."; |
- state_ = kIdle; |
- extension_id_in_use_.clear(); |
-} |
- |
-int SpeechInputExtensionManager::GetRenderProcessIDForExtension( |
- const std::string& extension_id) const { |
- ExtensionProcessManager* epm = |
- extensions::ExtensionSystem::Get(profile_)->process_manager(); |
- DCHECK(epm); |
- extensions::ExtensionHost* eh = |
- epm->GetBackgroundHostForExtension(extension_id); |
- DCHECK(eh); |
- content::RenderProcessHost* rph = eh->render_process_host(); |
- DCHECK(rph); |
- return rph->GetID(); |
-} |
- |
-void SpeechInputExtensionManager::OnRecognitionResults( |
- int session_id, |
- const content::SpeechRecognitionResults& results) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- DCHECK_EQ(session_id, speech_recognition_session_id_); |
- |
- // Stopping will start the disassociation with the extension. |
- // Make a copy to report the results to the proper one. |
- std::string extension_id = extension_id_in_use_; |
- ForceStopOnIOThread(); |
- |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::SetRecognitionResultsOnUIThread, |
- this, results, extension_id)); |
-} |
- |
-void SpeechInputExtensionManager::SetRecognitionResultsOnUIThread( |
- const content::SpeechRecognitionResults& results, |
- const std::string& extension_id) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- |
- content::SpeechRecognitionResults::const_iterator it = results.begin(); |
- for (; it != results.end(); ++it) { |
- const content::SpeechRecognitionResult& result = (*it); |
- |
- scoped_ptr<ListValue> args(new ListValue()); |
- DictionaryValue* js_event = new DictionaryValue(); |
- args->Append(js_event); |
- |
- ListValue* js_hypothesis_array = new ListValue(); |
- js_event->Set(kHypothesesKey, js_hypothesis_array); |
- |
- for (size_t i = 0; i < result.hypotheses.size(); ++i) { |
- const SpeechRecognitionHypothesis& hypothesis = result.hypotheses[i]; |
- |
- DictionaryValue* js_hypothesis_object = new DictionaryValue(); |
- js_hypothesis_array->Append(js_hypothesis_object); |
- |
- js_hypothesis_object->SetString(kUtteranceKey, |
- UTF16ToUTF8(hypothesis.utterance)); |
- js_hypothesis_object->SetDouble(kConfidenceKey, |
- hypothesis.confidence); |
- } |
- |
- DispatchEventToExtension(extension_id, kOnResultEvent, args.Pass()); |
- } |
-} |
- |
-void SpeechInputExtensionManager::OnRecognitionStart(int session_id) { |
- DCHECK_EQ(session_id, speech_recognition_session_id_); |
-} |
- |
-void SpeechInputExtensionManager::OnAudioStart(int session_id) { |
- VLOG(1) << "OnAudioStart"; |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- DCHECK_EQ(session_id, speech_recognition_session_id_); |
- |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread, |
- this)); |
-} |
- |
-void SpeechInputExtensionManager::OnAudioEnd(int session_id) { |
-} |
- |
-void SpeechInputExtensionManager::OnRecognitionEnd(int session_id) { |
- // In the very exceptional case in which we requested a new recognition before |
- // the previous one ended, don't clobber the speech_recognition_session_id_. |
- if (speech_recognition_session_id_ == session_id) { |
- is_recognition_in_progress_ = false; |
- speech_recognition_session_id_ = |
- SpeechRecognitionManager::kSessionIDInvalid; |
- } |
-} |
- |
-void SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- |
- base::AutoLock auto_lock(state_lock_); |
- if (state_ == kShutdown) |
- return; |
- |
- DCHECK_EQ(state_, kStarting); |
- VLOG(1) << "State changed to recording"; |
- state_ = kRecording; |
- |
- DCHECK(profile_); |
- |
- VLOG(1) << "Sending start notification"; |
- content::NotificationService::current()->Notify( |
- chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED, |
- content::Source<Profile>(profile_), |
- content::Details<std::string>(&extension_id_in_use_)); |
-} |
- |
-void SpeechInputExtensionManager::OnRecognitionError( |
- int session_id, const content::SpeechRecognitionError& error) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- DCHECK_EQ(session_id, speech_recognition_session_id_); |
- VLOG(1) << "OnRecognitionError: " << error.code; |
- |
- base::AutoLock auto_lock(state_lock_); |
- if (state_ == kShutdown) |
- return; |
- |
- GetSpeechInputExtensionInterface()->StopRecording(true); |
- |
- std::string event_error_code; |
- bool report_to_event = true; |
- |
- switch (error.code) { |
- case content::SPEECH_RECOGNITION_ERROR_NONE: |
- break; |
- |
- case content::SPEECH_RECOGNITION_ERROR_ABORTED: |
- // ERROR_ABORTED is received whenever AbortSession is called on the |
- // manager. However, we want propagate the error only if it is triggered |
- // by an external cause (another recognition started, aborting us), thus |
- // only if it occurs while we are capturing audio. |
- if (state_ == kRecording) |
- event_error_code = kErrorCaptureError; |
- break; |
- |
- case content::SPEECH_RECOGNITION_ERROR_AUDIO: |
- if (state_ == kStarting) { |
- event_error_code = kErrorUnableToStart; |
- report_to_event = false; |
- } else { |
- event_error_code = kErrorCaptureError; |
- } |
- break; |
- |
- case content::SPEECH_RECOGNITION_ERROR_NETWORK: |
- event_error_code = kErrorNetworkError; |
- break; |
- |
- case content::SPEECH_RECOGNITION_ERROR_BAD_GRAMMAR: |
- // No error is returned on invalid language, for example. |
- // To avoid confusion about when this is would be fired, the invalid |
- // params error is not being exposed to the onError event. |
- event_error_code = kErrorUnableToStart; |
- break; |
- |
- case content::SPEECH_RECOGNITION_ERROR_NO_SPEECH: |
- event_error_code = kErrorNoSpeechHeard; |
- break; |
- |
- case content::SPEECH_RECOGNITION_ERROR_NO_MATCH: |
- event_error_code = kErrorNoResults; |
- break; |
- |
- // The remaining kErrorAborted case should never be returned by the server. |
- default: |
- NOTREACHED(); |
- } |
- |
- if (!event_error_code.empty()) { |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::DispatchError, |
- this, event_error_code, report_to_event)); |
- } |
-} |
- |
-void SpeechInputExtensionManager::OnEnvironmentEstimationComplete( |
- int session_id) { |
- DCHECK_EQ(session_id, speech_recognition_session_id_); |
-} |
- |
-void SpeechInputExtensionManager::OnSoundStart(int session_id) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- DCHECK_EQ(session_id, speech_recognition_session_id_); |
- VLOG(1) << "OnSoundStart"; |
- |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension, |
- this, extension_id_in_use_, std::string(kOnSoundStartEvent), |
- Passed(scoped_ptr<ListValue>(new ListValue())))); |
-} |
- |
-void SpeechInputExtensionManager::OnSoundEnd(int session_id) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- VLOG(1) << "OnSoundEnd"; |
- |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension, |
- this, extension_id_in_use_, std::string(kOnSoundEndEvent), |
- Passed(scoped_ptr<ListValue>(new ListValue())))); |
-} |
- |
-void SpeechInputExtensionManager::DispatchEventToExtension( |
- const std::string& extension_id, const std::string& event_name, |
- scoped_ptr<ListValue> event_args) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- |
- base::AutoLock auto_lock(state_lock_); |
- if (state_ == kShutdown) |
- return; |
- |
- if (profile_ && extensions::ExtensionSystem::Get(profile_)->event_router()) { |
- scoped_ptr<extensions::Event> event(new extensions::Event( |
- event_name, event_args.Pass())); |
- event->restrict_to_profile = profile_; |
- extensions::ExtensionSystem::Get(profile_)->event_router()-> |
- DispatchEventToExtension(extension_id, event.Pass()); |
- } |
-} |
- |
-void SpeechInputExtensionManager::DispatchError( |
- const std::string& error, bool dispatch_event) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- |
- std::string extension_id; |
- { |
- base::AutoLock auto_lock(state_lock_); |
- if (state_ == kShutdown) |
- return; |
- |
- extension_id = extension_id_in_use_; |
- ResetToIdleState(); |
- |
- // Will set the error property in the ongoing extension function calls. |
- ExtensionError details(extension_id, error); |
- content::NotificationService::current()->Notify( |
- chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_FAILED, |
- content::Source<Profile>(profile_), |
- content::Details<ExtensionError>(&details)); |
- } |
- |
- // Used for errors that are also reported via the onError event. |
- if (dispatch_event) { |
- scoped_ptr<ListValue> args(new ListValue()); |
- DictionaryValue* js_error = new DictionaryValue(); |
- args->Append(js_error); |
- js_error->SetString(kErrorCodeKey, error); |
- DispatchEventToExtension(extension_id, kOnErrorEvent, args.Pass()); |
- } |
-} |
- |
-bool SpeechInputExtensionManager::Start( |
- const std::string& extension_id, const std::string& language, |
- const std::string& grammar, bool filter_profanities, std::string* error) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- DCHECK(error); |
- VLOG(1) << "Requesting start (UI thread)"; |
- |
- base::AutoLock auto_lock(state_lock_); |
- if (state_ == kShutdown || |
- (!extension_id_in_use_.empty() && extension_id_in_use_ != extension_id)) { |
- *error = kErrorRequestDenied; |
- return false; |
- } |
- |
- switch (state_) { |
- case kIdle: |
- break; |
- |
- case kStarting: |
- *error = kErrorRequestInProgress; |
- return false; |
- |
- case kRecording: |
- case kStopping: |
- *error = kErrorInvalidOperation; |
- return false; |
- |
- default: |
- NOTREACHED(); |
- } |
- |
- const extensions::Extension* extension = |
- extensions::ExtensionSystem::Get(profile_)->extension_service()-> |
- GetExtensionById(extension_id, true); |
- DCHECK(extension); |
- const std::string& extension_name = extension->name(); |
- |
- extension_id_in_use_ = extension_id; |
- VLOG(1) << "State changed to starting"; |
- state_ = kStarting; |
- |
- scoped_refptr<net::URLRequestContextGetter> url_request_context_getter = |
- profile_->GetRequestContext(); |
- |
- const int render_process_id = GetRenderProcessIDForExtension(extension_id); |
- |
- BrowserThread::PostTask( |
- BrowserThread::IO, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::StartOnIOThread, this, |
- url_request_context_getter, extension_name, language, grammar, |
- filter_profanities, render_process_id)); |
- return true; |
-} |
- |
-void SpeechInputExtensionManager::StartOnIOThread( |
- scoped_refptr<net::URLRequestContextGetter> context_getter, |
- const std::string& extension_name, |
- const std::string& language, |
- const std::string& grammar, |
- bool filter_profanities, |
- int render_process_id) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- VLOG(1) << "Requesting start (IO thread)"; |
- |
- // Everything put inside the lock to ensure the validity of context_getter, |
- // guaranteed while not in the shutdown state. Any ongoing or recognition |
- // request will be requested to be aborted when entering the shutdown state. |
- base::AutoLock auto_lock(state_lock_); |
- if (state_ == kShutdown) |
- return; |
- |
- // TODO(primiano): These two checks below could be avoided, since they are |
- // already handled in the speech recognition classes. However, since the |
- // speech input extensions tests are bypassing the manager, we need them to |
- // pass the tests. |
- if (!GetSpeechInputExtensionInterface()->HasAudioInputDevices()) { |
- BrowserThread::PostTask( |
- BrowserThread::UI, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::DispatchError, this, |
- std::string(kErrorNoRecordingDeviceFound), false)); |
- return; |
- } |
- |
- if (GetSpeechInputExtensionInterface()->IsCapturingAudio()) { |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::DispatchError, this, |
- std::string(kErrorRecordingDeviceInUse), false)); |
- return; |
- } |
- |
- GetSpeechInputExtensionInterface()->StartRecording(this, |
- context_getter, |
- extension_name, |
- language, |
- grammar, |
- filter_profanities, |
- render_process_id); |
-} |
- |
-bool SpeechInputExtensionManager::HasAudioInputDevices() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- return SpeechRecognitionManager::GetInstance()->HasAudioInputDevices(); |
-} |
- |
-bool SpeechInputExtensionManager::IsCapturingAudio() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- return SpeechRecognitionManager::GetInstance()->IsCapturingAudio(); |
-} |
- |
-void SpeechInputExtensionManager::IsRecording( |
- const IsRecordingCallback& callback) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- BrowserThread::PostTask( |
- BrowserThread::IO, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::IsRecordingOnIOThread, |
- this, callback)); |
-} |
- |
-void SpeechInputExtensionManager::IsRecordingOnIOThread( |
- const IsRecordingCallback& callback) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- |
- bool result = GetSpeechInputExtensionInterface()->IsCapturingAudio(); |
- |
- BrowserThread::PostTask( |
- BrowserThread::UI, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::IsRecordingOnUIThread, |
- this, callback, result)); |
-} |
- |
-void SpeechInputExtensionManager::IsRecordingOnUIThread( |
- const IsRecordingCallback& callback, |
- bool result) { |
- BrowserThread::CurrentlyOn(BrowserThread::UI); |
- callback.Run(result); |
-} |
- |
-void SpeechInputExtensionManager::StartRecording( |
- content::SpeechRecognitionEventListener* listener, |
- net::URLRequestContextGetter* context_getter, |
- const std::string& extension_name, |
- const std::string& language, |
- const std::string& grammar, |
- bool filter_profanities, |
- int render_process_id) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- |
- content::SpeechRecognitionSessionContext context; |
- context.requested_by_page_element = false; |
- context.render_process_id = render_process_id; |
- context.context_name = extension_name; |
- |
- content::SpeechRecognitionSessionConfig config; |
- config.language = language; |
- config.grammars.push_back(content::SpeechRecognitionGrammar(grammar)); |
- config.initial_context = context; |
- config.url_request_context_getter = context_getter; |
- config.filter_profanities = filter_profanities; |
- config.event_listener = listener; |
- |
- DCHECK(!is_recognition_in_progress_); |
- SpeechRecognitionManager& manager = *SpeechRecognitionManager::GetInstance(); |
- speech_recognition_session_id_ = |
- manager.CreateSession(config); |
- DCHECK_NE(speech_recognition_session_id_, |
- SpeechRecognitionManager::kSessionIDInvalid); |
- is_recognition_in_progress_ = true; |
- manager.StartSession(speech_recognition_session_id_); |
-} |
- |
-bool SpeechInputExtensionManager::HasValidRecognizer() { |
- if (!is_recognition_in_progress_) |
- return false; |
- return SpeechRecognitionManager::GetInstance()->IsCapturingAudio(); |
-} |
- |
-bool SpeechInputExtensionManager::Stop(const std::string& extension_id, |
- std::string* error) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- DCHECK(error); |
- VLOG(1) << "Requesting stop (UI thread)"; |
- |
- base::AutoLock auto_lock(state_lock_); |
- if (state_ == kShutdown || |
- (!extension_id_in_use_.empty() && extension_id_in_use_ != extension_id)) { |
- *error = kErrorRequestDenied; |
- return false; |
- } |
- |
- switch (state_) { |
- case kRecording: |
- break; |
- |
- case kStopping: |
- *error = kErrorRequestInProgress; |
- return false; |
- |
- case kIdle: |
- case kStarting: |
- *error = kErrorInvalidOperation; |
- return false; |
- |
- default: |
- NOTREACHED(); |
- } |
- |
- // Guarded by the state lock. |
- DCHECK(GetSpeechInputExtensionInterface()->HasValidRecognizer()); |
- |
- VLOG(1) << "State changed to stopping"; |
- state_ = kStopping; |
- |
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); |
- return true; |
-} |
- |
-void SpeechInputExtensionManager::ForceStopOnIOThread() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- VLOG(1) << "Requesting forced stop (IO thread)"; |
- |
- base::AutoLock auto_lock(state_lock_); |
- DCHECK(state_ != kIdle); |
- |
- GetSpeechInputExtensionInterface()->StopRecording(false); |
- |
- if (state_ == kShutdown) |
- return; |
- |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- base::Bind(&SpeechInputExtensionManager::StopSucceededOnUIThread, this)); |
-} |
- |
-void SpeechInputExtensionManager::StopRecording(bool recognition_failed) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- if (!is_recognition_in_progress_) |
- return; |
- DCHECK_NE(speech_recognition_session_id_, |
- SpeechRecognitionManager::kSessionIDInvalid); |
- SpeechRecognitionManager::GetInstance()->AbortSession( |
- speech_recognition_session_id_); |
-} |
- |
-void SpeechInputExtensionManager::StopSucceededOnUIThread() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- VLOG(1) << "Stop succeeded (UI thread)"; |
- |
- base::AutoLock auto_lock(state_lock_); |
- if (state_ == kShutdown) |
- return; |
- |
- std::string extension_id = extension_id_in_use_; |
- ResetToIdleState(); |
- |
- content::NotificationService::current()->Notify( |
- chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED, |
- // Guarded by the state_ == kShutdown check. |
- content::Source<Profile>(profile_), |
- content::Details<std::string>(&extension_id)); |
-} |
- |
-void SpeechInputExtensionManager::OnAudioLevelsChange(int session_id, |
- float volume, |
- float noise_volume) {} |
- |
-namespace extensions { |
- |
-SpeechInputAPI::SpeechInputAPI(Profile* profile) |
- : manager_(new SpeechInputExtensionManager(profile)) { |
- ExtensionFunctionRegistry* registry = |
- ExtensionFunctionRegistry::GetInstance(); |
- registry->RegisterFunction<StartSpeechInputFunction>(); |
- registry->RegisterFunction<StopSpeechInputFunction>(); |
- registry->RegisterFunction<IsRecordingSpeechInputFunction>(); |
-} |
- |
-SpeechInputAPI::~SpeechInputAPI() { |
-} |
- |
-void SpeechInputAPI::Shutdown() { |
- manager_->ShutdownOnUIThread(); |
-} |
- |
-static base::LazyInstance<ProfileKeyedAPIFactory<SpeechInputAPI> > |
- g_factory = LAZY_INSTANCE_INITIALIZER; |
- |
-// static |
-ProfileKeyedAPIFactory<SpeechInputAPI>* SpeechInputAPI::GetFactoryInstance() { |
- return &g_factory.Get(); |
-} |
- |
-} // namespace extensions |