Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/speech/speech_input_extension_manager.h" | 5 #include "chrome/browser/speech/speech_input_extension_manager.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/json/json_writer.h" | 8 #include "base/json/json_writer.h" |
| 9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
| 10 #include "base/values.h" | 10 #include "base/values.h" |
| 11 #include "chrome/browser/extensions/extension_event_router.h" | 11 #include "chrome/browser/extensions/extension_event_router.h" |
| 12 #include "chrome/browser/extensions/extension_service.h" | 12 #include "chrome/browser/extensions/extension_service.h" |
| 13 #include "chrome/browser/prefs/pref_service.h" | 13 #include "chrome/browser/prefs/pref_service.h" |
| 14 #include "chrome/browser/profiles/profile.h" | 14 #include "chrome/browser/profiles/profile.h" |
| 15 #include "chrome/browser/profiles/profile_dependency_manager.h" | 15 #include "chrome/browser/profiles/profile_dependency_manager.h" |
| 16 #include "chrome/browser/profiles/profile_keyed_service.h" | 16 #include "chrome/browser/profiles/profile_keyed_service.h" |
| 17 #include "chrome/browser/profiles/profile_keyed_service_factory.h" | 17 #include "chrome/browser/profiles/profile_keyed_service_factory.h" |
| 18 #include "chrome/browser/speech/speech_recognition_tray_icon_controller.h" | |
| 19 #include "chrome/common/chrome_notification_types.h" | 18 #include "chrome/common/chrome_notification_types.h" |
| 20 #include "chrome/common/extensions/extension.h" | 19 #include "chrome/common/extensions/extension.h" |
| 21 #include "chrome/common/pref_names.h" | 20 #include "chrome/common/pref_names.h" |
| 22 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
| 23 #include "content/public/browser/notification_registrar.h" | 22 #include "content/public/browser/notification_registrar.h" |
| 24 #include "content/public/browser/notification_service.h" | 23 #include "content/public/browser/notification_service.h" |
| 25 #include "content/public/browser/speech_recognition_manager.h" | 24 #include "content/public/browser/speech_recognition_manager.h" |
| 26 #include "content/public/browser/speech_recognizer.h" | 25 #include "content/public/browser/speech_recognition_session_config.h" |
| 26 #include "content/public/browser/speech_recognition_session_context.h" | |
| 27 #include "content/public/common/speech_recognition_error.h" | 27 #include "content/public/common/speech_recognition_error.h" |
| 28 #include "content/public/common/speech_recognition_result.h" | 28 #include "content/public/common/speech_recognition_result.h" |
| 29 #include "net/url_request/url_request_context_getter.h" | |
| 29 | 30 |
| 30 using content::BrowserThread; | 31 using content::BrowserThread; |
| 31 using content::SpeechRecognitionHypothesis; | 32 using content::SpeechRecognitionHypothesis; |
| 32 using content::SpeechRecognitionManager; | 33 using content::SpeechRecognitionManager; |
| 33 | 34 |
| 34 namespace { | 35 namespace { |
| 35 | 36 |
| 36 const char kErrorNoRecordingDeviceFound[] = "noRecordingDeviceFound"; | 37 const char kErrorNoRecordingDeviceFound[] = "noRecordingDeviceFound"; |
| 37 const char kErrorRecordingDeviceInUse[] = "recordingDeviceInUse"; | 38 const char kErrorRecordingDeviceInUse[] = "recordingDeviceInUse"; |
| 38 const char kErrorUnableToStart[] = "unableToStart"; | 39 const char kErrorUnableToStart[] = "unableToStart"; |
| 39 const char kErrorRequestDenied[] = "requestDenied"; | 40 const char kErrorRequestDenied[] = "requestDenied"; |
| 40 const char kErrorRequestInProgress[] = "requestInProgress"; | 41 const char kErrorRequestInProgress[] = "requestInProgress"; |
| 41 const char kErrorInvalidOperation[] = "invalidOperation"; | 42 const char kErrorInvalidOperation[] = "invalidOperation"; |
| 42 | 43 |
| 43 const char kErrorCodeKey[] = "code"; | 44 const char kErrorCodeKey[] = "code"; |
| 44 const char kErrorCaptureError[] = "captureError"; | 45 const char kErrorCaptureError[] = "captureError"; |
| 45 const char kErrorNetworkError[] = "networkError"; | 46 const char kErrorNetworkError[] = "networkError"; |
| 46 const char kErrorNoSpeechHeard[] = "noSpeechHeard"; | 47 const char kErrorNoSpeechHeard[] = "noSpeechHeard"; |
| 47 const char kErrorNoResults[] = "noResults"; | 48 const char kErrorNoResults[] = "noResults"; |
| 48 | 49 |
| 49 const char kUtteranceKey[] = "utterance"; | 50 const char kUtteranceKey[] = "utterance"; |
| 50 const char kConfidenceKey[] = "confidence"; | 51 const char kConfidenceKey[] = "confidence"; |
| 51 const char kHypothesesKey[] = "hypotheses"; | 52 const char kHypothesesKey[] = "hypotheses"; |
| 52 | 53 |
| 53 const char kOnErrorEvent[] = "experimental.speechInput.onError"; | 54 const char kOnErrorEvent[] = "experimental.speechInput.onError"; |
| 54 const char kOnResultEvent[] = "experimental.speechInput.onResult"; | 55 const char kOnResultEvent[] = "experimental.speechInput.onResult"; |
| 55 const char kOnSoundStartEvent[] = "experimental.speechInput.onSoundStart"; | 56 const char kOnSoundStartEvent[] = "experimental.speechInput.onSoundStart"; |
| 56 const char kOnSoundEndEvent[] = "experimental.speechInput.onSoundEnd"; | 57 const char kOnSoundEndEvent[] = "experimental.speechInput.onSoundEnd"; |
| 57 | 58 |
| 58 // Session id provided to the speech recognizer. Since only one extension can | |
| 59 // be recording on the same time a constant value is enough as id. | |
| 60 // TODO(primiano) this will not be valid anymore once speech input extension | |
| 61 // will use the SpeechRecognitionManager and not the SpeechRecognizer directly. | |
| 62 static const int kSpeechInputSessionId = 1; | |
| 63 | |
| 64 // Wrap an SpeechInputExtensionManager using scoped_refptr to avoid | 59 // Wrap an SpeechInputExtensionManager using scoped_refptr to avoid |
| 65 // assertion failures on destruction because of not using release(). | 60 // assertion failures on destruction because of not using release(). |
| 66 class SpeechInputExtensionManagerWrapper : public ProfileKeyedService { | 61 class SpeechInputExtensionManagerWrapper : public ProfileKeyedService { |
| 67 public: | 62 public: |
| 68 explicit SpeechInputExtensionManagerWrapper( | 63 explicit SpeechInputExtensionManagerWrapper( |
| 69 SpeechInputExtensionManager* manager) | 64 SpeechInputExtensionManager* manager) |
| 70 : manager_(manager) {} | 65 : manager_(manager) {} |
| 71 | 66 |
| 72 virtual ~SpeechInputExtensionManagerWrapper() {} | 67 virtual ~SpeechInputExtensionManagerWrapper() {} |
| 73 | 68 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 150 SpeechInputExtensionInterface::SpeechInputExtensionInterface() { | 145 SpeechInputExtensionInterface::SpeechInputExtensionInterface() { |
| 151 } | 146 } |
| 152 | 147 |
| 153 SpeechInputExtensionInterface::~SpeechInputExtensionInterface() { | 148 SpeechInputExtensionInterface::~SpeechInputExtensionInterface() { |
| 154 } | 149 } |
| 155 | 150 |
| 156 SpeechInputExtensionManager::SpeechInputExtensionManager(Profile* profile) | 151 SpeechInputExtensionManager::SpeechInputExtensionManager(Profile* profile) |
| 157 : profile_(profile), | 152 : profile_(profile), |
| 158 state_(kIdle), | 153 state_(kIdle), |
| 159 registrar_(new content::NotificationRegistrar), | 154 registrar_(new content::NotificationRegistrar), |
| 160 speech_interface_(NULL) { | 155 speech_interface_(NULL), |
| 156 is_recognition_in_progress_(false), | |
| 157 speech_recognition_session_id_( | |
| 158 SpeechRecognitionManager::kSessionIDInvalid) { | |
| 161 registrar_->Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | 159 registrar_->Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
| 162 content::Source<Profile>(profile_)); | 160 content::Source<Profile>(profile_)); |
| 163 } | 161 } |
| 164 | 162 |
| 165 SpeechInputExtensionManager::~SpeechInputExtensionManager() { | 163 SpeechInputExtensionManager::~SpeechInputExtensionManager() { |
| 166 } | 164 } |
| 167 | 165 |
| 168 SpeechInputExtensionManager* SpeechInputExtensionManager::GetForProfile( | 166 SpeechInputExtensionManager* SpeechInputExtensionManager::GetForProfile( |
| 169 Profile* profile) { | 167 Profile* profile) { |
| 170 SpeechInputExtensionManagerWrapper* wrapper = | 168 SpeechInputExtensionManagerWrapper* wrapper = |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 186 content::Details<UnloadedExtensionInfo>(details)->extension->id()); | 184 content::Details<UnloadedExtensionInfo>(details)->extension->id()); |
| 187 } else { | 185 } else { |
| 188 NOTREACHED(); | 186 NOTREACHED(); |
| 189 } | 187 } |
| 190 } | 188 } |
| 191 | 189 |
| 192 void SpeechInputExtensionManager::ShutdownOnUIThread() { | 190 void SpeechInputExtensionManager::ShutdownOnUIThread() { |
| 193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 194 VLOG(1) << "Profile shutting down."; | 192 VLOG(1) << "Profile shutting down."; |
| 195 | 193 |
| 194 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
| 195 base::Bind(&SpeechRecognitionManager::AbortAllSessionsForListener, | |
| 196 base::Unretained(SpeechRecognitionManager::GetInstance()), | |
| 197 base::Unretained(this))); | |
| 198 | |
| 196 base::AutoLock auto_lock(state_lock_); | 199 base::AutoLock auto_lock(state_lock_); |
| 197 DCHECK(state_ != kShutdown); | 200 DCHECK(state_ != kShutdown); |
| 198 if (state_ != kIdle) { | 201 if (state_ != kIdle) { |
| 199 DCHECK(notification_.get()); | |
| 200 notification_->Hide(); | |
| 201 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 202 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 202 base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); | 203 base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); |
| 203 } | 204 } |
| 204 state_ = kShutdown; | 205 state_ = kShutdown; |
| 205 VLOG(1) << "Entering the shutdown sink state."; | 206 VLOG(1) << "Entering the shutdown sink state."; |
| 206 registrar_.reset(); | 207 registrar_.reset(); |
| 207 profile_ = NULL; | 208 profile_ = NULL; |
| 208 } | 209 } |
| 209 | 210 |
| 210 void SpeechInputExtensionManager::ExtensionUnloaded( | 211 void SpeechInputExtensionManager::ExtensionUnloaded( |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 237 void SpeechInputExtensionManager::ResetToIdleState() { | 238 void SpeechInputExtensionManager::ResetToIdleState() { |
| 238 VLOG(1) << "State changed to idle. Deassociating any extensions."; | 239 VLOG(1) << "State changed to idle. Deassociating any extensions."; |
| 239 state_ = kIdle; | 240 state_ = kIdle; |
| 240 extension_id_in_use_.clear(); | 241 extension_id_in_use_.clear(); |
| 241 } | 242 } |
| 242 | 243 |
| 243 void SpeechInputExtensionManager::OnRecognitionResult( | 244 void SpeechInputExtensionManager::OnRecognitionResult( |
| 244 int session_id, | 245 int session_id, |
| 245 const content::SpeechRecognitionResult& result) { | 246 const content::SpeechRecognitionResult& result) { |
| 246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 247 DCHECK_EQ(session_id, kSpeechInputSessionId); | 248 DCHECK_EQ(session_id, speech_recognition_session_id_); |
| 248 | 249 |
| 249 // Stopping will start the disassociation with the extension. | 250 // Stopping will start the disassociation with the extension. |
| 250 // Make a copy to report the results to the proper one. | 251 // Make a copy to report the results to the proper one. |
| 251 std::string extension_id = extension_id_in_use_; | 252 std::string extension_id = extension_id_in_use_; |
| 252 ForceStopOnIOThread(); | 253 ForceStopOnIOThread(); |
| 253 | 254 |
| 254 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 255 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 255 base::Bind(&SpeechInputExtensionManager::SetRecognitionResultOnUIThread, | 256 base::Bind(&SpeechInputExtensionManager::SetRecognitionResultOnUIThread, |
| 256 this, result, extension_id)); | 257 this, result, extension_id)); |
| 257 } | 258 } |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 280 hypothesis.confidence); | 281 hypothesis.confidence); |
| 281 } | 282 } |
| 282 | 283 |
| 283 std::string json_args; | 284 std::string json_args; |
| 284 base::JSONWriter::Write(&args, &json_args); | 285 base::JSONWriter::Write(&args, &json_args); |
| 285 VLOG(1) << "Results: " << json_args; | 286 VLOG(1) << "Results: " << json_args; |
| 286 DispatchEventToExtension(extension_id, kOnResultEvent, json_args); | 287 DispatchEventToExtension(extension_id, kOnResultEvent, json_args); |
| 287 } | 288 } |
| 288 | 289 |
| 289 void SpeechInputExtensionManager::OnRecognitionStart(int session_id) { | 290 void SpeechInputExtensionManager::OnRecognitionStart(int session_id) { |
| 290 DCHECK_EQ(session_id, kSpeechInputSessionId); | 291 DCHECK_EQ(session_id, speech_recognition_session_id_); |
| 291 } | 292 } |
| 292 | 293 |
| 293 void SpeechInputExtensionManager::OnAudioStart(int session_id) { | 294 void SpeechInputExtensionManager::OnAudioStart(int session_id) { |
| 294 VLOG(1) << "OnAudioStart"; | 295 VLOG(1) << "OnAudioStart"; |
| 295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 296 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 296 DCHECK_EQ(session_id, kSpeechInputSessionId); | 297 DCHECK_EQ(session_id, speech_recognition_session_id_); |
| 297 | 298 |
| 298 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 299 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 299 base::Bind(&SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread, | 300 base::Bind(&SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread, |
| 300 this)); | 301 this)); |
| 301 } | 302 } |
| 302 | 303 |
| 303 void SpeechInputExtensionManager::OnAudioEnd(int session_id) { | 304 void SpeechInputExtensionManager::OnAudioEnd(int session_id) { |
| 304 DCHECK_EQ(session_id, kSpeechInputSessionId); | |
| 305 } | 305 } |
| 306 | 306 |
| 307 void SpeechInputExtensionManager::OnRecognitionEnd(int session_id) { | 307 void SpeechInputExtensionManager::OnRecognitionEnd(int session_id) { |
| 308 DCHECK_EQ(session_id, kSpeechInputSessionId); | 308 // In the very exceptional case in which we requested a new recognition before |
| 309 // the previous one ended, don't clobber the speech_recognition_session_id_. | |
| 310 if (speech_recognition_session_id_ == session_id) { | |
| 311 is_recognition_in_progress_ = false; | |
| 312 speech_recognition_session_id_ = | |
| 313 SpeechRecognitionManager::kSessionIDInvalid; | |
| 314 } | |
| 309 } | 315 } |
| 310 | 316 |
| 311 void SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread() { | 317 void SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread() { |
| 312 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 313 | 319 |
| 314 base::AutoLock auto_lock(state_lock_); | 320 base::AutoLock auto_lock(state_lock_); |
| 315 if (state_ == kShutdown) | 321 if (state_ == kShutdown) |
| 316 return; | 322 return; |
| 317 | 323 |
| 318 DCHECK_EQ(state_, kStarting); | 324 DCHECK_EQ(state_, kStarting); |
| 319 VLOG(1) << "State changed to recording"; | 325 VLOG(1) << "State changed to recording"; |
| 320 state_ = kRecording; | 326 state_ = kRecording; |
| 321 | 327 |
| 322 const Extension* extension = profile_->GetExtensionService()-> | 328 DCHECK(profile_); |
| 323 GetExtensionById(extension_id_in_use_, true); | 329 profile_->GetPrefs()->SetBoolean( |
| 324 DCHECK(extension); | 330 prefs::kSpeechInputTrayNotificationShown, true); |
|
hans
2012/05/15 13:35:17
this looks like a simplification of the old code..
Primiano Tucci (use gerrit)
2012/05/16 10:16:00
The previous code was doing 3 things:
(a) checkin
| |
| 325 | |
| 326 bool show_notification = !profile_->GetPrefs()->GetBoolean( | |
| 327 prefs::kSpeechInputTrayNotificationShown); | |
| 328 | |
| 329 if (!notification_.get()) | |
| 330 notification_ = new SpeechRecognitionTrayIconController(); | |
| 331 notification_->Show(UTF8ToUTF16(extension->name()), show_notification); | |
| 332 | |
| 333 if (show_notification) { | |
| 334 profile_->GetPrefs()->SetBoolean( | |
| 335 prefs::kSpeechInputTrayNotificationShown, true); | |
| 336 } | |
| 337 | 331 |
| 338 VLOG(1) << "Sending start notification"; | 332 VLOG(1) << "Sending start notification"; |
| 339 content::NotificationService::current()->Notify( | 333 content::NotificationService::current()->Notify( |
| 340 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED, | 334 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED, |
| 341 content::Source<Profile>(profile_), | 335 content::Source<Profile>(profile_), |
| 342 content::Details<std::string>(&extension_id_in_use_)); | 336 content::Details<std::string>(&extension_id_in_use_)); |
| 343 } | 337 } |
| 344 | 338 |
| 345 void SpeechInputExtensionManager::OnRecognitionError( | 339 void SpeechInputExtensionManager::OnRecognitionError( |
| 346 int session_id, const content::SpeechRecognitionError& error) { | 340 int session_id, const content::SpeechRecognitionError& error) { |
| 347 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 348 DCHECK_EQ(session_id, kSpeechInputSessionId); | |
| 349 | 342 |
| 350 // Simply return in case of an ERROR_ABORTED, since it is not contemplated | 343 // Simply return in case of an ERROR_ABORTED, since it is not contemplated |
| 351 // in the speech input extensions architecture. | 344 // in the speech input extensions architecture. |
| 352 if (error.code == content::SPEECH_RECOGNITION_ERROR_ABORTED) | 345 if (error.code == content::SPEECH_RECOGNITION_ERROR_ABORTED) |
| 353 return; | 346 return; |
| 354 | 347 |
| 348 DCHECK_EQ(session_id, speech_recognition_session_id_); | |
| 355 VLOG(1) << "OnRecognitionError: " << error.code; | 349 VLOG(1) << "OnRecognitionError: " << error.code; |
| 356 | 350 |
| 357 base::AutoLock auto_lock(state_lock_); | 351 base::AutoLock auto_lock(state_lock_); |
| 358 if (state_ == kShutdown) | 352 if (state_ == kShutdown) |
| 359 return; | 353 return; |
| 360 | 354 |
| 361 // Release the recognizer object. | 355 // Release the recognizer object. |
| 362 GetSpeechInputExtensionInterface()->StopRecording(true); | 356 GetSpeechInputExtensionInterface()->StopRecording(true); |
| 363 | 357 |
| 364 std::string event_error_code; | 358 std::string event_error_code; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 403 | 397 |
| 404 if (!event_error_code.empty()) { | 398 if (!event_error_code.empty()) { |
| 405 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 399 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 406 base::Bind(&SpeechInputExtensionManager::DispatchError, | 400 base::Bind(&SpeechInputExtensionManager::DispatchError, |
| 407 this, event_error_code, report_to_event)); | 401 this, event_error_code, report_to_event)); |
| 408 } | 402 } |
| 409 } | 403 } |
| 410 | 404 |
| 411 void SpeechInputExtensionManager::OnEnvironmentEstimationComplete( | 405 void SpeechInputExtensionManager::OnEnvironmentEstimationComplete( |
| 412 int session_id) { | 406 int session_id) { |
| 413 DCHECK_EQ(session_id, kSpeechInputSessionId); | 407 DCHECK_EQ(session_id, speech_recognition_session_id_); |
| 414 } | 408 } |
| 415 | 409 |
| 416 void SpeechInputExtensionManager::OnSoundStart(int session_id) { | 410 void SpeechInputExtensionManager::OnSoundStart(int session_id) { |
| 417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 411 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 418 DCHECK_EQ(session_id, kSpeechInputSessionId); | 412 DCHECK_EQ(session_id, speech_recognition_session_id_); |
| 419 VLOG(1) << "OnSoundStart"; | 413 VLOG(1) << "OnSoundStart"; |
| 420 | 414 |
| 421 std::string json_args; | 415 std::string json_args; |
| 422 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 416 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 423 base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension, | 417 base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension, |
| 424 this, extension_id_in_use_, std::string(kOnSoundStartEvent), | 418 this, extension_id_in_use_, std::string(kOnSoundStartEvent), |
| 425 json_args)); | 419 json_args)); |
| 426 } | 420 } |
| 427 | 421 |
| 428 void SpeechInputExtensionManager::OnSoundEnd(int session_id) { | 422 void SpeechInputExtensionManager::OnSoundEnd(int session_id) { |
| 429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 430 DCHECK_EQ(session_id, kSpeechInputSessionId); | |
| 431 VLOG(1) << "OnSoundEnd"; | 424 VLOG(1) << "OnSoundEnd"; |
| 432 | 425 |
| 433 std::string json_args; | 426 std::string json_args; |
| 434 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 427 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 435 base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension, | 428 base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension, |
| 436 this, extension_id_in_use_, std::string(kOnSoundEndEvent), | 429 this, extension_id_in_use_, std::string(kOnSoundEndEvent), |
| 437 json_args)); | 430 json_args)); |
| 438 } | 431 } |
| 439 | 432 |
| 440 void SpeechInputExtensionManager::DispatchEventToExtension( | 433 void SpeechInputExtensionManager::DispatchEventToExtension( |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 463 void SpeechInputExtensionManager::DispatchError( | 456 void SpeechInputExtensionManager::DispatchError( |
| 464 const std::string& error, bool dispatch_event) { | 457 const std::string& error, bool dispatch_event) { |
| 465 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 458 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 466 | 459 |
| 467 std::string extension_id; | 460 std::string extension_id; |
| 468 { | 461 { |
| 469 base::AutoLock auto_lock(state_lock_); | 462 base::AutoLock auto_lock(state_lock_); |
| 470 if (state_ == kShutdown) | 463 if (state_ == kShutdown) |
| 471 return; | 464 return; |
| 472 | 465 |
| 473 if (state_ == kRecording) { | |
| 474 DCHECK(notification_.get()); | |
| 475 notification_->Hide(); | |
| 476 } | |
| 477 | |
| 478 extension_id = extension_id_in_use_; | 466 extension_id = extension_id_in_use_; |
| 479 ResetToIdleState(); | 467 ResetToIdleState(); |
| 480 | 468 |
| 481 // Will set the error property in the ongoing extension function calls. | 469 // Will set the error property in the ongoing extension function calls. |
| 482 ExtensionError details(extension_id, error); | 470 ExtensionError details(extension_id, error); |
| 483 content::NotificationService::current()->Notify( | 471 content::NotificationService::current()->Notify( |
| 484 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_FAILED, | 472 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_FAILED, |
| 485 content::Source<Profile>(profile_), | 473 content::Source<Profile>(profile_), |
| 486 content::Details<ExtensionError>(&details)); | 474 content::Details<ExtensionError>(&details)); |
| 487 } | 475 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 523 | 511 |
| 524 case kRecording: | 512 case kRecording: |
| 525 case kStopping: | 513 case kStopping: |
| 526 *error = kErrorInvalidOperation; | 514 *error = kErrorInvalidOperation; |
| 527 return false; | 515 return false; |
| 528 | 516 |
| 529 default: | 517 default: |
| 530 NOTREACHED(); | 518 NOTREACHED(); |
| 531 } | 519 } |
| 532 | 520 |
| 521 const Extension* extension = profile_->GetExtensionService()-> | |
| 522 GetExtensionById(extension_id, true); | |
| 523 DCHECK(extension); | |
| 524 const string16& extension_name = UTF8ToUTF16(extension->name()); | |
| 525 | |
| 533 extension_id_in_use_ = extension_id; | 526 extension_id_in_use_ = extension_id; |
| 534 VLOG(1) << "State changed to starting"; | 527 VLOG(1) << "State changed to starting"; |
| 535 state_ = kStarting; | 528 state_ = kStarting; |
| 536 | 529 |
| 530 // Checks if the security notification balloon has been already shown (only | |
| 531 // once for a profile). It is reset on DidStartReceivingAudioOnUIThread. | |
| 532 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter = | |
| 533 profile_->GetRequestContext(); | |
| 534 const bool show_notification = !profile_->GetPrefs()->GetBoolean( | |
| 535 prefs::kSpeechInputTrayNotificationShown); | |
| 536 | |
| 537 BrowserThread::PostTask( | 537 BrowserThread::PostTask( |
| 538 BrowserThread::IO, FROM_HERE, | 538 BrowserThread::IO, FROM_HERE, |
| 539 base::Bind(&SpeechInputExtensionManager::StartOnIOThread, this, | 539 base::Bind(&SpeechInputExtensionManager::StartOnIOThread, this, |
| 540 profile_->GetRequestContext(), language, grammar, | 540 url_request_context_getter, extension_name, language, grammar, |
| 541 filter_profanities)); | 541 filter_profanities, show_notification)); |
| 542 return true; | 542 return true; |
| 543 } | 543 } |
| 544 | 544 |
| 545 void SpeechInputExtensionManager::StartOnIOThread( | 545 void SpeechInputExtensionManager::StartOnIOThread( |
| 546 net::URLRequestContextGetter* context_getter, | 546 scoped_refptr<net::URLRequestContextGetter> context_getter, |
| 547 const string16& extension_name, | |
| 547 const std::string& language, | 548 const std::string& language, |
| 548 const std::string& grammar, | 549 const std::string& grammar, |
| 549 bool filter_profanities) { | 550 bool filter_profanities, |
| 551 bool show_notification) { | |
| 550 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 552 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 551 VLOG(1) << "Requesting start (IO thread)"; | 553 VLOG(1) << "Requesting start (IO thread)"; |
| 552 | 554 |
| 553 // Everything put inside the lock to ensure the validity of context_getter, | 555 // Everything put inside the lock to ensure the validity of context_getter, |
| 554 // guaranteed while not in the shutdown state. Any ongoing or recognition | 556 // guaranteed while not in the shutdown state. Any ongoing or recognition |
| 555 // request will be requested to be aborted when entering the shutdown state. | 557 // request will be requested to be aborted when entering the shutdown state. |
| 556 base::AutoLock auto_lock(state_lock_); | 558 base::AutoLock auto_lock(state_lock_); |
| 557 if (state_ == kShutdown) | 559 if (state_ == kShutdown) |
| 558 return; | 560 return; |
| 559 | 561 |
| 560 if (!GetSpeechInputExtensionInterface()->HasAudioInputDevices()) { | 562 if (!GetSpeechInputExtensionInterface()->HasAudioInputDevices()) { |
| 561 BrowserThread::PostTask( | 563 BrowserThread::PostTask( |
| 562 BrowserThread::UI, FROM_HERE, | 564 BrowserThread::UI, FROM_HERE, |
| 563 base::Bind(&SpeechInputExtensionManager::DispatchError, this, | 565 base::Bind(&SpeechInputExtensionManager::DispatchError, this, |
| 564 std::string(kErrorNoRecordingDeviceFound), false)); | 566 std::string(kErrorNoRecordingDeviceFound), false)); |
| 565 return; | 567 return; |
| 566 } | 568 } |
| 567 | 569 |
| 568 if (GetSpeechInputExtensionInterface()->IsCapturingAudio()) { | 570 if (GetSpeechInputExtensionInterface()->IsCapturingAudio()) { |
| 569 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 571 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 570 base::Bind(&SpeechInputExtensionManager::DispatchError, this, | 572 base::Bind(&SpeechInputExtensionManager::DispatchError, this, |
| 571 std::string(kErrorRecordingDeviceInUse), false)); | 573 std::string(kErrorRecordingDeviceInUse), false)); |
| 572 return; | 574 return; |
| 573 } | 575 } |
| 574 | 576 |
| 575 GetSpeechInputExtensionInterface()->StartRecording( | 577 GetSpeechInputExtensionInterface()->StartRecording(this, |
| 576 this, context_getter, kSpeechInputSessionId, language, grammar, | 578 context_getter, |
| 577 filter_profanities); | 579 extension_name, |
| 580 language, | |
| 581 grammar, | |
| 582 filter_profanities, | |
| 583 show_notification); | |
| 578 } | 584 } |
| 579 | 585 |
| 580 bool SpeechInputExtensionManager::HasAudioInputDevices() { | 586 bool SpeechInputExtensionManager::HasAudioInputDevices() { |
| 581 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 587 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 582 return SpeechRecognitionManager::GetInstance()->HasAudioInputDevices(); | 588 return SpeechRecognitionManager::GetInstance()->HasAudioInputDevices(); |
| 583 } | 589 } |
| 584 | 590 |
| 585 bool SpeechInputExtensionManager::IsCapturingAudio() { | 591 bool SpeechInputExtensionManager::IsCapturingAudio() { |
| 586 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 592 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 587 return SpeechRecognitionManager::GetInstance()->IsCapturingAudio(); | 593 return SpeechRecognitionManager::GetInstance()->IsCapturingAudio(); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 610 void SpeechInputExtensionManager::IsRecordingOnUIThread( | 616 void SpeechInputExtensionManager::IsRecordingOnUIThread( |
| 611 const IsRecordingCallback& callback, | 617 const IsRecordingCallback& callback, |
| 612 bool result) { | 618 bool result) { |
| 613 BrowserThread::CurrentlyOn(BrowserThread::UI); | 619 BrowserThread::CurrentlyOn(BrowserThread::UI); |
| 614 callback.Run(result); | 620 callback.Run(result); |
| 615 } | 621 } |
| 616 | 622 |
| 617 void SpeechInputExtensionManager::StartRecording( | 623 void SpeechInputExtensionManager::StartRecording( |
| 618 content::SpeechRecognitionEventListener* listener, | 624 content::SpeechRecognitionEventListener* listener, |
| 619 net::URLRequestContextGetter* context_getter, | 625 net::URLRequestContextGetter* context_getter, |
| 620 int session_id, | 626 const string16& extension_name, |
| 621 const std::string& language, | 627 const std::string& language, |
| 622 const std::string& grammar, | 628 const std::string& grammar, |
| 623 bool filter_profanities) { | 629 bool filter_profanities, |
| 630 bool show_notification) { | |
| 624 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 631 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 625 DCHECK(!recognizer_); | 632 |
| 626 recognizer_ = content::SpeechRecognizer::Create( | 633 content::SpeechRecognitionSessionContext context; |
| 627 listener, session_id, language, grammar, context_getter, | 634 context.use_bubble_on_element = false; |
| 628 filter_profanities, "", ""); | 635 context.show_security_balloon = show_notification; |
| 629 recognizer_->StartRecognition(); | 636 context.context_name = extension_name; |
| 637 | |
| 638 content::SpeechRecognitionSessionConfig config; | |
| 639 // config.is_one_shot = true; // TODO(primiano) Uncomment when CL2.0 lands. | |
| 640 config.language = language; | |
| 641 config.grammar = grammar; | |
| 642 config.initial_context = context; | |
| 643 config.url_request_context_getter = context_getter; | |
| 644 config.filter_profanities = filter_profanities; | |
| 645 config.event_listener = listener; | |
| 646 | |
| 647 DCHECK(!is_recognition_in_progress_); | |
| 648 SpeechRecognitionManager& manager = *SpeechRecognitionManager::GetInstance(); | |
| 649 speech_recognition_session_id_ = | |
| 650 manager.CreateSession(config); | |
| 651 DCHECK_NE(speech_recognition_session_id_, | |
| 652 SpeechRecognitionManager::kSessionIDInvalid); | |
| 653 is_recognition_in_progress_ = true; | |
| 654 manager.StartSession(speech_recognition_session_id_); | |
| 630 } | 655 } |
| 631 | 656 |
| 632 bool SpeechInputExtensionManager::HasValidRecognizer() { | 657 bool SpeechInputExtensionManager::HasValidRecognizer() { |
| 633 return !!recognizer_; | 658 if (!is_recognition_in_progress_) |
| 659 return false; | |
| 660 return SpeechRecognitionManager::GetInstance()->IsCapturingAudio(); | |
| 634 } | 661 } |
| 635 | 662 |
| 636 bool SpeechInputExtensionManager::Stop(const std::string& extension_id, | 663 bool SpeechInputExtensionManager::Stop(const std::string& extension_id, |
| 637 std::string* error) { | 664 std::string* error) { |
| 638 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 665 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 639 DCHECK(error); | 666 DCHECK(error); |
| 640 VLOG(1) << "Requesting stop (UI thread)"; | 667 VLOG(1) << "Requesting stop (UI thread)"; |
| 641 | 668 |
| 642 base::AutoLock auto_lock(state_lock_); | 669 base::AutoLock auto_lock(state_lock_); |
| 643 if (state_ == kShutdown || | 670 if (state_ == kShutdown || |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 684 GetSpeechInputExtensionInterface()->StopRecording(false); | 711 GetSpeechInputExtensionInterface()->StopRecording(false); |
| 685 | 712 |
| 686 if (state_ == kShutdown) | 713 if (state_ == kShutdown) |
| 687 return; | 714 return; |
| 688 | 715 |
| 689 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 716 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 690 base::Bind(&SpeechInputExtensionManager::StopSucceededOnUIThread, this)); | 717 base::Bind(&SpeechInputExtensionManager::StopSucceededOnUIThread, this)); |
| 691 } | 718 } |
| 692 | 719 |
| 693 void SpeechInputExtensionManager::StopRecording(bool recognition_failed) { | 720 void SpeechInputExtensionManager::StopRecording(bool recognition_failed) { |
| 694 if (recognizer_) { | 721 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 695 // Recognition is already cancelled in case of failure. | 722 if (!is_recognition_in_progress_) |
| 696 // Double-cancelling leads to assertion failures. | 723 return; |
| 697 if (!recognition_failed) | 724 DCHECK_NE(speech_recognition_session_id_, |
| 698 recognizer_->AbortRecognition(); | 725 SpeechRecognitionManager::kSessionIDInvalid); |
| 699 recognizer_.release(); | 726 SpeechRecognitionManager::GetInstance()->AbortSession( |
| 700 } | 727 speech_recognition_session_id_); |
| 701 } | 728 } |
| 702 | 729 |
| 703 void SpeechInputExtensionManager::StopSucceededOnUIThread() { | 730 void SpeechInputExtensionManager::StopSucceededOnUIThread() { |
| 704 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 731 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 705 VLOG(1) << "Stop succeeded (UI thread)"; | 732 VLOG(1) << "Stop succeeded (UI thread)"; |
| 706 | 733 |
| 707 base::AutoLock auto_lock(state_lock_); | 734 base::AutoLock auto_lock(state_lock_); |
| 708 if (state_ == kShutdown) | 735 if (state_ == kShutdown) |
| 709 return; | 736 return; |
| 710 | 737 |
| 711 std::string extension_id = extension_id_in_use_; | 738 std::string extension_id = extension_id_in_use_; |
| 712 ResetToIdleState(); | 739 ResetToIdleState(); |
| 713 | 740 |
| 714 DCHECK(notification_.get()); | |
| 715 notification_->Hide(); | |
| 716 | |
| 717 content::NotificationService::current()->Notify( | 741 content::NotificationService::current()->Notify( |
| 718 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED, | 742 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED, |
| 719 // Guarded by the state_ == kShutdown check. | 743 // Guarded by the state_ == kShutdown check. |
| 720 content::Source<Profile>(profile_), | 744 content::Source<Profile>(profile_), |
| 721 content::Details<std::string>(&extension_id)); | 745 content::Details<std::string>(&extension_id)); |
| 722 } | 746 } |
| 723 | 747 |
| 724 void SpeechInputExtensionManager::OnAudioLevelsChange(int session_id, | 748 void SpeechInputExtensionManager::OnAudioLevelsChange(int session_id, |
| 725 float volume, | 749 float volume, |
| 726 float noise_volume) { | 750 float noise_volume) {} |
| 727 DCHECK_EQ(session_id, kSpeechInputSessionId); | |
| 728 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 729 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 730 base::Bind(&SpeechInputExtensionManager::SetInputVolumeOnUIThread, | |
| 731 this, volume)); | |
| 732 } | |
| 733 | |
| 734 void SpeechInputExtensionManager::SetInputVolumeOnUIThread( | |
| 735 float volume) { | |
| 736 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 737 DCHECK(notification_.get()); | |
| 738 notification_->SetVUMeterVolume(volume); | |
| 739 } | |
| OLD | NEW |