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

Side by Side Diff: chrome/browser/extensions/extension_speech_input_manager.cc

Issue 8201030: Introducing the basic functionality to the speech input experimental API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: removing call error codes from the json file and doc (no longer reported by onError). Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/extensions/extension_speech_input_manager.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/bind.h"
8 #include "base/json/json_writer.h"
9 #include "base/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "chrome/browser/extensions/extension_event_router.h"
12 #include "chrome/browser/extensions/extension_speech_input_api_constants.h"
13 #include "chrome/browser/profiles/profile.h"
7 #include "chrome/browser/profiles/profile_dependency_manager.h" 14 #include "chrome/browser/profiles/profile_dependency_manager.h"
8 #include "chrome/browser/profiles/profile_keyed_service.h" 15 #include "chrome/browser/profiles/profile_keyed_service.h"
9 #include "chrome/browser/profiles/profile_keyed_service_factory.h" 16 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
10 #include "chrome/common/chrome_notification_types.h" 17 #include "chrome/common/chrome_notification_types.h"
11 #include "chrome/common/extensions/extension.h" 18 #include "chrome/common/extensions/extension.h"
19 #include "content/browser/browser_thread.h"
12 #include "content/common/notification_service.h" 20 #include "content/common/notification_service.h"
13 21
22 using namespace speech_input;
23
24 namespace constants = extension_speech_input_api_constants;
25
14 namespace { 26 namespace {
15 27
28 // Caller id provided to the speech recognizer. Since only one extension can
29 // be recording on the same time a constant value is enough as id.
30 static const int kSpeechCallerId = 1;
31
16 // Wrap an ExtensionSpeechInputManager using scoped_refptr to avoid 32 // Wrap an ExtensionSpeechInputManager using scoped_refptr to avoid
17 // assertion failures on destruction because of not using release(). 33 // assertion failures on destruction because of not using release().
18 class ExtensionSpeechInputManagerWrapper : public ProfileKeyedService { 34 class ExtensionSpeechInputManagerWrapper : public ProfileKeyedService {
19 public: 35 public:
20 explicit ExtensionSpeechInputManagerWrapper( 36 explicit ExtensionSpeechInputManagerWrapper(
21 ExtensionSpeechInputManager* manager) 37 ExtensionSpeechInputManager* manager)
22 : manager_(manager) {} 38 : manager_(manager) {}
23 39
24 virtual ~ExtensionSpeechInputManagerWrapper() {} 40 virtual ~ExtensionSpeechInputManagerWrapper() {}
25 41
(...skipping 19 matching lines...) Expand all
45 ExtensionSpeechInputManagerWrapper* GetForProfile(Profile* profile); 61 ExtensionSpeechInputManagerWrapper* GetForProfile(Profile* profile);
46 62
47 private: 63 private:
48 friend struct DefaultSingletonTraits<Factory>; 64 friend struct DefaultSingletonTraits<Factory>;
49 65
50 Factory(); 66 Factory();
51 virtual ~Factory(); 67 virtual ~Factory();
52 68
53 // ProfileKeyedServiceFactory methods: 69 // ProfileKeyedServiceFactory methods:
54 virtual ProfileKeyedService* BuildServiceInstanceFor( 70 virtual ProfileKeyedService* BuildServiceInstanceFor(
55 Profile* profile) const; 71 Profile* profile) const OVERRIDE;
56 virtual bool ServiceRedirectedInIncognito() { return false; } 72 virtual bool ServiceRedirectedInIncognito() { return false; }
Leandro GraciĆ” Gil 2011/10/11 18:10:51 Adding OVERRIDE to these.
57 virtual bool ServiceIsNULLWhileTesting() { return true; } 73 virtual bool ServiceIsNULLWhileTesting() { return true; }
58 virtual bool ServiceIsCreatedWithProfile() { return true; } 74 virtual bool ServiceIsCreatedWithProfile() { return true; }
59 75
60 DISALLOW_COPY_AND_ASSIGN(Factory); 76 DISALLOW_COPY_AND_ASSIGN(Factory);
61 }; 77 };
62 78
63 void ExtensionSpeechInputManager::Factory::Initialize() { 79 void ExtensionSpeechInputManager::Factory::Initialize() {
64 GetInstance(); 80 GetInstance();
65 } 81 }
66 82
(...skipping 19 matching lines...) Expand all
86 ProfileKeyedService* 102 ProfileKeyedService*
87 ExtensionSpeechInputManager::Factory::BuildServiceInstanceFor( 103 ExtensionSpeechInputManager::Factory::BuildServiceInstanceFor(
88 Profile* profile) const { 104 Profile* profile) const {
89 scoped_refptr<ExtensionSpeechInputManager> manager( 105 scoped_refptr<ExtensionSpeechInputManager> manager(
90 new ExtensionSpeechInputManager(profile)); 106 new ExtensionSpeechInputManager(profile));
91 return new ExtensionSpeechInputManagerWrapper(manager); 107 return new ExtensionSpeechInputManagerWrapper(manager);
92 } 108 }
93 109
94 ExtensionSpeechInputManager::ExtensionSpeechInputManager(Profile* profile) 110 ExtensionSpeechInputManager::ExtensionSpeechInputManager(Profile* profile)
95 : profile_(profile), 111 : profile_(profile),
96 extension_(NULL) { 112 state_(kIdle),
113 speech_interface_(NULL) {
97 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 114 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
98 Source<Profile>(profile_)); 115 Source<Profile>(profile_));
99 } 116 }
100 117
101 ExtensionSpeechInputManager::~ExtensionSpeechInputManager() { 118 ExtensionSpeechInputManager::~ExtensionSpeechInputManager() {
102 } 119 }
103 120
104 ExtensionSpeechInputManager* ExtensionSpeechInputManager::GetForProfile( 121 ExtensionSpeechInputManager* ExtensionSpeechInputManager::GetForProfile(
105 Profile* profile) { 122 Profile* profile) {
106 ExtensionSpeechInputManagerWrapper *wrapper = 123 ExtensionSpeechInputManagerWrapper *wrapper =
(...skipping 10 matching lines...) Expand all
117 void ExtensionSpeechInputManager::Observe(int type, 134 void ExtensionSpeechInputManager::Observe(int type,
118 const NotificationSource& source, 135 const NotificationSource& source,
119 const NotificationDetails& details) { 136 const NotificationDetails& details) {
120 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) 137 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED)
121 ExtensionUnloaded(Details<UnloadedExtensionInfo>(details)->extension->id()); 138 ExtensionUnloaded(Details<UnloadedExtensionInfo>(details)->extension->id());
122 else 139 else
123 NOTREACHED(); 140 NOTREACHED();
124 } 141 }
125 142
126 void ExtensionSpeechInputManager::ShutdownOnUIThread() { 143 void ExtensionSpeechInputManager::ShutdownOnUIThread() {
127 // TODO(leandrogracia): Force stop to speech recognition if active. 144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
145 VLOG(1) << "Profile shutting down.";
146
147 base::AutoLock auto_lock(state_lock_);
148 DCHECK(state_ != kShutdown);
149 if (state_ != kIdle) {
150 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
151 base::Bind(&ExtensionSpeechInputManager::ForceStopOnIOThread, this));
152 }
153 state_ = kShutdown;
154 VLOG(1) << "Entering the shutdown sink state.";
128 registrar_.RemoveAll(); 155 registrar_.RemoveAll();
129 profile_ = NULL; 156 profile_ = NULL;
130 } 157 }
131 158
132 void ExtensionSpeechInputManager::ExtensionUnloaded(const std::string& id) { 159 void ExtensionSpeechInputManager::ExtensionUnloaded(
133 // TODO(leandrogracia): Force stop to speech recognition if the extension 160 const std::string& extension_id) {
134 // is currently using the API. 161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
135 } 162
136 163 base::AutoLock auto_lock(state_lock_);
137 void ExtensionSpeechInputManager::Start(const Extension *extension) { 164 if (state_ == kShutdown)
138 // TODO(leandrogracia): Start speech recognition. 165 return;
139 } 166
140 167 VLOG(1) << "Extension unloaded. Requesting to enforce stop...";
141 void ExtensionSpeechInputManager::Stop(const Extension *extension) { 168 if (extension_id_in_use_ == extension_id) {
142 // TODO(leandrogracia): Stop speech recognition. 169 if (state_ != kIdle) {
143 } 170 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
144 171 base::Bind(&ExtensionSpeechInputManager::ForceStopOnIOThread, this));
172 }
173 }
174 }
175
176 void ExtensionSpeechInputManager::SetExtensionSpeechInterface(
177 ExtensionSpeechInterface* interface) {
178 speech_interface_ = interface;
179 }
180
181 ExtensionSpeechInterface*
182 ExtensionSpeechInputManager::GetExtensionSpeechInterface() {
183 return speech_interface_ ? speech_interface_ : this;
184 }
185
186 void ExtensionSpeechInputManager::SetRecognitionResult(
187 int caller_id,
188 const SpeechInputResult& result) {
189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
190 DCHECK_EQ(caller_id, kSpeechCallerId);
191
192 // Stopping will start the disassociation with the extension.
193 // Make a copy to report the results to the proper one.
194 std::string extension_id = extension_id_in_use_;
195 ForceStopOnIOThread();
196
197 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
198 base::Bind(&ExtensionSpeechInputManager::SetRecognitionResultOnUIThread,
199 this, result, extension_id));
200 }
201
202 void ExtensionSpeechInputManager::SetRecognitionResultOnUIThread(
203 const SpeechInputResult& result, const std::string& extension_id) {
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
205
206 {
207 base::AutoLock auto_lock(state_lock_);
208 if (state_ == kShutdown)
209 return;
210 state_ = kIdle;
211 }
212
213 ListValue args;
214 DictionaryValue* js_event = new DictionaryValue();
215 args.Append(js_event);
216
217 ListValue* js_hypothesis_array = new ListValue();
218 js_event->Set(constants::kHypothesesKey, js_hypothesis_array);
219
220 for (size_t i = 0; i < result.hypotheses.size(); ++i) {
221 const SpeechInputHypothesis& hypothesis = result.hypotheses[i];
222
223 DictionaryValue* js_hypothesis_object = new DictionaryValue();
224 js_hypothesis_array->Append(js_hypothesis_object);
225
226 js_hypothesis_object->SetString(constants::kUtteranceKey,
227 UTF16ToUTF8(hypothesis.utterance));
228 js_hypothesis_object->SetDouble(constants::kConfidenceKey,
229 hypothesis.confidence);
230 }
231
232 std::string json_args;
233 base::JSONWriter::Write(&args, false, &json_args);
234 VLOG(1) << "Results: " << json_args;
235 DispatchEventToExtension(extension_id, constants::kOnResultEvent, json_args);
236 }
237
238 void ExtensionSpeechInputManager::DidStartReceivingAudio(int caller_id) {
239 VLOG(1) << "DidStartReceivingAudio";
240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
241 DCHECK_EQ(caller_id, kSpeechCallerId);
242
243 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
244 base::Bind(&ExtensionSpeechInputManager::DidStartReceivingAudioOnUIThread,
245 this));
246 }
247
248 void ExtensionSpeechInputManager::DidCompleteRecording(int caller_id) {
249 DCHECK_EQ(caller_id, kSpeechCallerId);
250 }
251
252 void ExtensionSpeechInputManager::DidCompleteRecognition(int caller_id) {
253 DCHECK_EQ(caller_id, kSpeechCallerId);
254 }
255
256 void ExtensionSpeechInputManager::DidStartReceivingAudioOnUIThread() {
257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
258
259 base::AutoLock auto_lock(state_lock_);
260 if (state_ == kShutdown)
261 return;
262
263 DCHECK_EQ(state_, kStarting);
264 VLOG(1) << "State changed to recording";
265 state_ = kRecording;
266
267 VLOG(1) << "Sending start notification";
268 NotificationService::current()->Notify(
269 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED,
270 Source<Profile>(profile_),
271 Details<std::string>(&extension_id_in_use_));
272 }
273
274 void ExtensionSpeechInputManager::OnRecognizerError(
275 int caller_id, SpeechInputError error) {
276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
277 DCHECK_EQ(caller_id, kSpeechCallerId);
278 VLOG(1) << "OnRecognizerError: " << error;
279
280 base::AutoLock auto_lock(state_lock_);
281 if (state_ == kShutdown)
282 return;
283
284 // Release the recognizer object.
285 GetExtensionSpeechInterface()->StopRecording(true);
286
287 std::string event_error_code;
288 bool report_to_event = true;
289
290 switch (error) {
291 case kErrorNone:
292 break;
293
294 case kErrorAudio:
295 if (state_ == kStarting) {
296 event_error_code = constants::kErrorUnableToStart;
297 report_to_event = false;
298 } else {
299 event_error_code = constants::kErrorCaptureError;
300 }
301 break;
302
303 case kErrorNetwork:
304 event_error_code = constants::kErrorNetworkError;
305 break;
306
307 case kErrorBadGrammar:
308 // No error is returned on invalid language, for example.
309 // To avoid confusion about when this is would be fired, the invalid
310 // params error is not being exposed to the onError event.
311 event_error_code = constants::kErrorUnableToStart;
312 break;
313
314 case kErrorNoSpeech:
315 event_error_code = constants::kErrorNoSpeechHeard;
316 break;
317
318 case kErrorNoMatch:
319 event_error_code = constants::kErrorNoResults;
320 break;
321
322 // The remaining kErrorAborted case should never be returned by the server.
323 default:
324 NOTREACHED();
325 }
326
327 VLOG(1) << "State changed to idle";
328 state_ = kIdle;
329
330 if (!event_error_code.empty()) {
331 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
332 base::Bind(&ExtensionSpeechInputManager::DispatchError,
333 this, event_error_code, report_to_event));
334 }
335 }
336
337 void ExtensionSpeechInputManager::DidCompleteEnvironmentEstimation(
338 int caller_id) {
339 DCHECK_EQ(caller_id, kSpeechCallerId);
340 }
341
342 void ExtensionSpeechInputManager::DidStartReceivingSpeech(int caller_id) {
343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
344 DCHECK_EQ(caller_id, kSpeechCallerId);
345 VLOG(1) << "DidStartReceivingSpeech";
346
347 std::string json_args;
348 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
349 base::Bind(&ExtensionSpeechInputManager::DispatchEventToExtension,
350 this, extension_id_in_use_, std::string(constants::kOnSoundStartEvent),
351 json_args));
352 }
353
354 void ExtensionSpeechInputManager::DidStopReceivingSpeech(int caller_id) {
355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
356 DCHECK_EQ(caller_id, kSpeechCallerId);
357 VLOG(1) << "DidStopReceivingSpeech";
358
359 std::string json_args;
360 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
361 base::Bind(&ExtensionSpeechInputManager::DispatchEventToExtension,
362 this, extension_id_in_use_, std::string(constants::kOnSoundEndEvent),
363 json_args));
364 }
365
366 void ExtensionSpeechInputManager::DispatchEventToExtension(
367 const std::string& extension_id, const std::string& event,
368 const std::string& json_args) {
369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
370
371 base::AutoLock auto_lock(state_lock_);
372 if (state_ == kShutdown)
373 return;
374
375 if (profile_ && profile_->GetExtensionEventRouter()) {
376 std::string final_args;
377 if (json_args.empty()) {
378 ListValue args;
379 base::JSONWriter::Write(&args, false, &final_args);
380 } else {
381 final_args = json_args;
382 }
383
384 profile_->GetExtensionEventRouter()->DispatchEventToExtension(
385 extension_id, event, final_args, profile_, GURL());
386 }
387 }
388
389 void ExtensionSpeechInputManager::DispatchError(
390 const std::string& error, bool dispatch_event) {
391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
392
393 {
394 base::AutoLock auto_lock(state_lock_);
395 if (state_ == kShutdown)
396 return;
397
398 // Will set the error property in the ongoing extension function calls.
399 ExtensionError details(extension_id_in_use_, error);
400 NotificationService::current()->Notify(
401 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_FAILED,
402 Source<Profile>(profile_),
403 Details<ExtensionError>(&details));
404 }
405
406 // Used for errors that are also reported via the onError event.
407 if (dispatch_event) {
408 ListValue args;
409 DictionaryValue *js_error = new DictionaryValue();
410 args.Append(js_error);
411 js_error->SetString(constants::kErrorCodeKey, error);
412 std::string json_args;
413 base::JSONWriter::Write(&args, false, &json_args);
414 DispatchEventToExtension(extension_id_in_use_,
415 constants::kOnErrorEvent, json_args);
416 }
417 }
418
419 bool ExtensionSpeechInputManager::Start(const std::string& extension_id,
420 const std::string& language, const std::string& grammar,
421 bool filter_profanities, std::string* error) {
422 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
423 DCHECK(error);
424 VLOG(1) << "Requesting start (UI thread)";
425
426 base::AutoLock auto_lock(state_lock_);
427 if (state_ == kShutdown ||
428 (!extension_id_in_use_.empty() && extension_id_in_use_ != extension_id)) {
429 *error = constants::kErrorRequestDenied;
430 return false;
431 }
432
433 switch (state_) {
434 case kIdle:
435 break;
436
437 case kStarting:
438 *error = constants::kErrorRequestInProgress;
439 return false;
440
441 case kRecording:
442 case kStopping:
443 *error = constants::kErrorInvalidOperation;
444 return false;
445
446 default:
447 NOTREACHED();
448 }
449
450 extension_id_in_use_ = extension_id;
451 VLOG(1) << "State changed to starting";
452 state_ = kStarting;
453
454 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
455 base::Bind(&ExtensionSpeechInputManager::StartOnIOThread, this,
456 profile_->GetRequestContext(), language, grammar, filter_profanities));
457 return true;
458 }
459
460 void ExtensionSpeechInputManager::StartOnIOThread(
461 net::URLRequestContextGetter* context_getter,
462 const std::string& language, const std::string& grammar,
463 bool filter_profanities) {
464 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
465 VLOG(1) << "Requesting start (IO thread)";
466
467 // Everything put inside the lock to ensure the validity of context_getter,
468 // guaranteed while not in the shutdown state. Any ongoing or recognition
469 // request will be requested to be aborted when entering the shutdown state.
470 base::AutoLock auto_lock(state_lock_);
471 if (state_ == kShutdown)
472 return;
473
474 if (!GetExtensionSpeechInterface()->CheckForAvailableDevices()) {
475 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
476 base::Bind(&ExtensionSpeechInputManager::DispatchError, this,
477 std::string(constants::kErrorNoDevicesAvailable), false));
478 return;
479 }
480
481 GetExtensionSpeechInterface()->StartRecording(this, context_getter,
482 kSpeechCallerId, language, grammar, filter_profanities);
483 }
484
485 bool ExtensionSpeechInputManager::CheckForAvailableDevices() {
486 return AudioManager::GetAudioManager()->HasAudioInputDevices();
487 }
488
489 void ExtensionSpeechInputManager::StartRecording(
490 speech_input::SpeechRecognizerDelegate* delegate,
491 net::URLRequestContextGetter* context_getter, int caller_id,
492 const std::string& language, const std::string& grammar,
493 bool filter_profanities) {
494 DCHECK(!recognizer_);
495 recognizer_ = new SpeechRecognizer(delegate, caller_id, language, grammar,
496 context_getter, filter_profanities, "", "");
497 recognizer_->StartRecording();
498 }
499
500 bool ExtensionSpeechInputManager::HasValidRecognizer() const {
501 return recognizer_;
502 }
503
504 bool ExtensionSpeechInputManager::Stop(const std::string& extension_id,
505 std::string* error) {
506 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
507 DCHECK(error);
508 VLOG(1) << "Requesting stop (UI thread)";
509
510 base::AutoLock auto_lock(state_lock_);
511 if (state_ == kShutdown ||
512 (!extension_id_in_use_.empty() && extension_id_in_use_ != extension_id)) {
513 *error = constants::kErrorRequestDenied;
514 return false;
515 }
516
517 switch (state_) {
518 case kRecording:
519 break;
520
521 case kStopping:
522 *error = constants::kErrorRequestInProgress;
523 return false;
524
525 case kIdle:
526 case kStarting:
527 *error = constants::kErrorInvalidOperation;
528 return false;
529
530 default:
531 NOTREACHED();
532 }
533
534 // Guarded by the state lock.
535 DCHECK(GetExtensionSpeechInterface()->HasValidRecognizer());
536
537 VLOG(1) << "State changed to stopping";
538 state_ = kStopping;
539
540 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
541 base::Bind(&ExtensionSpeechInputManager::ForceStopOnIOThread, this));
542 return true;
543 }
544
545 void ExtensionSpeechInputManager::ForceStopOnIOThread() {
546 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
547 VLOG(1) << "Requesting forced stop (IO thread)";
548
549 base::AutoLock auto_lock(state_lock_);
550 DCHECK(state_ != kIdle);
551
552 GetExtensionSpeechInterface()->StopRecording(false);
553
554 if (state_ == kShutdown)
555 return;
556
557 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
558 base::Bind(&ExtensionSpeechInputManager::StopSucceededOnUIThread, this));
559 }
560
561 void ExtensionSpeechInputManager::StopRecording(bool recognition_failed) {
562 if (recognizer_) {
563 // Recognition is already cancelled in case of failure.
564 // Double-cancelling leads to assertion failures.
565 if (!recognition_failed)
566 recognizer_->CancelRecognition();
567 recognizer_.release();
568 }
569 }
570
571 void ExtensionSpeechInputManager::StopSucceededOnUIThread() {
572 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
573 VLOG(1) << "Stop succeeded (UI thread)";
574
575 base::AutoLock auto_lock(state_lock_);
576 if (state_ == kShutdown)
577 return;
578
579 state_ = kIdle;
580 VLOG(1) << "State changed to idle";
581
582 NotificationService::current()->Notify(
583 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED,
584 Source<Profile>(profile_), // Guarded by the state_ == kShutdown check.
585 Details<std::string>(&extension_id_in_use_));
586
587 extension_id_in_use_.clear();
588 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_speech_input_manager.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698