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

Side by Side Diff: chrome/browser/speech/speech_input_extension_manager.cc

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

Powered by Google App Engine
This is Rietveld 408576698