Chromium Code Reviews| 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/extension_speech_input_manager.h" | 5 #include "chrome/browser/extensions/extension_speech_input_manager.h" |
| 6 | 6 |
| 7 #include "base/json/json_writer.h" | |
| 8 #include "base/utf_string_conversions.h" | |
| 9 #include "base/values.h" | |
| 10 #include "chrome/browser/extensions/extension_event_router.h" | |
| 11 #include "chrome/browser/extensions/extension_speech_input_api_constants.h" | |
| 12 #include "chrome/browser/profiles/profile.h" | |
| 7 #include "chrome/browser/profiles/profile_dependency_manager.h" | 13 #include "chrome/browser/profiles/profile_dependency_manager.h" |
| 8 #include "chrome/browser/profiles/profile_keyed_service.h" | 14 #include "chrome/browser/profiles/profile_keyed_service.h" |
| 9 #include "chrome/browser/profiles/profile_keyed_service_factory.h" | 15 #include "chrome/browser/profiles/profile_keyed_service_factory.h" |
| 10 #include "chrome/common/chrome_notification_types.h" | 16 #include "chrome/common/chrome_notification_types.h" |
| 11 #include "chrome/common/extensions/extension.h" | 17 #include "chrome/common/extensions/extension.h" |
| 18 #include "content/browser/browser_thread.h" | |
| 12 #include "content/common/notification_service.h" | 19 #include "content/common/notification_service.h" |
| 13 | 20 |
| 21 using namespace speech_input; | |
| 22 namespace constants = extension_speech_input_api_constants; | |
| 23 | |
| 14 namespace { | 24 namespace { |
| 15 | 25 |
| 16 // Wrap an ExtensionSpeechInputManager using scoped_refptr to avoid | 26 // Wrap an ExtensionSpeechInputManager using scoped_refptr to avoid |
| 17 // assertion failures on destruction because of not using release(). | 27 // assertion failures on destruction because of not using release(). |
| 18 class ExtensionSpeechInputManagerWrapper : public ProfileKeyedService { | 28 class ExtensionSpeechInputManagerWrapper : public ProfileKeyedService { |
| 19 public: | 29 public: |
| 20 explicit ExtensionSpeechInputManagerWrapper( | 30 explicit ExtensionSpeechInputManagerWrapper( |
| 21 ExtensionSpeechInputManager* manager) | 31 ExtensionSpeechInputManager* manager) |
| 22 : manager_(manager) {} | 32 : manager_(manager) {} |
| 23 | 33 |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 50 Factory(); | 60 Factory(); |
| 51 virtual ~Factory(); | 61 virtual ~Factory(); |
| 52 | 62 |
| 53 // ProfileKeyedServiceFactory methods: | 63 // ProfileKeyedServiceFactory methods: |
| 54 virtual ProfileKeyedService* BuildServiceInstanceFor( | 64 virtual ProfileKeyedService* BuildServiceInstanceFor( |
| 55 Profile* profile) const; | 65 Profile* profile) const; |
| 56 virtual bool ServiceRedirectedInIncognito() { return false; } | 66 virtual bool ServiceRedirectedInIncognito() { return false; } |
| 57 virtual bool ServiceIsNULLWhileTesting() { return true; } | 67 virtual bool ServiceIsNULLWhileTesting() { return true; } |
| 58 virtual bool ServiceIsCreatedWithProfile() { return true; } | 68 virtual bool ServiceIsCreatedWithProfile() { return true; } |
| 59 | 69 |
| 70 // Since speech input extension API managers are created per-profile, | |
| 71 // a unique id is required for each of them to avoid mixing results | |
| 72 // from extensions being used on different profiles simultaneously. | |
| 73 static int per_profile_id_; | |
|
Satish
2011/10/09 20:01:47
The caller id give to SpeechRecognizer is useful o
Leandro Graciá Gil
2011/10/10 18:59:38
Done.
| |
| 74 | |
| 60 DISALLOW_COPY_AND_ASSIGN(Factory); | 75 DISALLOW_COPY_AND_ASSIGN(Factory); |
| 61 }; | 76 }; |
| 62 | 77 |
| 78 int ExtensionSpeechInputManager::Factory::per_profile_id_ = 0; | |
| 79 | |
| 63 void ExtensionSpeechInputManager::Factory::Initialize() { | 80 void ExtensionSpeechInputManager::Factory::Initialize() { |
| 64 GetInstance(); | 81 GetInstance(); |
| 65 } | 82 } |
| 66 | 83 |
| 67 ExtensionSpeechInputManager::Factory* | 84 ExtensionSpeechInputManager::Factory* |
| 68 ExtensionSpeechInputManager::Factory::GetInstance() { | 85 ExtensionSpeechInputManager::Factory::GetInstance() { |
| 69 return Singleton<ExtensionSpeechInputManager::Factory>::get(); | 86 return Singleton<ExtensionSpeechInputManager::Factory>::get(); |
| 70 } | 87 } |
| 71 | 88 |
| 72 ExtensionSpeechInputManagerWrapper* | 89 ExtensionSpeechInputManagerWrapper* |
| 73 ExtensionSpeechInputManager::Factory::GetForProfile( | 90 ExtensionSpeechInputManager::Factory::GetForProfile( |
| 74 Profile* profile) { | 91 Profile* profile) { |
| 75 return static_cast<ExtensionSpeechInputManagerWrapper*>( | 92 return static_cast<ExtensionSpeechInputManagerWrapper*>( |
| 76 GetServiceForProfile(profile, true)); | 93 GetServiceForProfile(profile, true)); |
| 77 } | 94 } |
| 78 | 95 |
| 79 ExtensionSpeechInputManager::Factory::Factory() | 96 ExtensionSpeechInputManager::Factory::Factory() |
| 80 : ProfileKeyedServiceFactory(ProfileDependencyManager::GetInstance()) { | 97 : ProfileKeyedServiceFactory(ProfileDependencyManager::GetInstance()) { |
| 81 } | 98 } |
| 82 | 99 |
| 83 ExtensionSpeechInputManager::Factory::~Factory() { | 100 ExtensionSpeechInputManager::Factory::~Factory() { |
| 84 } | 101 } |
| 85 | 102 |
| 86 ProfileKeyedService* | 103 ProfileKeyedService* |
| 87 ExtensionSpeechInputManager::Factory::BuildServiceInstanceFor( | 104 ExtensionSpeechInputManager::Factory::BuildServiceInstanceFor( |
| 88 Profile* profile) const { | 105 Profile* profile) const { |
| 89 scoped_refptr<ExtensionSpeechInputManager> manager( | 106 scoped_refptr<ExtensionSpeechInputManager> manager( |
| 90 new ExtensionSpeechInputManager(profile)); | 107 new ExtensionSpeechInputManager(profile, ++per_profile_id_)); |
| 91 return new ExtensionSpeechInputManagerWrapper(manager); | 108 return new ExtensionSpeechInputManagerWrapper(manager); |
| 92 } | 109 } |
| 93 | 110 |
| 94 ExtensionSpeechInputManager::ExtensionSpeechInputManager(Profile* profile) | 111 ExtensionSpeechInputManager::ExtensionSpeechInputManager(Profile* profile, |
| 112 int speech_caller_id) | |
| 95 : profile_(profile), | 113 : profile_(profile), |
| 96 extension_(NULL) { | 114 speech_caller_id_(speech_caller_id), |
| 115 state_(kIdle) { | |
| 97 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | 116 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
| 98 Source<Profile>(profile_)); | 117 Source<Profile>(profile_)); |
| 99 } | 118 } |
| 100 | 119 |
| 101 ExtensionSpeechInputManager::~ExtensionSpeechInputManager() { | 120 ExtensionSpeechInputManager::~ExtensionSpeechInputManager() { |
| 102 } | 121 } |
| 103 | 122 |
| 104 ExtensionSpeechInputManager* ExtensionSpeechInputManager::GetForProfile( | 123 ExtensionSpeechInputManager* ExtensionSpeechInputManager::GetForProfile( |
| 105 Profile* profile) { | 124 Profile* profile) { |
| 106 ExtensionSpeechInputManagerWrapper *wrapper = | 125 ExtensionSpeechInputManagerWrapper *wrapper = |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 117 void ExtensionSpeechInputManager::Observe(int type, | 136 void ExtensionSpeechInputManager::Observe(int type, |
| 118 const NotificationSource& source, | 137 const NotificationSource& source, |
| 119 const NotificationDetails& details) { | 138 const NotificationDetails& details) { |
| 120 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) | 139 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) |
| 121 ExtensionUnloaded(Details<UnloadedExtensionInfo>(details)->extension->id()); | 140 ExtensionUnloaded(Details<UnloadedExtensionInfo>(details)->extension->id()); |
| 122 else | 141 else |
| 123 NOTREACHED(); | 142 NOTREACHED(); |
| 124 } | 143 } |
| 125 | 144 |
| 126 void ExtensionSpeechInputManager::ShutdownOnUIThread() { | 145 void ExtensionSpeechInputManager::ShutdownOnUIThread() { |
| 127 // TODO(leandrogracia): Force stop to speech recognition if active. | 146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 147 VLOG(1) << "Profile shutting down."; | |
| 148 | |
| 149 state_lock_.Acquire(); | |
|
Satish
2011/10/09 20:01:47
use base::AutoLock instead of acquiring and releas
Leandro Graciá Gil
2011/10/10 18:59:38
Done.
| |
| 150 DCHECK(state_ != kShutdown); | |
| 151 if (state_ != kIdle) { | |
| 152 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
| 153 NewRunnableMethod(this, | |
| 154 &ExtensionSpeechInputManager::ForceStopOnIOThread)); | |
| 155 } | |
| 156 state_ = kShutdown; | |
| 157 VLOG(1) << "Entering the shutdown sink state."; | |
| 128 registrar_.RemoveAll(); | 158 registrar_.RemoveAll(); |
| 129 profile_ = NULL; | 159 profile_ = NULL; |
| 160 state_lock_.Release(); | |
| 161 } | |
| 162 | |
| 163 bool ExtensionSpeechInputManager::ShuttingDown() { | |
| 164 state_lock_.Acquire(); | |
| 165 bool shutting_down = state_ == kShutdown; | |
| 166 state_lock_.Release(); | |
| 167 return shutting_down; | |
| 130 } | 168 } |
| 131 | 169 |
| 132 void ExtensionSpeechInputManager::ExtensionUnloaded(const std::string& id) { | 170 void ExtensionSpeechInputManager::ExtensionUnloaded(const std::string& id) { |
| 133 // TODO(leandrogracia): Force stop to speech recognition if the extension | 171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 134 // is currently using the API. | 172 |
| 135 } | 173 VLOG(1) << "Extension unloaded. Requesting to enforce stop..."; |
|
Satish
2011/10/09 20:01:47
should this be after the below if block?
Leandro Graciá Gil
2011/10/10 18:59:38
Done.
| |
| 136 | 174 state_lock_.Acquire(); |
| 137 void ExtensionSpeechInputManager::Start(const Extension *extension) { | 175 if (state_ == kShutdown) { |
| 138 // TODO(leandrogracia): Start speech recognition. | 176 state_lock_.Release(); |
| 139 } | 177 return; |
| 140 | 178 } |
| 141 void ExtensionSpeechInputManager::Stop(const Extension *extension) { | 179 |
| 142 // TODO(leandrogracia): Stop speech recognition. | 180 if (!extension_id_.empty() && extension_id_ == id) { |
|
Satish
2011/10/09 20:01:47
is the .empty() check required since it is a strin
Leandro Graciá Gil
2011/10/10 18:59:38
Done.
| |
| 143 } | 181 extension_id_.clear(); |
|
Satish
2011/10/09 20:01:47
You are clearing this id here but in ForceStopOnIO
Leandro Graciá Gil
2011/10/10 18:59:38
Now clearing only on ForceStopOnIOThread. Fixed.
| |
| 144 | 182 |
| 183 if (state_ != kIdle) { | |
| 184 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
| 185 NewRunnableMethod(this, | |
| 186 &ExtensionSpeechInputManager::ForceStopOnIOThread)); | |
| 187 } | |
| 188 } | |
| 189 state_lock_.Release(); | |
| 190 } | |
| 191 | |
| 192 void ExtensionSpeechInputManager::SetRecognitionResult( | |
| 193 int caller_id, | |
| 194 const SpeechInputResult& result) { | |
| 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 196 DCHECK_EQ(caller_id, speech_caller_id_); | |
| 197 | |
| 198 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 199 NewRunnableMethod(this, | |
| 200 &ExtensionSpeechInputManager::SetRecognitionResultOnUIThread, result)); | |
|
Satish
2011/10/09 20:01:47
You may need to convert all NewRunnableMethod call
Leandro Graciá Gil
2011/10/10 18:59:38
Fixed here. I'll prepare a CL for the speech input
| |
| 201 } | |
| 202 | |
| 203 void ExtensionSpeechInputManager::SetRecognitionResultOnUIThread( | |
| 204 const SpeechInputResult& result) { | |
|
Satish
2011/10/09 20:01:47
fix indentation
Leandro Graciá Gil
2011/10/10 18:59:38
Done.
| |
| 205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 206 | |
| 207 state_lock_.Acquire(); | |
| 208 if (state_ == kShutdown) { | |
| 209 state_lock_.Release(); | |
| 210 return; | |
| 211 } | |
| 212 state_ = kIdle; | |
| 213 state_lock_.Release(); | |
| 214 | |
| 215 ListValue args; | |
| 216 DictionaryValue* js_event = new DictionaryValue(); | |
| 217 args.Append(js_event); | |
| 218 | |
| 219 ListValue* js_hypothesis_array = new ListValue(); | |
| 220 js_event->Set(constants::kHypothesesKey, js_hypothesis_array); | |
| 221 | |
| 222 for (size_t i = 0; i < result.hypotheses.size(); ++i) { | |
| 223 const SpeechInputHypothesis& hypothesis = result.hypotheses[i]; | |
| 224 | |
| 225 DictionaryValue* js_hypothesis_object = new DictionaryValue(); | |
| 226 js_hypothesis_array->Append(js_hypothesis_object); | |
| 227 | |
| 228 js_hypothesis_object->SetString(constants::kUtteranceKey, | |
| 229 UTF16ToUTF8(hypothesis.utterance)); | |
| 230 js_hypothesis_object->SetDouble(constants::kConfidenceKey, | |
| 231 hypothesis.confidence); | |
| 232 } | |
| 233 | |
| 234 std::string json_args; | |
| 235 base::JSONWriter::Write(&args, false, &json_args); | |
| 236 VLOG(1) << "Results: " << json_args; | |
| 237 DispatchEventToExtension(constants::kOnResultEvent, json_args); | |
| 238 } | |
| 239 | |
| 240 void ExtensionSpeechInputManager::DidStartReceivingAudio(int caller_id) { | |
| 241 VLOG(1) << "DidStartReceivingAudio"; | |
| 242 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 243 DCHECK_EQ(caller_id, speech_caller_id_); | |
| 244 | |
| 245 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 246 NewRunnableMethod(this, | |
| 247 &ExtensionSpeechInputManager::DidStartReceivingAudioOnUIThread)); | |
| 248 } | |
| 249 | |
| 250 void ExtensionSpeechInputManager::DidCompleteRecording(int caller_id) { | |
| 251 VLOG(1) << "DidCompleteRecording"; | |
|
Satish
2011/10/09 20:01:47
if you don't intend to add any code here and the n
Leandro Graciá Gil
2011/10/10 18:59:38
Done.
| |
| 252 DCHECK_EQ(caller_id, speech_caller_id_); | |
| 253 } | |
| 254 | |
| 255 void ExtensionSpeechInputManager::DidCompleteRecognition(int caller_id) { | |
| 256 VLOG(1) << "DidCompleteRecognition"; | |
| 257 DCHECK_EQ(caller_id, speech_caller_id_); | |
| 258 } | |
| 259 | |
| 260 void ExtensionSpeechInputManager::DidStartReceivingAudioOnUIThread() { | |
| 261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 262 | |
| 263 state_lock_.Acquire(); | |
| 264 if (state_ == kShutdown) { | |
| 265 state_lock_.Release(); | |
| 266 return; | |
| 267 } | |
| 268 | |
| 269 DCHECK_EQ(state_, kStarting); | |
| 270 VLOG(1) << "State changed to recording"; | |
| 271 state_ = kRecording; | |
| 272 state_lock_.Release(); | |
| 273 | |
| 274 VLOG(1) << "Sending start notification"; | |
| 275 NotificationService::current()->Notify( | |
| 276 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED, | |
| 277 Source<Profile>(profile_), | |
| 278 Details<std::string>(&extension_id_)); | |
| 279 } | |
| 280 | |
| 281 void ExtensionSpeechInputManager::OnRecognizerError( | |
| 282 int caller_id, SpeechInputError error) { | |
| 283 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 284 DCHECK_EQ(caller_id, speech_caller_id_); | |
| 285 VLOG(1) << "OnRecognizerError: " << error; | |
| 286 | |
| 287 state_lock_.Acquire(); | |
| 288 if (state_ == kShutdown) { | |
| 289 state_lock_.Release(); | |
| 290 return; | |
| 291 } | |
| 292 | |
| 293 std::string event_error_code; | |
| 294 switch (error) { | |
| 295 case kErrorNone: | |
|
Satish
2011/10/09 20:01:47
fix indentation of case statements
Leandro Graciá Gil
2011/10/10 18:59:38
Done.
| |
| 296 break; | |
| 297 | |
| 298 case kErrorAudio: | |
| 299 if (state_ == kStarting) | |
|
Satish
2011/10/09 20:01:47
use braces
Leandro Graciá Gil
2011/10/10 18:59:38
Done.
| |
| 300 event_error_code = constants::kErrorUnableToStart; | |
| 301 else | |
| 302 event_error_code = constants::kErrorCaptureError; | |
| 303 break; | |
| 304 | |
| 305 case kErrorNetwork: | |
| 306 event_error_code = constants::kErrorNetworkError; | |
| 307 break; | |
| 308 | |
| 309 case kErrorBadGrammar: | |
| 310 // No error is returned on invalid language, for example. | |
| 311 // To avoid confusion about when this is would be fired, the invalid | |
| 312 // params error is not being exposed to the onError event. | |
| 313 event_error_code = constants::kErrorUnableToStart; | |
| 314 break; | |
| 315 | |
| 316 case kErrorNoSpeech: | |
| 317 event_error_code = constants::kErrorNoSpeechHeard; | |
| 318 break; | |
| 319 | |
| 320 case kErrorNoMatch: | |
| 321 event_error_code = constants::kErrorNoResults; | |
| 322 break; | |
| 323 | |
| 324 // The remaining kErrorAborted case should never be returned by the server. | |
| 325 default: | |
| 326 NOTREACHED(); | |
| 327 } | |
| 328 | |
| 329 VLOG(1) << "State changed to idle"; | |
| 330 state_ = kIdle; | |
| 331 state_lock_.Release(); | |
| 332 | |
| 333 if (!event_error_code.empty()) | |
|
Satish
2011/10/09 20:01:47
ditto
Leandro Graciá Gil
2011/10/10 18:59:38
Done.
| |
| 334 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 335 NewRunnableMethod(this, | |
| 336 &ExtensionSpeechInputManager::DispatchError, event_error_code)); | |
| 337 } | |
| 338 | |
| 339 void ExtensionSpeechInputManager::DidCompleteEnvironmentEstimation( | |
| 340 int caller_id) { | |
| 341 VLOG(1) << "DidCompleteEnvironmentEstimation"; | |
| 342 DCHECK_EQ(caller_id, speech_caller_id_); | |
| 343 } | |
| 344 | |
| 345 void ExtensionSpeechInputManager::DidStartReceivingSpeech(int caller_id) { | |
| 346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 347 DCHECK_EQ(caller_id, speech_caller_id_); | |
| 348 VLOG(1) << "DidStartReceivingSpeech"; | |
| 349 | |
| 350 ListValue args; | |
| 351 std::string json_args; | |
| 352 base::JSONWriter::Write(&args, false, &json_args); | |
|
Satish
2011/10/09 20:01:47
is it really required to send an empty list as arg
Leandro Graciá Gil
2011/10/10 18:59:38
It is required to send the empty list, otherwise y
| |
| 353 | |
| 354 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 355 NewRunnableMethod(this, | |
| 356 &ExtensionSpeechInputManager::DispatchEventToExtension, | |
| 357 std::string(constants::kOnSoundStartEvent), json_args)); | |
| 358 } | |
| 359 | |
| 360 void ExtensionSpeechInputManager::DidStopReceivingSpeech(int caller_id) { | |
| 361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 362 DCHECK_EQ(caller_id, speech_caller_id_); | |
| 363 VLOG(1) << "DidStopReceivingSpeech"; | |
| 364 | |
| 365 ListValue args; | |
| 366 std::string json_args; | |
| 367 base::JSONWriter::Write(&args, false, &json_args); | |
| 368 | |
| 369 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 370 NewRunnableMethod(this, | |
| 371 &ExtensionSpeechInputManager::DispatchEventToExtension, | |
| 372 std::string(constants::kOnSoundEndEvent), json_args)); | |
| 373 } | |
| 374 | |
| 375 void ExtensionSpeechInputManager::DispatchEventToExtension( | |
| 376 const std::string& event, const std::string& json_args) { | |
| 377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 378 | |
| 379 if (ShuttingDown()) | |
| 380 return; | |
| 381 | |
| 382 if (profile_ && profile_->GetExtensionEventRouter()) | |
|
Satish
2011/10/09 20:01:47
use braces
Leandro Graciá Gil
2011/10/10 18:59:38
Done.
| |
| 383 profile_->GetExtensionEventRouter()->DispatchEventToExtension( | |
| 384 extension_id_, event, json_args, profile_, GURL()); | |
| 385 } | |
| 386 | |
| 387 void ExtensionSpeechInputManager::DispatchError(const std::string& code) { | |
| 388 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 389 | |
| 390 if (ShuttingDown()) | |
| 391 return; | |
| 392 | |
| 393 NotificationService::current()->Notify( | |
| 394 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_FAILED, | |
| 395 Source<Profile>(profile_), | |
| 396 Details<std::string>(&extension_id_)); | |
| 397 | |
| 398 ListValue args; | |
| 399 DictionaryValue *js_error = new DictionaryValue(); | |
| 400 args.Append(js_error); | |
| 401 js_error->SetString(constants::kErrorCodeKey, code); | |
| 402 std::string json_args; | |
| 403 base::JSONWriter::Write(&args, false, &json_args); | |
| 404 DispatchEventToExtension(constants::kOnErrorEvent, json_args); | |
| 405 } | |
| 406 | |
| 407 void ExtensionSpeechInputManager::Start(const std::string& extension_id, | |
| 408 const std::string& language, const std::string& grammar, | |
| 409 bool filter_profanities) { | |
| 410 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 411 VLOG(1) << "Requesting start (UI thread)"; | |
| 412 | |
| 413 if (ShuttingDown()) | |
| 414 return; | |
| 415 | |
| 416 if (!extension_id_.empty() && extension_id != extension_id_) { | |
|
Satish
2011/10/09 20:01:47
is the .empty check required as asked above?
Leandro Graciá Gil
2011/10/10 18:59:38
Here it is, otherwise it will generate an error ev
| |
| 417 DispatchError(constants::kErrorRequestDenied); | |
| 418 return; | |
| 419 } | |
| 420 | |
| 421 state_lock_.Acquire(); | |
| 422 if (state_ != kIdle) { | |
|
Satish
2011/10/09 20:01:47
could be simpler to merge this check with the 'if
Leandro Graciá Gil
2011/10/10 18:59:38
Done.
| |
| 423 DCHECK(recognizer_); | |
| 424 state_lock_.Release(); | |
| 425 return; | |
| 426 } | |
| 427 | |
| 428 extension_id_ = extension_id; | |
| 429 VLOG(1) << "Start"; | |
| 430 | |
| 431 VLOG(1) << "State changed to starting"; | |
| 432 state_ = kStarting; | |
| 433 state_lock_.Release(); | |
| 434 | |
| 435 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
| 436 NewRunnableMethod(this, &ExtensionSpeechInputManager::StartOnIOThread, | |
| 437 profile_->GetRequestContext(), language, grammar, filter_profanities)); | |
| 438 } | |
| 439 | |
| 440 void ExtensionSpeechInputManager::StartOnIOThread( | |
| 441 net::URLRequestContextGetter* context_getter, | |
| 442 const std::string& language, const std::string& grammar, | |
| 443 bool filter_profanities) { | |
| 444 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 445 VLOG(1) << "Requesting start (IO thread)"; | |
| 446 | |
| 447 // Everything put inside the lock to ensure the validity of context_getter, | |
| 448 // guaranteed while not in the shutdown state. Any ongoing or recognition | |
| 449 // request will be requested to be aborted when entering the shutdown state. | |
| 450 state_lock_.Acquire(); | |
| 451 if (state_ == kShutdown) { | |
| 452 state_lock_.Release(); | |
| 453 return; | |
| 454 } | |
| 455 | |
| 456 if (!AudioManager::GetAudioManager()->HasAudioInputDevices()) { | |
| 457 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 458 NewRunnableMethod(this, &ExtensionSpeechInputManager::DispatchError, | |
| 459 std::string(constants::kErrorNoDevicesAvailable))); | |
| 460 state_lock_.Release(); | |
| 461 return; | |
| 462 } | |
| 463 | |
| 464 recognizer_ = new SpeechRecognizer(this, speech_caller_id_, language, grammar, | |
| 465 context_getter, filter_profanities, "", ""); | |
| 466 recognizer_->StartRecording(); | |
| 467 state_lock_.Release(); | |
| 468 } | |
| 469 | |
| 470 void ExtensionSpeechInputManager::Stop(const std::string& extension_id) { | |
| 471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 472 VLOG(1) << "Requesting stop (UI thread)"; | |
| 473 | |
| 474 if (ShuttingDown()) | |
| 475 return; | |
| 476 | |
| 477 if (!extension_id_.empty() && extension_id != extension_id_) { | |
| 478 DispatchError(constants::kErrorRequestDenied); | |
| 479 return; | |
| 480 } | |
| 481 | |
| 482 state_lock_.Acquire(); | |
| 483 if (state_ != kRecording) { | |
|
Satish
2011/10/09 20:01:47
merge this with the first if statement here?
Leandro Graciá Gil
2011/10/10 18:59:38
Done.
| |
| 484 state_lock_.Release(); | |
| 485 return; | |
| 486 } | |
| 487 | |
| 488 DCHECK(recognizer_); | |
| 489 | |
| 490 VLOG(1) << "State changed to stopping"; | |
| 491 state_ = kStopping; | |
| 492 state_lock_.Release(); | |
| 493 | |
| 494 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
| 495 NewRunnableMethod(this, | |
| 496 &ExtensionSpeechInputManager::ForceStopOnIOThread)); | |
| 497 } | |
| 498 | |
| 499 void ExtensionSpeechInputManager::ForceStopOnIOThread() { | |
| 500 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 501 VLOG(1) << "Requesting forced stop (IO thread)"; | |
| 502 | |
| 503 state_lock_.Acquire(); | |
| 504 DCHECK(state_ != kIdle); | |
| 505 | |
| 506 if (recognizer_) { | |
| 507 recognizer_->CancelRecognition(); | |
| 508 recognizer_ = NULL; | |
|
Satish
2011/10/09 20:01:47
recognizer_.release() ?
Leandro Graciá Gil
2011/10/10 18:59:38
Done.
| |
| 509 } | |
| 510 | |
| 511 if (state_ == kShutdown) { | |
| 512 state_lock_.Release(); | |
| 513 return; | |
| 514 } | |
| 515 | |
| 516 state_ = kIdle; | |
| 517 VLOG(1) << "State changed to idle"; | |
| 518 | |
| 519 NotificationService::current()->Notify( | |
| 520 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED, | |
| 521 Source<Profile>(profile_), // Guarded by the state_ == kShutdown check. | |
| 522 Details<std::string>(&extension_id_)); | |
| 523 | |
| 524 extension_id_.clear(); | |
| 525 state_lock_.Release(); | |
| 526 } | |
| 527 | |
| OLD | NEW |