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

Unified Diff: chrome/browser/speech/speech_input_extension_manager.cc

Issue 10377082: SpeechInputExtensionManager now interface with SpeechRecognitionManagerDelegate (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase before dcommit Created 8 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/speech/speech_input_extension_manager.cc
diff --git a/chrome/browser/speech/speech_input_extension_manager.cc b/chrome/browser/speech/speech_input_extension_manager.cc
index 047f1de60be447c604881ee0a860fd15d80ff8d2..abc92509057e8ad91bf095a8aafcaed732c3866a 100644
--- a/chrome/browser/speech/speech_input_extension_manager.cc
+++ b/chrome/browser/speech/speech_input_extension_manager.cc
@@ -15,7 +15,6 @@
#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_recognition_tray_icon_controller.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/pref_names.h"
@@ -23,9 +22,11 @@
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/speech_recognition_manager.h"
-#include "content/public/browser/speech_recognizer.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;
@@ -55,12 +56,6 @@ const char kOnResultEvent[] = "experimental.speechInput.onResult";
const char kOnSoundStartEvent[] = "experimental.speechInput.onSoundStart";
const char kOnSoundEndEvent[] = "experimental.speechInput.onSoundEnd";
-// Session id provided to the speech recognizer. Since only one extension can
-// be recording on the same time a constant value is enough as id.
-// TODO(primiano) this will not be valid anymore once speech input extension
-// will use the SpeechRecognitionManager and not the SpeechRecognizer directly.
-static const int kSpeechInputSessionId = 1;
-
// Wrap an SpeechInputExtensionManager using scoped_refptr to avoid
// assertion failures on destruction because of not using release().
class SpeechInputExtensionManagerWrapper : public ProfileKeyedService {
@@ -157,7 +152,10 @@ SpeechInputExtensionManager::SpeechInputExtensionManager(Profile* profile)
: profile_(profile),
state_(kIdle),
registrar_(new content::NotificationRegistrar),
- speech_interface_(NULL) {
+ 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_));
}
@@ -194,11 +192,17 @@ 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(&SpeechRecognitionManager::AbortAllSessionsForListener,
+ base::Unretained(SpeechRecognitionManager::GetInstance()),
+ base::Unretained(this)));
+
base::AutoLock auto_lock(state_lock_);
DCHECK(state_ != kShutdown);
if (state_ != kIdle) {
- DCHECK(notification_.get());
- notification_->Hide();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this));
}
@@ -245,7 +249,7 @@ void SpeechInputExtensionManager::OnRecognitionResult(
int session_id,
const content::SpeechRecognitionResult& result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK_EQ(session_id, kSpeechInputSessionId);
+ 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.
@@ -288,13 +292,13 @@ void SpeechInputExtensionManager::SetRecognitionResultOnUIThread(
}
void SpeechInputExtensionManager::OnRecognitionStart(int session_id) {
- DCHECK_EQ(session_id, kSpeechInputSessionId);
+ 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, kSpeechInputSessionId);
+ DCHECK_EQ(session_id, speech_recognition_session_id_);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread,
@@ -302,11 +306,16 @@ void SpeechInputExtensionManager::OnAudioStart(int session_id) {
}
void SpeechInputExtensionManager::OnAudioEnd(int session_id) {
- DCHECK_EQ(session_id, kSpeechInputSessionId);
}
void SpeechInputExtensionManager::OnRecognitionEnd(int session_id) {
- DCHECK_EQ(session_id, kSpeechInputSessionId);
+ // 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() {
@@ -320,21 +329,9 @@ void SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread() {
VLOG(1) << "State changed to recording";
state_ = kRecording;
- const extensions::Extension* extension = profile_->GetExtensionService()->
- GetExtensionById(extension_id_in_use_, true);
- DCHECK(extension);
-
- bool show_notification = !profile_->GetPrefs()->GetBoolean(
- prefs::kSpeechInputTrayNotificationShown);
-
- if (!notification_.get())
- notification_ = new SpeechRecognitionTrayIconController();
- notification_->Show(UTF8ToUTF16(extension->name()), show_notification);
-
- if (show_notification) {
- profile_->GetPrefs()->SetBoolean(
- prefs::kSpeechInputTrayNotificationShown, true);
- }
+ DCHECK(profile_);
+ profile_->GetPrefs()->SetBoolean(
+ prefs::kSpeechInputTrayNotificationShown, true);
VLOG(1) << "Sending start notification";
content::NotificationService::current()->Notify(
@@ -346,20 +343,13 @@ void SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread() {
void SpeechInputExtensionManager::OnRecognitionError(
int session_id, const content::SpeechRecognitionError& error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK_EQ(session_id, kSpeechInputSessionId);
-
- // Simply return in case of an ERROR_ABORTED, since it is not contemplated
- // in the speech input extensions architecture.
- if (error.code == content::SPEECH_RECOGNITION_ERROR_ABORTED)
- return;
-
+ DCHECK_EQ(session_id, speech_recognition_session_id_);
VLOG(1) << "OnRecognitionError: " << error.code;
base::AutoLock auto_lock(state_lock_);
if (state_ == kShutdown)
return;
- // Release the recognizer object.
GetSpeechInputExtensionInterface()->StopRecording(true);
std::string event_error_code;
@@ -369,6 +359,15 @@ void SpeechInputExtensionManager::OnRecognitionError(
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;
@@ -411,12 +410,12 @@ void SpeechInputExtensionManager::OnRecognitionError(
void SpeechInputExtensionManager::OnEnvironmentEstimationComplete(
int session_id) {
- DCHECK_EQ(session_id, kSpeechInputSessionId);
+ DCHECK_EQ(session_id, speech_recognition_session_id_);
}
void SpeechInputExtensionManager::OnSoundStart(int session_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK_EQ(session_id, kSpeechInputSessionId);
+ DCHECK_EQ(session_id, speech_recognition_session_id_);
VLOG(1) << "OnSoundStart";
std::string json_args;
@@ -428,7 +427,6 @@ void SpeechInputExtensionManager::OnSoundStart(int session_id) {
void SpeechInputExtensionManager::OnSoundEnd(int session_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK_EQ(session_id, kSpeechInputSessionId);
VLOG(1) << "OnSoundEnd";
std::string json_args;
@@ -471,11 +469,6 @@ void SpeechInputExtensionManager::DispatchError(
if (state_ == kShutdown)
return;
- if (state_ == kRecording) {
- DCHECK(notification_.get());
- notification_->Hide();
- }
-
extension_id = extension_id_in_use_;
ResetToIdleState();
@@ -531,23 +524,37 @@ bool SpeechInputExtensionManager::Start(
NOTREACHED();
}
+ const extensions::Extension* extension = profile_->GetExtensionService()->
+ GetExtensionById(extension_id, true);
+ DCHECK(extension);
+ const string16& extension_name = UTF8ToUTF16(extension->name());
+
extension_id_in_use_ = extension_id;
VLOG(1) << "State changed to starting";
state_ = kStarting;
+ // Checks if the security notification balloon has been already shown (only
+ // once for a profile). It is reset on DidStartReceivingAudioOnUIThread.
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
+ profile_->GetRequestContext();
+ const bool show_notification = !profile_->GetPrefs()->GetBoolean(
+ prefs::kSpeechInputTrayNotificationShown);
+
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&SpeechInputExtensionManager::StartOnIOThread, this,
- profile_->GetRequestContext(), language, grammar,
- filter_profanities));
+ url_request_context_getter, extension_name, language, grammar,
+ filter_profanities, show_notification));
return true;
}
void SpeechInputExtensionManager::StartOnIOThread(
- net::URLRequestContextGetter* context_getter,
+ scoped_refptr<net::URLRequestContextGetter> context_getter,
+ const string16& extension_name,
const std::string& language,
const std::string& grammar,
- bool filter_profanities) {
+ bool filter_profanities,
+ bool show_notification) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
VLOG(1) << "Requesting start (IO thread)";
@@ -558,6 +565,12 @@ void SpeechInputExtensionManager::StartOnIOThread(
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. A complete unit test which puts all the pieces together,
+ // mocking just the endpoints (the audio input controller and the URL fetcher)
+ // should be written.
if (!GetSpeechInputExtensionInterface()->HasAudioInputDevices()) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
@@ -573,9 +586,13 @@ void SpeechInputExtensionManager::StartOnIOThread(
return;
}
- GetSpeechInputExtensionInterface()->StartRecording(
- this, context_getter, kSpeechInputSessionId, language, grammar,
- filter_profanities);
+ GetSpeechInputExtensionInterface()->StartRecording(this,
+ context_getter,
+ extension_name,
+ language,
+ grammar,
+ filter_profanities,
+ show_notification);
}
bool SpeechInputExtensionManager::HasAudioInputDevices() {
@@ -602,6 +619,7 @@ void SpeechInputExtensionManager::IsRecordingOnIOThread(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
bool result = GetSpeechInputExtensionInterface()->IsCapturingAudio();
+
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&SpeechInputExtensionManager::IsRecordingOnUIThread,
@@ -618,20 +636,41 @@ void SpeechInputExtensionManager::IsRecordingOnUIThread(
void SpeechInputExtensionManager::StartRecording(
content::SpeechRecognitionEventListener* listener,
net::URLRequestContextGetter* context_getter,
- int session_id,
+ const string16& extension_name,
const std::string& language,
const std::string& grammar,
- bool filter_profanities) {
+ bool filter_profanities,
+ bool show_notification) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(!recognizer_);
- recognizer_ = content::SpeechRecognizer::Create(
- listener, session_id, language, grammar, context_getter,
- filter_profanities, "", "");
- recognizer_->StartRecognition();
+
+ content::SpeechRecognitionSessionContext context;
+ context.requested_by_page_element = false;
+ context.is_first_request_for_context = show_notification;
+ context.context_name = extension_name;
+
+ content::SpeechRecognitionSessionConfig config;
+ // config.is_one_shot = true; // TODO(primiano) Uncomment when CL2.0 lands.
+ 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() {
- return !!recognizer_;
+ if (!is_recognition_in_progress_)
+ return false;
+ return SpeechRecognitionManager::GetInstance()->IsCapturingAudio();
}
bool SpeechInputExtensionManager::Stop(const std::string& extension_id,
@@ -692,13 +731,13 @@ void SpeechInputExtensionManager::ForceStopOnIOThread() {
}
void SpeechInputExtensionManager::StopRecording(bool recognition_failed) {
- if (recognizer_) {
- // Recognition is already cancelled in case of failure.
- // Double-cancelling leads to assertion failures.
- if (!recognition_failed)
- recognizer_->AbortRecognition();
- recognizer_.release();
- }
+ 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() {
@@ -712,9 +751,6 @@ void SpeechInputExtensionManager::StopSucceededOnUIThread() {
std::string extension_id = extension_id_in_use_;
ResetToIdleState();
- DCHECK(notification_.get());
- notification_->Hide();
-
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED,
// Guarded by the state_ == kShutdown check.
@@ -723,18 +759,5 @@ void SpeechInputExtensionManager::StopSucceededOnUIThread() {
}
void SpeechInputExtensionManager::OnAudioLevelsChange(int session_id,
- float volume,
- float noise_volume) {
- DCHECK_EQ(session_id, kSpeechInputSessionId);
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&SpeechInputExtensionManager::SetInputVolumeOnUIThread,
- this, volume));
-}
-
-void SpeechInputExtensionManager::SetInputVolumeOnUIThread(
- float volume) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(notification_.get());
- notification_->SetVUMeterVolume(volume);
-}
+ float volume,
+ float noise_volume) {}
« no previous file with comments | « chrome/browser/speech/speech_input_extension_manager.h ('k') | content/browser/speech/speech_recognition_manager_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698