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

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: review fixes. 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
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/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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698