| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/extensions/speech_input/extension_speech_input_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/speech_input/extension_speech_input_api_cons
tants.h" | 12 #include "chrome/browser/extensions/extension_service.h" |
| 13 #include "chrome/browser/prefs/pref_service.h" |
| 13 #include "chrome/browser/profiles/profile.h" | 14 #include "chrome/browser/profiles/profile.h" |
| 14 #include "chrome/browser/profiles/profile_dependency_manager.h" | 15 #include "chrome/browser/profiles/profile_dependency_manager.h" |
| 15 #include "chrome/browser/profiles/profile_keyed_service.h" | 16 #include "chrome/browser/profiles/profile_keyed_service.h" |
| 16 #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_input_extension_notification_ui.h" |
| 17 #include "chrome/common/chrome_notification_types.h" | 19 #include "chrome/common/chrome_notification_types.h" |
| 18 #include "chrome/common/extensions/extension.h" | 20 #include "chrome/common/extensions/extension.h" |
| 21 #include "chrome/common/pref_names.h" |
| 19 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
| 20 #include "content/public/browser/notification_service.h" | 23 #include "content/public/browser/notification_service.h" |
| 21 | 24 |
| 22 using content::BrowserThread; | 25 using content::BrowserThread; |
| 23 | |
| 24 using namespace speech_input; | 26 using namespace speech_input; |
| 25 | 27 |
| 26 namespace constants = extension_speech_input_api_constants; | 28 namespace { |
| 27 | 29 |
| 28 namespace { | 30 const char kErrorNoRecordingDeviceFound[] = "noRecordingDeviceFound"; |
| 31 const char kErrorRecordingDeviceInUse[] = "recordingDeviceInUse"; |
| 32 const char kErrorUnableToStart[] = "unableToStart"; |
| 33 const char kErrorRequestDenied[] = "requestDenied"; |
| 34 const char kErrorRequestInProgress[] = "requestInProgress"; |
| 35 const char kErrorInvalidOperation[] = "invalidOperation"; |
| 36 |
| 37 const char kErrorCodeKey[] = "code"; |
| 38 const char kErrorCaptureError[] = "captureError"; |
| 39 const char kErrorNetworkError[] = "networkError"; |
| 40 const char kErrorNoSpeechHeard[] = "noSpeechHeard"; |
| 41 const char kErrorNoResults[] = "noResults"; |
| 42 |
| 43 const char kUtteranceKey[] = "utterance"; |
| 44 const char kConfidenceKey[] = "confidence"; |
| 45 const char kHypothesesKey[] = "hypotheses"; |
| 46 |
| 47 const char kOnErrorEvent[] = "experimental.speechInput.onError"; |
| 48 const char kOnResultEvent[] = "experimental.speechInput.onResult"; |
| 49 const char kOnSoundStartEvent[] = "experimental.speechInput.onSoundStart"; |
| 50 const char kOnSoundEndEvent[] = "experimental.speechInput.onSoundEnd"; |
| 29 | 51 |
| 30 // Caller id provided to the speech recognizer. Since only one extension can | 52 // Caller id provided to the speech recognizer. Since only one extension can |
| 31 // be recording on the same time a constant value is enough as id. | 53 // be recording on the same time a constant value is enough as id. |
| 32 static const int kSpeechCallerId = 1; | 54 static const int kSpeechCallerId = 1; |
| 33 | 55 |
| 34 // Wrap an ExtensionSpeechInputManager using scoped_refptr to avoid | 56 // Wrap an SpeechInputExtensionManager using scoped_refptr to avoid |
| 35 // assertion failures on destruction because of not using release(). | 57 // assertion failures on destruction because of not using release(). |
| 36 class ExtensionSpeechInputManagerWrapper : public ProfileKeyedService { | 58 class SpeechInputExtensionManagerWrapper : public ProfileKeyedService { |
| 37 public: | 59 public: |
| 38 explicit ExtensionSpeechInputManagerWrapper( | 60 explicit SpeechInputExtensionManagerWrapper( |
| 39 ExtensionSpeechInputManager* manager) | 61 SpeechInputExtensionManager* manager) |
| 40 : manager_(manager) {} | 62 : manager_(manager) {} |
| 41 | 63 |
| 42 virtual ~ExtensionSpeechInputManagerWrapper() {} | 64 virtual ~SpeechInputExtensionManagerWrapper() {} |
| 43 | 65 |
| 44 ExtensionSpeechInputManager* manager() const { return manager_.get(); } | 66 SpeechInputExtensionManager* manager() const { return manager_.get(); } |
| 45 | 67 |
| 46 private: | 68 private: |
| 47 // Methods from ProfileKeyedService. | 69 // Methods from ProfileKeyedService. |
| 48 virtual void Shutdown() OVERRIDE { | 70 virtual void Shutdown() OVERRIDE { |
| 49 manager()->ShutdownOnUIThread(); | 71 manager()->ShutdownOnUIThread(); |
| 50 } | 72 } |
| 51 | 73 |
| 52 scoped_refptr<ExtensionSpeechInputManager> manager_; | 74 scoped_refptr<SpeechInputExtensionManager> manager_; |
| 53 }; | 75 }; |
| 54 | 76 |
| 55 } | 77 } |
| 56 | 78 |
| 57 // Factory for ExtensionSpeechInputManagers as profile keyed services. | 79 // Factory for SpeechInputExtensionManagers as profile keyed services. |
| 58 class ExtensionSpeechInputManager::Factory : public ProfileKeyedServiceFactory { | 80 class SpeechInputExtensionManager::Factory : public ProfileKeyedServiceFactory { |
| 59 public: | 81 public: |
| 60 static void Initialize(); | 82 static void Initialize(); |
| 61 static Factory* GetInstance(); | 83 static Factory* GetInstance(); |
| 62 | 84 |
| 63 ExtensionSpeechInputManagerWrapper* GetForProfile(Profile* profile); | 85 SpeechInputExtensionManagerWrapper* GetForProfile(Profile* profile); |
| 64 | 86 |
| 65 private: | 87 private: |
| 66 friend struct DefaultSingletonTraits<Factory>; | 88 friend struct DefaultSingletonTraits<Factory>; |
| 67 | 89 |
| 68 Factory(); | 90 Factory(); |
| 69 virtual ~Factory(); | 91 virtual ~Factory(); |
| 70 | 92 |
| 71 // ProfileKeyedServiceFactory methods: | 93 // ProfileKeyedServiceFactory methods: |
| 72 virtual ProfileKeyedService* BuildServiceInstanceFor( | 94 virtual ProfileKeyedService* BuildServiceInstanceFor( |
| 73 Profile* profile) const OVERRIDE; | 95 Profile* profile) const OVERRIDE; |
| 74 virtual bool ServiceRedirectedInIncognito() OVERRIDE { return false; } | 96 virtual bool ServiceRedirectedInIncognito() OVERRIDE { return false; } |
| 75 virtual bool ServiceIsNULLWhileTesting() OVERRIDE { return true; } | 97 virtual bool ServiceIsNULLWhileTesting() OVERRIDE { return true; } |
| 76 virtual bool ServiceIsCreatedWithProfile() OVERRIDE { return true; } | 98 virtual bool ServiceIsCreatedWithProfile() OVERRIDE { return true; } |
| 77 | 99 |
| 78 DISALLOW_COPY_AND_ASSIGN(Factory); | 100 DISALLOW_COPY_AND_ASSIGN(Factory); |
| 79 }; | 101 }; |
| 80 | 102 |
| 81 void ExtensionSpeechInputManager::Factory::Initialize() { | 103 void SpeechInputExtensionManager::Factory::Initialize() { |
| 82 GetInstance(); | 104 GetInstance(); |
| 83 } | 105 } |
| 84 | 106 |
| 85 ExtensionSpeechInputManager::Factory* | 107 SpeechInputExtensionManager::Factory* |
| 86 ExtensionSpeechInputManager::Factory::GetInstance() { | 108 SpeechInputExtensionManager::Factory::GetInstance() { |
| 87 return Singleton<ExtensionSpeechInputManager::Factory>::get(); | 109 return Singleton<SpeechInputExtensionManager::Factory>::get(); |
| 88 } | 110 } |
| 89 | 111 |
| 90 ExtensionSpeechInputManagerWrapper* | 112 SpeechInputExtensionManagerWrapper* |
| 91 ExtensionSpeechInputManager::Factory::GetForProfile( | 113 SpeechInputExtensionManager::Factory::GetForProfile( |
| 92 Profile* profile) { | 114 Profile* profile) { |
| 93 return static_cast<ExtensionSpeechInputManagerWrapper*>( | 115 return static_cast<SpeechInputExtensionManagerWrapper*>( |
| 94 GetServiceForProfile(profile, true)); | 116 GetServiceForProfile(profile, true)); |
| 95 } | 117 } |
| 96 | 118 |
| 97 ExtensionSpeechInputManager::Factory::Factory() | 119 SpeechInputExtensionManager::Factory::Factory() |
| 98 : ProfileKeyedServiceFactory(ProfileDependencyManager::GetInstance()) { | 120 : ProfileKeyedServiceFactory(ProfileDependencyManager::GetInstance()) { |
| 99 } | 121 } |
| 100 | 122 |
| 101 ExtensionSpeechInputManager::Factory::~Factory() { | 123 SpeechInputExtensionManager::Factory::~Factory() { |
| 102 } | 124 } |
| 103 | 125 |
| 104 ProfileKeyedService* | 126 ProfileKeyedService* |
| 105 ExtensionSpeechInputManager::Factory::BuildServiceInstanceFor( | 127 SpeechInputExtensionManager::Factory::BuildServiceInstanceFor( |
| 106 Profile* profile) const { | 128 Profile* profile) const { |
| 107 scoped_refptr<ExtensionSpeechInputManager> manager( | 129 scoped_refptr<SpeechInputExtensionManager> manager( |
| 108 new ExtensionSpeechInputManager(profile)); | 130 new SpeechInputExtensionManager(profile)); |
| 109 return new ExtensionSpeechInputManagerWrapper(manager); | 131 return new SpeechInputExtensionManagerWrapper(manager); |
| 110 } | 132 } |
| 111 | 133 |
| 112 ExtensionSpeechInterface::ExtensionSpeechInterface() { | 134 SpeechExtensionInterface::SpeechExtensionInterface() { |
| 113 } | 135 } |
| 114 | 136 |
| 115 ExtensionSpeechInterface::~ExtensionSpeechInterface() { | 137 SpeechExtensionInterface::~SpeechExtensionInterface() { |
| 116 } | 138 } |
| 117 | 139 |
| 118 ExtensionSpeechInputManager::ExtensionSpeechInputManager(Profile* profile) | 140 SpeechInputExtensionManager::SpeechInputExtensionManager(Profile* profile) |
| 119 : profile_(profile), | 141 : profile_(profile), |
| 120 state_(kIdle), | 142 state_(kIdle), |
| 121 speech_interface_(NULL) { | 143 speech_interface_(NULL), |
| 144 notification_(profile) { |
| 122 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | 145 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
| 123 content::Source<Profile>(profile_)); | 146 content::Source<Profile>(profile_)); |
| 124 } | 147 } |
| 125 | 148 |
| 126 ExtensionSpeechInputManager::~ExtensionSpeechInputManager() { | 149 SpeechInputExtensionManager::~SpeechInputExtensionManager() { |
| 127 } | 150 } |
| 128 | 151 |
| 129 ExtensionSpeechInputManager* ExtensionSpeechInputManager::GetForProfile( | 152 SpeechInputExtensionManager* SpeechInputExtensionManager::GetForProfile( |
| 130 Profile* profile) { | 153 Profile* profile) { |
| 131 ExtensionSpeechInputManagerWrapper *wrapper = | 154 SpeechInputExtensionManagerWrapper *wrapper = |
| 132 Factory::GetInstance()->GetForProfile(profile); | 155 Factory::GetInstance()->GetForProfile(profile); |
| 133 if (!wrapper) | 156 if (!wrapper) |
| 134 return NULL; | 157 return NULL; |
| 135 return wrapper->manager(); | 158 return wrapper->manager(); |
| 136 } | 159 } |
| 137 | 160 |
| 138 void ExtensionSpeechInputManager::InitializeFactory() { | 161 void SpeechInputExtensionManager::InitializeFactory() { |
| 139 Factory::Initialize(); | 162 Factory::Initialize(); |
| 140 } | 163 } |
| 141 | 164 |
| 142 void ExtensionSpeechInputManager::Observe(int type, | 165 void SpeechInputExtensionManager::Observe(int type, |
| 143 const content::NotificationSource& source, | 166 const content::NotificationSource& source, |
| 144 const content::NotificationDetails& details) { | 167 const content::NotificationDetails& details) { |
| 145 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) { | 168 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) { |
| 146 ExtensionUnloaded( | 169 ExtensionUnloaded( |
| 147 content::Details<UnloadedExtensionInfo>(details)->extension->id()); | 170 content::Details<UnloadedExtensionInfo>(details)->extension->id()); |
| 148 } else { | 171 } else { |
| 149 NOTREACHED(); | 172 NOTREACHED(); |
| 150 } | 173 } |
| 151 } | 174 } |
| 152 | 175 |
| 153 void ExtensionSpeechInputManager::ShutdownOnUIThread() { | 176 void SpeechInputExtensionManager::ShutdownOnUIThread() { |
| 154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 155 VLOG(1) << "Profile shutting down."; | 178 VLOG(1) << "Profile shutting down."; |
| 156 | 179 |
| 157 base::AutoLock auto_lock(state_lock_); | 180 base::AutoLock auto_lock(state_lock_); |
| 158 DCHECK(state_ != kShutdown); | 181 DCHECK(state_ != kShutdown); |
| 159 if (state_ != kIdle) { | 182 if (state_ != kIdle) { |
| 183 notification_.Hide(); |
| 160 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 184 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 161 base::Bind(&ExtensionSpeechInputManager::ForceStopOnIOThread, this)); | 185 base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); |
| 162 } | 186 } |
| 163 state_ = kShutdown; | 187 state_ = kShutdown; |
| 164 VLOG(1) << "Entering the shutdown sink state."; | 188 VLOG(1) << "Entering the shutdown sink state."; |
| 165 registrar_.RemoveAll(); | 189 registrar_.RemoveAll(); |
| 166 profile_ = NULL; | 190 profile_ = NULL; |
| 167 } | 191 } |
| 168 | 192 |
| 169 void ExtensionSpeechInputManager::ExtensionUnloaded( | 193 void SpeechInputExtensionManager::ExtensionUnloaded( |
| 170 const std::string& extension_id) { | 194 const std::string& extension_id) { |
| 171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 172 | 196 |
| 173 base::AutoLock auto_lock(state_lock_); | 197 base::AutoLock auto_lock(state_lock_); |
| 174 if (state_ == kShutdown) | 198 if (state_ == kShutdown) |
| 175 return; | 199 return; |
| 176 | 200 |
| 177 VLOG(1) << "Extension unloaded. Requesting to enforce stop..."; | 201 VLOG(1) << "Extension unloaded. Requesting to enforce stop..."; |
| 178 if (extension_id_in_use_ == extension_id) { | 202 if (extension_id_in_use_ == extension_id) { |
| 179 if (state_ != kIdle) { | 203 if (state_ != kIdle) { |
| 180 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 204 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 181 base::Bind(&ExtensionSpeechInputManager::ForceStopOnIOThread, this)); | 205 base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); |
| 182 } | 206 } |
| 183 } | 207 } |
| 184 } | 208 } |
| 185 | 209 |
| 186 void ExtensionSpeechInputManager::SetExtensionSpeechInterface( | 210 void SpeechInputExtensionManager::SetSpeechExtensionInterface( |
| 187 ExtensionSpeechInterface* interface) { | 211 SpeechExtensionInterface* interface) { |
| 188 speech_interface_ = interface; | 212 speech_interface_ = interface; |
| 189 } | 213 } |
| 190 | 214 |
| 191 ExtensionSpeechInterface* | 215 SpeechExtensionInterface* |
| 192 ExtensionSpeechInputManager::GetExtensionSpeechInterface() { | 216 SpeechInputExtensionManager::GetSpeechExtensionInterface() { |
| 193 return speech_interface_ ? speech_interface_ : this; | 217 return speech_interface_ ? speech_interface_ : this; |
| 194 } | 218 } |
| 195 | 219 |
| 196 void ExtensionSpeechInputManager::ResetToIdleState() { | 220 void SpeechInputExtensionManager::ResetToIdleState() { |
| 197 VLOG(1) << "State changed to idle. Deassociating any extensions."; | 221 VLOG(1) << "State changed to idle. Deassociating any extensions."; |
| 198 state_ = kIdle; | 222 state_ = kIdle; |
| 199 extension_id_in_use_.clear(); | 223 extension_id_in_use_.clear(); |
| 200 } | 224 } |
| 201 | 225 |
| 202 void ExtensionSpeechInputManager::SetRecognitionResult( | 226 void SpeechInputExtensionManager::SetRecognitionResult( |
| 203 int caller_id, | 227 int caller_id, |
| 204 const SpeechInputResult& result) { | 228 const SpeechInputResult& result) { |
| 205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 229 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 206 DCHECK_EQ(caller_id, kSpeechCallerId); | 230 DCHECK_EQ(caller_id, kSpeechCallerId); |
| 207 | 231 |
| 208 // Stopping will start the disassociation with the extension. | 232 // Stopping will start the disassociation with the extension. |
| 209 // Make a copy to report the results to the proper one. | 233 // Make a copy to report the results to the proper one. |
| 210 std::string extension_id = extension_id_in_use_; | 234 std::string extension_id = extension_id_in_use_; |
| 211 ForceStopOnIOThread(); | 235 ForceStopOnIOThread(); |
| 212 | 236 |
| 213 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 237 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 214 base::Bind(&ExtensionSpeechInputManager::SetRecognitionResultOnUIThread, | 238 base::Bind(&SpeechInputExtensionManager::SetRecognitionResultOnUIThread, |
| 215 this, result, extension_id)); | 239 this, result, extension_id)); |
| 216 } | 240 } |
| 217 | 241 |
| 218 void ExtensionSpeechInputManager::SetRecognitionResultOnUIThread( | 242 void SpeechInputExtensionManager::SetRecognitionResultOnUIThread( |
| 219 const SpeechInputResult& result, const std::string& extension_id) { | 243 const SpeechInputResult& result, const std::string& extension_id) { |
| 220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 221 | 245 |
| 222 ListValue args; | 246 ListValue args; |
| 223 DictionaryValue* js_event = new DictionaryValue(); | 247 DictionaryValue* js_event = new DictionaryValue(); |
| 224 args.Append(js_event); | 248 args.Append(js_event); |
| 225 | 249 |
| 226 ListValue* js_hypothesis_array = new ListValue(); | 250 ListValue* js_hypothesis_array = new ListValue(); |
| 227 js_event->Set(constants::kHypothesesKey, js_hypothesis_array); | 251 js_event->Set(kHypothesesKey, js_hypothesis_array); |
| 228 | 252 |
| 229 for (size_t i = 0; i < result.hypotheses.size(); ++i) { | 253 for (size_t i = 0; i < result.hypotheses.size(); ++i) { |
| 230 const SpeechInputHypothesis& hypothesis = result.hypotheses[i]; | 254 const SpeechInputHypothesis& hypothesis = result.hypotheses[i]; |
| 231 | 255 |
| 232 DictionaryValue* js_hypothesis_object = new DictionaryValue(); | 256 DictionaryValue* js_hypothesis_object = new DictionaryValue(); |
| 233 js_hypothesis_array->Append(js_hypothesis_object); | 257 js_hypothesis_array->Append(js_hypothesis_object); |
| 234 | 258 |
| 235 js_hypothesis_object->SetString(constants::kUtteranceKey, | 259 js_hypothesis_object->SetString(kUtteranceKey, |
| 236 UTF16ToUTF8(hypothesis.utterance)); | 260 UTF16ToUTF8(hypothesis.utterance)); |
| 237 js_hypothesis_object->SetDouble(constants::kConfidenceKey, | 261 js_hypothesis_object->SetDouble(kConfidenceKey, |
| 238 hypothesis.confidence); | 262 hypothesis.confidence); |
| 239 } | 263 } |
| 240 | 264 |
| 241 std::string json_args; | 265 std::string json_args; |
| 242 base::JSONWriter::Write(&args, false, &json_args); | 266 base::JSONWriter::Write(&args, false, &json_args); |
| 243 VLOG(1) << "Results: " << json_args; | 267 VLOG(1) << "Results: " << json_args; |
| 244 DispatchEventToExtension(extension_id, constants::kOnResultEvent, json_args); | 268 DispatchEventToExtension(extension_id, kOnResultEvent, json_args); |
| 245 } | 269 } |
| 246 | 270 |
| 247 void ExtensionSpeechInputManager::DidStartReceivingAudio(int caller_id) { | 271 void SpeechInputExtensionManager::DidStartReceivingAudio(int caller_id) { |
| 248 VLOG(1) << "DidStartReceivingAudio"; | 272 VLOG(1) << "DidStartReceivingAudio"; |
| 249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 250 DCHECK_EQ(caller_id, kSpeechCallerId); | 274 DCHECK_EQ(caller_id, kSpeechCallerId); |
| 251 | 275 |
| 252 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 276 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 253 base::Bind(&ExtensionSpeechInputManager::DidStartReceivingAudioOnUIThread, | 277 base::Bind(&SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread, |
| 254 this)); | 278 this)); |
| 255 } | 279 } |
| 256 | 280 |
| 257 void ExtensionSpeechInputManager::DidCompleteRecording(int caller_id) { | 281 void SpeechInputExtensionManager::DidCompleteRecording(int caller_id) { |
| 258 DCHECK_EQ(caller_id, kSpeechCallerId); | 282 DCHECK_EQ(caller_id, kSpeechCallerId); |
| 259 } | 283 } |
| 260 | 284 |
| 261 void ExtensionSpeechInputManager::DidCompleteRecognition(int caller_id) { | 285 void SpeechInputExtensionManager::DidCompleteRecognition(int caller_id) { |
| 262 DCHECK_EQ(caller_id, kSpeechCallerId); | 286 DCHECK_EQ(caller_id, kSpeechCallerId); |
| 263 } | 287 } |
| 264 | 288 |
| 265 void ExtensionSpeechInputManager::DidStartReceivingAudioOnUIThread() { | 289 void SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread() { |
| 266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 267 | 291 |
| 268 base::AutoLock auto_lock(state_lock_); | 292 base::AutoLock auto_lock(state_lock_); |
| 269 if (state_ == kShutdown) | 293 if (state_ == kShutdown) |
| 270 return; | 294 return; |
| 271 | 295 |
| 272 DCHECK_EQ(state_, kStarting); | 296 DCHECK_EQ(state_, kStarting); |
| 273 VLOG(1) << "State changed to recording"; | 297 VLOG(1) << "State changed to recording"; |
| 274 state_ = kRecording; | 298 state_ = kRecording; |
| 275 | 299 |
| 300 const Extension* extension = profile_->GetExtensionService()-> |
| 301 GetExtensionById(extension_id_in_use_, true); |
| 302 DCHECK(extension); |
| 303 |
| 304 bool show_notification = !profile_->GetPrefs()->GetBoolean( |
| 305 prefs::kSpeechInputTrayNotificationShown); |
| 306 |
| 307 notification_.Show(extension, show_notification); |
| 308 |
| 309 if (show_notification) { |
| 310 profile_->GetPrefs()->SetBoolean( |
| 311 prefs::kSpeechInputTrayNotificationShown, true); |
| 312 } |
| 313 |
| 276 VLOG(1) << "Sending start notification"; | 314 VLOG(1) << "Sending start notification"; |
| 277 content::NotificationService::current()->Notify( | 315 content::NotificationService::current()->Notify( |
| 278 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED, | 316 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED, |
| 279 content::Source<Profile>(profile_), | 317 content::Source<Profile>(profile_), |
| 280 content::Details<std::string>(&extension_id_in_use_)); | 318 content::Details<std::string>(&extension_id_in_use_)); |
| 281 } | 319 } |
| 282 | 320 |
| 283 void ExtensionSpeechInputManager::OnRecognizerError( | 321 void SpeechInputExtensionManager::OnRecognizerError( |
| 284 int caller_id, SpeechInputError error) { | 322 int caller_id, SpeechInputError error) { |
| 285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 286 DCHECK_EQ(caller_id, kSpeechCallerId); | 324 DCHECK_EQ(caller_id, kSpeechCallerId); |
| 287 VLOG(1) << "OnRecognizerError: " << error; | 325 VLOG(1) << "OnRecognizerError: " << error; |
| 288 | 326 |
| 289 base::AutoLock auto_lock(state_lock_); | 327 base::AutoLock auto_lock(state_lock_); |
| 290 if (state_ == kShutdown) | 328 if (state_ == kShutdown) |
| 291 return; | 329 return; |
| 292 | 330 |
| 293 // Release the recognizer object. | 331 // Release the recognizer object. |
| 294 GetExtensionSpeechInterface()->StopRecording(true); | 332 GetSpeechExtensionInterface()->StopRecording(true); |
| 295 | 333 |
| 296 std::string event_error_code; | 334 std::string event_error_code; |
| 297 bool report_to_event = true; | 335 bool report_to_event = true; |
| 298 | 336 |
| 299 switch (error) { | 337 switch (error) { |
| 300 case kErrorNone: | 338 case kErrorNone: |
| 301 break; | 339 break; |
| 302 | 340 |
| 303 case kErrorAudio: | 341 case kErrorAudio: |
| 304 if (state_ == kStarting) { | 342 if (state_ == kStarting) { |
| 305 event_error_code = constants::kErrorUnableToStart; | 343 event_error_code = kErrorUnableToStart; |
| 306 report_to_event = false; | 344 report_to_event = false; |
| 307 } else { | 345 } else { |
| 308 event_error_code = constants::kErrorCaptureError; | 346 event_error_code = kErrorCaptureError; |
| 309 } | 347 } |
| 310 break; | 348 break; |
| 311 | 349 |
| 312 case kErrorNetwork: | 350 case kErrorNetwork: |
| 313 event_error_code = constants::kErrorNetworkError; | 351 event_error_code = kErrorNetworkError; |
| 314 break; | 352 break; |
| 315 | 353 |
| 316 case kErrorBadGrammar: | 354 case kErrorBadGrammar: |
| 317 // No error is returned on invalid language, for example. | 355 // No error is returned on invalid language, for example. |
| 318 // To avoid confusion about when this is would be fired, the invalid | 356 // To avoid confusion about when this is would be fired, the invalid |
| 319 // params error is not being exposed to the onError event. | 357 // params error is not being exposed to the onError event. |
| 320 event_error_code = constants::kErrorUnableToStart; | 358 event_error_code = kErrorUnableToStart; |
| 321 break; | 359 break; |
| 322 | 360 |
| 323 case kErrorNoSpeech: | 361 case kErrorNoSpeech: |
| 324 event_error_code = constants::kErrorNoSpeechHeard; | 362 event_error_code = kErrorNoSpeechHeard; |
| 325 break; | 363 break; |
| 326 | 364 |
| 327 case kErrorNoMatch: | 365 case kErrorNoMatch: |
| 328 event_error_code = constants::kErrorNoResults; | 366 event_error_code = kErrorNoResults; |
| 329 break; | 367 break; |
| 330 | 368 |
| 331 // The remaining kErrorAborted case should never be returned by the server. | 369 // The remaining kErrorAborted case should never be returned by the server. |
| 332 default: | 370 default: |
| 333 NOTREACHED(); | 371 NOTREACHED(); |
| 334 } | 372 } |
| 335 | 373 |
| 336 if (!event_error_code.empty()) { | 374 if (!event_error_code.empty()) { |
| 337 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 375 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 338 base::Bind(&ExtensionSpeechInputManager::DispatchError, | 376 base::Bind(&SpeechInputExtensionManager::DispatchError, |
| 339 this, event_error_code, report_to_event)); | 377 this, event_error_code, report_to_event)); |
| 340 } | 378 } |
| 341 } | 379 } |
| 342 | 380 |
| 343 void ExtensionSpeechInputManager::DidCompleteEnvironmentEstimation( | 381 void SpeechInputExtensionManager::DidCompleteEnvironmentEstimation( |
| 344 int caller_id) { | 382 int caller_id) { |
| 345 DCHECK_EQ(caller_id, kSpeechCallerId); | 383 DCHECK_EQ(caller_id, kSpeechCallerId); |
| 346 } | 384 } |
| 347 | 385 |
| 348 void ExtensionSpeechInputManager::DidStartReceivingSpeech(int caller_id) { | 386 void SpeechInputExtensionManager::DidStartReceivingSpeech(int caller_id) { |
| 349 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 387 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 350 DCHECK_EQ(caller_id, kSpeechCallerId); | 388 DCHECK_EQ(caller_id, kSpeechCallerId); |
| 351 VLOG(1) << "DidStartReceivingSpeech"; | 389 VLOG(1) << "DidStartReceivingSpeech"; |
| 352 | 390 |
| 353 std::string json_args; | 391 std::string json_args; |
| 354 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 392 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 355 base::Bind(&ExtensionSpeechInputManager::DispatchEventToExtension, | 393 base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension, |
| 356 this, extension_id_in_use_, std::string(constants::kOnSoundStartEvent), | 394 this, extension_id_in_use_, std::string(kOnSoundStartEvent), |
| 357 json_args)); | 395 json_args)); |
| 358 } | 396 } |
| 359 | 397 |
| 360 void ExtensionSpeechInputManager::DidStopReceivingSpeech(int caller_id) { | 398 void SpeechInputExtensionManager::DidStopReceivingSpeech(int caller_id) { |
| 361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 399 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 362 DCHECK_EQ(caller_id, kSpeechCallerId); | 400 DCHECK_EQ(caller_id, kSpeechCallerId); |
| 363 VLOG(1) << "DidStopReceivingSpeech"; | 401 VLOG(1) << "DidStopReceivingSpeech"; |
| 364 | 402 |
| 365 std::string json_args; | 403 std::string json_args; |
| 366 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 404 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 367 base::Bind(&ExtensionSpeechInputManager::DispatchEventToExtension, | 405 base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension, |
| 368 this, extension_id_in_use_, std::string(constants::kOnSoundEndEvent), | 406 this, extension_id_in_use_, std::string(kOnSoundEndEvent), |
| 369 json_args)); | 407 json_args)); |
| 370 } | 408 } |
| 371 | 409 |
| 372 void ExtensionSpeechInputManager::DispatchEventToExtension( | 410 void SpeechInputExtensionManager::DispatchEventToExtension( |
| 373 const std::string& extension_id, const std::string& event, | 411 const std::string& extension_id, const std::string& event, |
| 374 const std::string& json_args) { | 412 const std::string& json_args) { |
| 375 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 376 | 414 |
| 377 base::AutoLock auto_lock(state_lock_); | 415 base::AutoLock auto_lock(state_lock_); |
| 378 if (state_ == kShutdown) | 416 if (state_ == kShutdown) |
| 379 return; | 417 return; |
| 380 | 418 |
| 381 if (profile_ && profile_->GetExtensionEventRouter()) { | 419 if (profile_ && profile_->GetExtensionEventRouter()) { |
| 382 std::string final_args; | 420 std::string final_args; |
| 383 if (json_args.empty()) { | 421 if (json_args.empty()) { |
| 384 ListValue args; | 422 ListValue args; |
| 385 base::JSONWriter::Write(&args, false, &final_args); | 423 base::JSONWriter::Write(&args, false, &final_args); |
| 386 } else { | 424 } else { |
| 387 final_args = json_args; | 425 final_args = json_args; |
| 388 } | 426 } |
| 389 | 427 |
| 390 profile_->GetExtensionEventRouter()->DispatchEventToExtension( | 428 profile_->GetExtensionEventRouter()->DispatchEventToExtension( |
| 391 extension_id, event, final_args, profile_, GURL()); | 429 extension_id, event, final_args, profile_, GURL()); |
| 392 } | 430 } |
| 393 } | 431 } |
| 394 | 432 |
| 395 void ExtensionSpeechInputManager::DispatchError( | 433 void SpeechInputExtensionManager::DispatchError( |
| 396 const std::string& error, bool dispatch_event) { | 434 const std::string& error, bool dispatch_event) { |
| 397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 435 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 398 | 436 |
| 399 std::string extension_id; | 437 std::string extension_id; |
| 400 { | 438 { |
| 401 base::AutoLock auto_lock(state_lock_); | 439 base::AutoLock auto_lock(state_lock_); |
| 402 if (state_ == kShutdown) | 440 if (state_ == kShutdown) |
| 403 return; | 441 return; |
| 404 | 442 |
| 443 if (state_ == kRecording) |
| 444 notification_.Hide(); |
| 445 |
| 405 extension_id = extension_id_in_use_; | 446 extension_id = extension_id_in_use_; |
| 406 ResetToIdleState(); | 447 ResetToIdleState(); |
| 407 | 448 |
| 408 // Will set the error property in the ongoing extension function calls. | 449 // Will set the error property in the ongoing extension function calls. |
| 409 ExtensionError details(extension_id, error); | 450 ExtensionError details(extension_id, error); |
| 410 content::NotificationService::current()->Notify( | 451 content::NotificationService::current()->Notify( |
| 411 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_FAILED, | 452 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_FAILED, |
| 412 content::Source<Profile>(profile_), | 453 content::Source<Profile>(profile_), |
| 413 content::Details<ExtensionError>(&details)); | 454 content::Details<ExtensionError>(&details)); |
| 414 } | 455 } |
| 415 | 456 |
| 416 // Used for errors that are also reported via the onError event. | 457 // Used for errors that are also reported via the onError event. |
| 417 if (dispatch_event) { | 458 if (dispatch_event) { |
| 418 ListValue args; | 459 ListValue args; |
| 419 DictionaryValue *js_error = new DictionaryValue(); | 460 DictionaryValue *js_error = new DictionaryValue(); |
| 420 args.Append(js_error); | 461 args.Append(js_error); |
| 421 js_error->SetString(constants::kErrorCodeKey, error); | 462 js_error->SetString(kErrorCodeKey, error); |
| 422 std::string json_args; | 463 std::string json_args; |
| 423 base::JSONWriter::Write(&args, false, &json_args); | 464 base::JSONWriter::Write(&args, false, &json_args); |
| 424 DispatchEventToExtension(extension_id, | 465 DispatchEventToExtension(extension_id, |
| 425 constants::kOnErrorEvent, json_args); | 466 kOnErrorEvent, json_args); |
| 426 } | 467 } |
| 427 } | 468 } |
| 428 | 469 |
| 429 bool ExtensionSpeechInputManager::Start(const std::string& extension_id, | 470 bool SpeechInputExtensionManager::Start(const std::string& extension_id, |
| 430 const std::string& language, const std::string& grammar, | 471 const std::string& language, const std::string& grammar, |
| 431 bool filter_profanities, std::string* error) { | 472 bool filter_profanities, std::string* error) { |
| 432 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 473 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 433 DCHECK(error); | 474 DCHECK(error); |
| 434 VLOG(1) << "Requesting start (UI thread)"; | 475 VLOG(1) << "Requesting start (UI thread)"; |
| 435 | 476 |
| 436 base::AutoLock auto_lock(state_lock_); | 477 base::AutoLock auto_lock(state_lock_); |
| 437 if (state_ == kShutdown || | 478 if (state_ == kShutdown || |
| 438 (!extension_id_in_use_.empty() && extension_id_in_use_ != extension_id)) { | 479 (!extension_id_in_use_.empty() && extension_id_in_use_ != extension_id)) { |
| 439 *error = constants::kErrorRequestDenied; | 480 *error = kErrorRequestDenied; |
| 440 return false; | 481 return false; |
| 441 } | 482 } |
| 442 | 483 |
| 443 switch (state_) { | 484 switch (state_) { |
| 444 case kIdle: | 485 case kIdle: |
| 445 break; | 486 break; |
| 446 | 487 |
| 447 case kStarting: | 488 case kStarting: |
| 448 *error = constants::kErrorRequestInProgress; | 489 *error = kErrorRequestInProgress; |
| 449 return false; | 490 return false; |
| 450 | 491 |
| 451 case kRecording: | 492 case kRecording: |
| 452 case kStopping: | 493 case kStopping: |
| 453 *error = constants::kErrorInvalidOperation; | 494 *error = kErrorInvalidOperation; |
| 454 return false; | 495 return false; |
| 455 | 496 |
| 456 default: | 497 default: |
| 457 NOTREACHED(); | 498 NOTREACHED(); |
| 458 } | 499 } |
| 459 | 500 |
| 460 extension_id_in_use_ = extension_id; | 501 extension_id_in_use_ = extension_id; |
| 461 VLOG(1) << "State changed to starting"; | 502 VLOG(1) << "State changed to starting"; |
| 462 state_ = kStarting; | 503 state_ = kStarting; |
| 463 | 504 |
| 464 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 505 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 465 base::Bind(&ExtensionSpeechInputManager::StartOnIOThread, this, | 506 base::Bind(&SpeechInputExtensionManager::StartOnIOThread, this, |
| 466 profile_->GetRequestContext(), language, grammar, filter_profanities)); | 507 profile_->GetRequestContext(), language, grammar, filter_profanities)); |
| 467 return true; | 508 return true; |
| 468 } | 509 } |
| 469 | 510 |
| 470 void ExtensionSpeechInputManager::StartOnIOThread( | 511 void SpeechInputExtensionManager::StartOnIOThread( |
| 471 net::URLRequestContextGetter* context_getter, | 512 net::URLRequestContextGetter* context_getter, |
| 472 const std::string& language, const std::string& grammar, | 513 const std::string& language, const std::string& grammar, |
| 473 bool filter_profanities) { | 514 bool filter_profanities) { |
| 474 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 515 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 475 VLOG(1) << "Requesting start (IO thread)"; | 516 VLOG(1) << "Requesting start (IO thread)"; |
| 476 | 517 |
| 477 // Everything put inside the lock to ensure the validity of context_getter, | 518 // Everything put inside the lock to ensure the validity of context_getter, |
| 478 // guaranteed while not in the shutdown state. Any ongoing or recognition | 519 // guaranteed while not in the shutdown state. Any ongoing or recognition |
| 479 // request will be requested to be aborted when entering the shutdown state. | 520 // request will be requested to be aborted when entering the shutdown state. |
| 480 base::AutoLock auto_lock(state_lock_); | 521 base::AutoLock auto_lock(state_lock_); |
| 481 if (state_ == kShutdown) | 522 if (state_ == kShutdown) |
| 482 return; | 523 return; |
| 483 | 524 |
| 484 if (!GetExtensionSpeechInterface()->HasAudioInputDevices()) { | 525 if (!GetSpeechExtensionInterface()->HasAudioInputDevices()) { |
| 485 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 526 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 486 base::Bind(&ExtensionSpeechInputManager::DispatchError, this, | 527 base::Bind(&SpeechInputExtensionManager::DispatchError, this, |
| 487 std::string(constants::kErrorNoRecordingDeviceFound), false)); | 528 std::string(kErrorNoRecordingDeviceFound), false)); |
| 488 return; | 529 return; |
| 489 } | 530 } |
| 490 | 531 |
| 491 if (GetExtensionSpeechInterface()->IsRecordingInProcess()) { | 532 if (GetSpeechExtensionInterface()->IsRecordingInProcess()) { |
| 492 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 533 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 493 base::Bind(&ExtensionSpeechInputManager::DispatchError, this, | 534 base::Bind(&SpeechInputExtensionManager::DispatchError, this, |
| 494 std::string(constants::kErrorRecordingDeviceInUse), false)); | 535 std::string(kErrorRecordingDeviceInUse), false)); |
| 495 return; | 536 return; |
| 496 } | 537 } |
| 497 | 538 |
| 498 GetExtensionSpeechInterface()->StartRecording(this, context_getter, | 539 GetSpeechExtensionInterface()->StartRecording(this, context_getter, |
| 499 kSpeechCallerId, language, grammar, filter_profanities); | 540 kSpeechCallerId, language, grammar, filter_profanities); |
| 500 } | 541 } |
| 501 | 542 |
| 502 bool ExtensionSpeechInputManager::HasAudioInputDevices() { | 543 bool SpeechInputExtensionManager::HasAudioInputDevices() { |
| 503 return AudioManager::GetAudioManager()->HasAudioInputDevices(); | 544 return AudioManager::GetAudioManager()->HasAudioInputDevices(); |
| 504 } | 545 } |
| 505 | 546 |
| 506 bool ExtensionSpeechInputManager::IsRecordingInProcess() { | 547 bool SpeechInputExtensionManager::IsRecordingInProcess() { |
| 507 // Thread-safe query. | 548 // Thread-safe query. |
| 508 return AudioManager::GetAudioManager()->IsRecordingInProcess(); | 549 return AudioManager::GetAudioManager()->IsRecordingInProcess(); |
| 509 } | 550 } |
| 510 | 551 |
| 511 bool ExtensionSpeechInputManager::IsRecording() { | 552 bool SpeechInputExtensionManager::IsRecording() { |
| 512 return GetExtensionSpeechInterface()->IsRecordingInProcess(); | 553 return GetSpeechExtensionInterface()->IsRecordingInProcess(); |
| 513 } | 554 } |
| 514 | 555 |
| 515 void ExtensionSpeechInputManager::StartRecording( | 556 void SpeechInputExtensionManager::StartRecording( |
| 516 speech_input::SpeechRecognizerDelegate* delegate, | 557 speech_input::SpeechRecognizerDelegate* delegate, |
| 517 net::URLRequestContextGetter* context_getter, int caller_id, | 558 net::URLRequestContextGetter* context_getter, int caller_id, |
| 518 const std::string& language, const std::string& grammar, | 559 const std::string& language, const std::string& grammar, |
| 519 bool filter_profanities) { | 560 bool filter_profanities) { |
| 520 DCHECK(!recognizer_); | 561 DCHECK(!recognizer_); |
| 521 recognizer_ = new SpeechRecognizer(delegate, caller_id, language, grammar, | 562 recognizer_ = new SpeechRecognizer(delegate, caller_id, language, grammar, |
| 522 context_getter, filter_profanities, "", ""); | 563 context_getter, filter_profanities, "", ""); |
| 523 recognizer_->StartRecording(); | 564 recognizer_->StartRecording(); |
| 524 } | 565 } |
| 525 | 566 |
| 526 bool ExtensionSpeechInputManager::HasValidRecognizer() { | 567 bool SpeechInputExtensionManager::HasValidRecognizer() { |
| 527 // Conditional expression used to avoid a performance warning on windows. | 568 // Conditional expression used to avoid a performance warning on windows. |
| 528 return recognizer_ ? true : false; | 569 return recognizer_ ? true : false; |
| 529 } | 570 } |
| 530 | 571 |
| 531 bool ExtensionSpeechInputManager::Stop(const std::string& extension_id, | 572 bool SpeechInputExtensionManager::Stop(const std::string& extension_id, |
| 532 std::string* error) { | 573 std::string* error) { |
| 533 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 574 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 534 DCHECK(error); | 575 DCHECK(error); |
| 535 VLOG(1) << "Requesting stop (UI thread)"; | 576 VLOG(1) << "Requesting stop (UI thread)"; |
| 536 | 577 |
| 537 base::AutoLock auto_lock(state_lock_); | 578 base::AutoLock auto_lock(state_lock_); |
| 538 if (state_ == kShutdown || | 579 if (state_ == kShutdown || |
| 539 (!extension_id_in_use_.empty() && extension_id_in_use_ != extension_id)) { | 580 (!extension_id_in_use_.empty() && extension_id_in_use_ != extension_id)) { |
| 540 *error = constants::kErrorRequestDenied; | 581 *error = kErrorRequestDenied; |
| 541 return false; | 582 return false; |
| 542 } | 583 } |
| 543 | 584 |
| 544 switch (state_) { | 585 switch (state_) { |
| 545 case kRecording: | 586 case kRecording: |
| 546 break; | 587 break; |
| 547 | 588 |
| 548 case kStopping: | 589 case kStopping: |
| 549 *error = constants::kErrorRequestInProgress; | 590 *error = kErrorRequestInProgress; |
| 550 return false; | 591 return false; |
| 551 | 592 |
| 552 case kIdle: | 593 case kIdle: |
| 553 case kStarting: | 594 case kStarting: |
| 554 *error = constants::kErrorInvalidOperation; | 595 *error = kErrorInvalidOperation; |
| 555 return false; | 596 return false; |
| 556 | 597 |
| 557 default: | 598 default: |
| 558 NOTREACHED(); | 599 NOTREACHED(); |
| 559 } | 600 } |
| 560 | 601 |
| 561 // Guarded by the state lock. | 602 // Guarded by the state lock. |
| 562 DCHECK(GetExtensionSpeechInterface()->HasValidRecognizer()); | 603 DCHECK(GetSpeechExtensionInterface()->HasValidRecognizer()); |
| 563 | 604 |
| 564 VLOG(1) << "State changed to stopping"; | 605 VLOG(1) << "State changed to stopping"; |
| 565 state_ = kStopping; | 606 state_ = kStopping; |
| 566 | 607 |
| 567 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 608 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 568 base::Bind(&ExtensionSpeechInputManager::ForceStopOnIOThread, this)); | 609 base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); |
| 569 return true; | 610 return true; |
| 570 } | 611 } |
| 571 | 612 |
| 572 void ExtensionSpeechInputManager::ForceStopOnIOThread() { | 613 void SpeechInputExtensionManager::ForceStopOnIOThread() { |
| 573 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 614 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 574 VLOG(1) << "Requesting forced stop (IO thread)"; | 615 VLOG(1) << "Requesting forced stop (IO thread)"; |
| 575 | 616 |
| 576 base::AutoLock auto_lock(state_lock_); | 617 base::AutoLock auto_lock(state_lock_); |
| 577 DCHECK(state_ != kIdle); | 618 DCHECK(state_ != kIdle); |
| 578 | 619 |
| 579 GetExtensionSpeechInterface()->StopRecording(false); | 620 GetSpeechExtensionInterface()->StopRecording(false); |
| 580 | 621 |
| 581 if (state_ == kShutdown) | 622 if (state_ == kShutdown) |
| 582 return; | 623 return; |
| 583 | 624 |
| 584 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 625 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 585 base::Bind(&ExtensionSpeechInputManager::StopSucceededOnUIThread, this)); | 626 base::Bind(&SpeechInputExtensionManager::StopSucceededOnUIThread, this)); |
| 586 } | 627 } |
| 587 | 628 |
| 588 void ExtensionSpeechInputManager::StopRecording(bool recognition_failed) { | 629 void SpeechInputExtensionManager::StopRecording(bool recognition_failed) { |
| 589 if (recognizer_) { | 630 if (recognizer_) { |
| 590 // Recognition is already cancelled in case of failure. | 631 // Recognition is already cancelled in case of failure. |
| 591 // Double-cancelling leads to assertion failures. | 632 // Double-cancelling leads to assertion failures. |
| 592 if (!recognition_failed) | 633 if (!recognition_failed) |
| 593 recognizer_->CancelRecognition(); | 634 recognizer_->CancelRecognition(); |
| 594 recognizer_.release(); | 635 recognizer_.release(); |
| 595 } | 636 } |
| 596 } | 637 } |
| 597 | 638 |
| 598 void ExtensionSpeechInputManager::StopSucceededOnUIThread() { | 639 void SpeechInputExtensionManager::StopSucceededOnUIThread() { |
| 599 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 640 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 600 VLOG(1) << "Stop succeeded (UI thread)"; | 641 VLOG(1) << "Stop succeeded (UI thread)"; |
| 601 | 642 |
| 602 base::AutoLock auto_lock(state_lock_); | 643 base::AutoLock auto_lock(state_lock_); |
| 603 if (state_ == kShutdown) | 644 if (state_ == kShutdown) |
| 604 return; | 645 return; |
| 605 | 646 |
| 606 std::string extension_id = extension_id_in_use_; | 647 std::string extension_id = extension_id_in_use_; |
| 607 ResetToIdleState(); | 648 ResetToIdleState(); |
| 608 | 649 |
| 650 notification_.Hide(); |
| 651 |
| 609 content::NotificationService::current()->Notify( | 652 content::NotificationService::current()->Notify( |
| 610 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED, | 653 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED, |
| 611 // Guarded by the state_ == kShutdown check. | 654 // Guarded by the state_ == kShutdown check. |
| 612 content::Source<Profile>(profile_), | 655 content::Source<Profile>(profile_), |
| 613 content::Details<std::string>(&extension_id)); | 656 content::Details<std::string>(&extension_id)); |
| 614 } | 657 } |
| 658 |
| 659 void SpeechInputExtensionManager::SetInputVolume(int caller_id, |
| 660 float volume, |
| 661 float noise_volume) { |
| 662 DCHECK_EQ(caller_id, kSpeechCallerId); |
| 663 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 664 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 665 base::Bind(&SpeechInputExtensionManager::SetInputVolumeOnUIThread, |
| 666 this, volume)); |
| 667 } |
| 668 |
| 669 void SpeechInputExtensionManager::SetInputVolumeOnUIThread( |
| 670 float volume) { |
| 671 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 672 notification_.SetVUMeterVolume(volume); |
| 673 } |
| OLD | NEW |