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

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: Rebase before dcommit 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 16 matching lines...) Expand all
187 extension->id()); 185 extension->id());
188 } else { 186 } else {
189 NOTREACHED(); 187 NOTREACHED();
190 } 188 }
191 } 189 }
192 190
193 void SpeechInputExtensionManager::ShutdownOnUIThread() { 191 void SpeechInputExtensionManager::ShutdownOnUIThread() {
194 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
195 VLOG(1) << "Profile shutting down."; 193 VLOG(1) << "Profile shutting down.";
196 194
195 // Note: Unretained(this) is safe, also if we are freed in the meanwhile.
196 // It is used by the SR manager just for comparing the raw pointer and remove
197 // the associated sessions.
198 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
199 base::Bind(&SpeechRecognitionManager::AbortAllSessionsForListener,
200 base::Unretained(SpeechRecognitionManager::GetInstance()),
201 base::Unretained(this)));
202
197 base::AutoLock auto_lock(state_lock_); 203 base::AutoLock auto_lock(state_lock_);
198 DCHECK(state_ != kShutdown); 204 DCHECK(state_ != kShutdown);
199 if (state_ != kIdle) { 205 if (state_ != kIdle) {
200 DCHECK(notification_.get());
201 notification_->Hide();
202 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 206 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
203 base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); 207 base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this));
204 } 208 }
205 state_ = kShutdown; 209 state_ = kShutdown;
206 VLOG(1) << "Entering the shutdown sink state."; 210 VLOG(1) << "Entering the shutdown sink state.";
207 registrar_.reset(); 211 registrar_.reset();
208 profile_ = NULL; 212 profile_ = NULL;
209 } 213 }
210 214
211 void SpeechInputExtensionManager::ExtensionUnloaded( 215 void SpeechInputExtensionManager::ExtensionUnloaded(
(...skipping 26 matching lines...) Expand all
238 void SpeechInputExtensionManager::ResetToIdleState() { 242 void SpeechInputExtensionManager::ResetToIdleState() {
239 VLOG(1) << "State changed to idle. Deassociating any extensions."; 243 VLOG(1) << "State changed to idle. Deassociating any extensions.";
240 state_ = kIdle; 244 state_ = kIdle;
241 extension_id_in_use_.clear(); 245 extension_id_in_use_.clear();
242 } 246 }
243 247
244 void SpeechInputExtensionManager::OnRecognitionResult( 248 void SpeechInputExtensionManager::OnRecognitionResult(
245 int session_id, 249 int session_id,
246 const content::SpeechRecognitionResult& result) { 250 const content::SpeechRecognitionResult& result) {
247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
248 DCHECK_EQ(session_id, kSpeechInputSessionId); 252 DCHECK_EQ(session_id, speech_recognition_session_id_);
249 253
250 // Stopping will start the disassociation with the extension. 254 // Stopping will start the disassociation with the extension.
251 // Make a copy to report the results to the proper one. 255 // Make a copy to report the results to the proper one.
252 std::string extension_id = extension_id_in_use_; 256 std::string extension_id = extension_id_in_use_;
253 ForceStopOnIOThread(); 257 ForceStopOnIOThread();
254 258
255 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 259 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
256 base::Bind(&SpeechInputExtensionManager::SetRecognitionResultOnUIThread, 260 base::Bind(&SpeechInputExtensionManager::SetRecognitionResultOnUIThread,
257 this, result, extension_id)); 261 this, result, extension_id));
258 } 262 }
(...skipping 22 matching lines...) Expand all
281 hypothesis.confidence); 285 hypothesis.confidence);
282 } 286 }
283 287
284 std::string json_args; 288 std::string json_args;
285 base::JSONWriter::Write(&args, &json_args); 289 base::JSONWriter::Write(&args, &json_args);
286 VLOG(1) << "Results: " << json_args; 290 VLOG(1) << "Results: " << json_args;
287 DispatchEventToExtension(extension_id, kOnResultEvent, json_args); 291 DispatchEventToExtension(extension_id, kOnResultEvent, json_args);
288 } 292 }
289 293
290 void SpeechInputExtensionManager::OnRecognitionStart(int session_id) { 294 void SpeechInputExtensionManager::OnRecognitionStart(int session_id) {
291 DCHECK_EQ(session_id, kSpeechInputSessionId); 295 DCHECK_EQ(session_id, speech_recognition_session_id_);
292 } 296 }
293 297
294 void SpeechInputExtensionManager::OnAudioStart(int session_id) { 298 void SpeechInputExtensionManager::OnAudioStart(int session_id) {
295 VLOG(1) << "OnAudioStart"; 299 VLOG(1) << "OnAudioStart";
296 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
297 DCHECK_EQ(session_id, kSpeechInputSessionId); 301 DCHECK_EQ(session_id, speech_recognition_session_id_);
298 302
299 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 303 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
300 base::Bind(&SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread, 304 base::Bind(&SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread,
301 this)); 305 this));
302 } 306 }
303 307
304 void SpeechInputExtensionManager::OnAudioEnd(int session_id) { 308 void SpeechInputExtensionManager::OnAudioEnd(int session_id) {
305 DCHECK_EQ(session_id, kSpeechInputSessionId);
306 } 309 }
307 310
308 void SpeechInputExtensionManager::OnRecognitionEnd(int session_id) { 311 void SpeechInputExtensionManager::OnRecognitionEnd(int session_id) {
309 DCHECK_EQ(session_id, kSpeechInputSessionId); 312 // In the very exceptional case in which we requested a new recognition before
313 // the previous one ended, don't clobber the speech_recognition_session_id_.
314 if (speech_recognition_session_id_ == session_id) {
315 is_recognition_in_progress_ = false;
316 speech_recognition_session_id_ =
317 SpeechRecognitionManager::kSessionIDInvalid;
318 }
310 } 319 }
311 320
312 void SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread() { 321 void SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread() {
313 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
314 323
315 base::AutoLock auto_lock(state_lock_); 324 base::AutoLock auto_lock(state_lock_);
316 if (state_ == kShutdown) 325 if (state_ == kShutdown)
317 return; 326 return;
318 327
319 DCHECK_EQ(state_, kStarting); 328 DCHECK_EQ(state_, kStarting);
320 VLOG(1) << "State changed to recording"; 329 VLOG(1) << "State changed to recording";
321 state_ = kRecording; 330 state_ = kRecording;
322 331
323 const extensions::Extension* extension = profile_->GetExtensionService()-> 332 DCHECK(profile_);
324 GetExtensionById(extension_id_in_use_, true); 333 profile_->GetPrefs()->SetBoolean(
325 DCHECK(extension); 334 prefs::kSpeechInputTrayNotificationShown, true);
326
327 bool show_notification = !profile_->GetPrefs()->GetBoolean(
328 prefs::kSpeechInputTrayNotificationShown);
329
330 if (!notification_.get())
331 notification_ = new SpeechRecognitionTrayIconController();
332 notification_->Show(UTF8ToUTF16(extension->name()), show_notification);
333
334 if (show_notification) {
335 profile_->GetPrefs()->SetBoolean(
336 prefs::kSpeechInputTrayNotificationShown, true);
337 }
338 335
339 VLOG(1) << "Sending start notification"; 336 VLOG(1) << "Sending start notification";
340 content::NotificationService::current()->Notify( 337 content::NotificationService::current()->Notify(
341 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED, 338 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED,
342 content::Source<Profile>(profile_), 339 content::Source<Profile>(profile_),
343 content::Details<std::string>(&extension_id_in_use_)); 340 content::Details<std::string>(&extension_id_in_use_));
344 } 341 }
345 342
346 void SpeechInputExtensionManager::OnRecognitionError( 343 void SpeechInputExtensionManager::OnRecognitionError(
347 int session_id, const content::SpeechRecognitionError& error) { 344 int session_id, const content::SpeechRecognitionError& error) {
348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
349 DCHECK_EQ(session_id, kSpeechInputSessionId); 346 DCHECK_EQ(session_id, speech_recognition_session_id_);
350
351 // Simply return in case of an ERROR_ABORTED, since it is not contemplated
352 // in the speech input extensions architecture.
353 if (error.code == content::SPEECH_RECOGNITION_ERROR_ABORTED)
354 return;
355
356 VLOG(1) << "OnRecognitionError: " << error.code; 347 VLOG(1) << "OnRecognitionError: " << error.code;
357 348
358 base::AutoLock auto_lock(state_lock_); 349 base::AutoLock auto_lock(state_lock_);
359 if (state_ == kShutdown) 350 if (state_ == kShutdown)
360 return; 351 return;
361 352
362 // Release the recognizer object.
363 GetSpeechInputExtensionInterface()->StopRecording(true); 353 GetSpeechInputExtensionInterface()->StopRecording(true);
364 354
365 std::string event_error_code; 355 std::string event_error_code;
366 bool report_to_event = true; 356 bool report_to_event = true;
367 357
368 switch (error.code) { 358 switch (error.code) {
369 case content::SPEECH_RECOGNITION_ERROR_NONE: 359 case content::SPEECH_RECOGNITION_ERROR_NONE:
370 break; 360 break;
371 361
362 case content::SPEECH_RECOGNITION_ERROR_ABORTED:
363 // ERROR_ABORTED is received whenever AbortSession is called on the
364 // manager. However, we want propagate the error only if it is triggered
365 // by an external cause (another recognition started, aborting us), thus
366 // only if it occurs while we are capturing audio.
367 if (state_ == kRecording)
368 event_error_code = kErrorCaptureError;
369 break;
370
372 case content::SPEECH_RECOGNITION_ERROR_AUDIO: 371 case content::SPEECH_RECOGNITION_ERROR_AUDIO:
373 if (state_ == kStarting) { 372 if (state_ == kStarting) {
374 event_error_code = kErrorUnableToStart; 373 event_error_code = kErrorUnableToStart;
375 report_to_event = false; 374 report_to_event = false;
376 } else { 375 } else {
377 event_error_code = kErrorCaptureError; 376 event_error_code = kErrorCaptureError;
378 } 377 }
379 break; 378 break;
380 379
381 case content::SPEECH_RECOGNITION_ERROR_NETWORK: 380 case content::SPEECH_RECOGNITION_ERROR_NETWORK:
(...skipping 22 matching lines...) Expand all
404 403
405 if (!event_error_code.empty()) { 404 if (!event_error_code.empty()) {
406 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 405 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
407 base::Bind(&SpeechInputExtensionManager::DispatchError, 406 base::Bind(&SpeechInputExtensionManager::DispatchError,
408 this, event_error_code, report_to_event)); 407 this, event_error_code, report_to_event));
409 } 408 }
410 } 409 }
411 410
412 void SpeechInputExtensionManager::OnEnvironmentEstimationComplete( 411 void SpeechInputExtensionManager::OnEnvironmentEstimationComplete(
413 int session_id) { 412 int session_id) {
414 DCHECK_EQ(session_id, kSpeechInputSessionId); 413 DCHECK_EQ(session_id, speech_recognition_session_id_);
415 } 414 }
416 415
417 void SpeechInputExtensionManager::OnSoundStart(int session_id) { 416 void SpeechInputExtensionManager::OnSoundStart(int session_id) {
418 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
419 DCHECK_EQ(session_id, kSpeechInputSessionId); 418 DCHECK_EQ(session_id, speech_recognition_session_id_);
420 VLOG(1) << "OnSoundStart"; 419 VLOG(1) << "OnSoundStart";
421 420
422 std::string json_args; 421 std::string json_args;
423 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 422 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
424 base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension, 423 base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension,
425 this, extension_id_in_use_, std::string(kOnSoundStartEvent), 424 this, extension_id_in_use_, std::string(kOnSoundStartEvent),
426 json_args)); 425 json_args));
427 } 426 }
428 427
429 void SpeechInputExtensionManager::OnSoundEnd(int session_id) { 428 void SpeechInputExtensionManager::OnSoundEnd(int session_id) {
430 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
431 DCHECK_EQ(session_id, kSpeechInputSessionId);
432 VLOG(1) << "OnSoundEnd"; 430 VLOG(1) << "OnSoundEnd";
433 431
434 std::string json_args; 432 std::string json_args;
435 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 433 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
436 base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension, 434 base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension,
437 this, extension_id_in_use_, std::string(kOnSoundEndEvent), 435 this, extension_id_in_use_, std::string(kOnSoundEndEvent),
438 json_args)); 436 json_args));
439 } 437 }
440 438
441 void SpeechInputExtensionManager::DispatchEventToExtension( 439 void SpeechInputExtensionManager::DispatchEventToExtension(
(...skipping 22 matching lines...) Expand all
464 void SpeechInputExtensionManager::DispatchError( 462 void SpeechInputExtensionManager::DispatchError(
465 const std::string& error, bool dispatch_event) { 463 const std::string& error, bool dispatch_event) {
466 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 464 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
467 465
468 std::string extension_id; 466 std::string extension_id;
469 { 467 {
470 base::AutoLock auto_lock(state_lock_); 468 base::AutoLock auto_lock(state_lock_);
471 if (state_ == kShutdown) 469 if (state_ == kShutdown)
472 return; 470 return;
473 471
474 if (state_ == kRecording) {
475 DCHECK(notification_.get());
476 notification_->Hide();
477 }
478
479 extension_id = extension_id_in_use_; 472 extension_id = extension_id_in_use_;
480 ResetToIdleState(); 473 ResetToIdleState();
481 474
482 // Will set the error property in the ongoing extension function calls. 475 // Will set the error property in the ongoing extension function calls.
483 ExtensionError details(extension_id, error); 476 ExtensionError details(extension_id, error);
484 content::NotificationService::current()->Notify( 477 content::NotificationService::current()->Notify(
485 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_FAILED, 478 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_FAILED,
486 content::Source<Profile>(profile_), 479 content::Source<Profile>(profile_),
487 content::Details<ExtensionError>(&details)); 480 content::Details<ExtensionError>(&details));
488 } 481 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 517
525 case kRecording: 518 case kRecording:
526 case kStopping: 519 case kStopping:
527 *error = kErrorInvalidOperation; 520 *error = kErrorInvalidOperation;
528 return false; 521 return false;
529 522
530 default: 523 default:
531 NOTREACHED(); 524 NOTREACHED();
532 } 525 }
533 526
527 const extensions::Extension* extension = profile_->GetExtensionService()->
528 GetExtensionById(extension_id, true);
529 DCHECK(extension);
530 const string16& extension_name = UTF8ToUTF16(extension->name());
531
534 extension_id_in_use_ = extension_id; 532 extension_id_in_use_ = extension_id;
535 VLOG(1) << "State changed to starting"; 533 VLOG(1) << "State changed to starting";
536 state_ = kStarting; 534 state_ = kStarting;
537 535
536 // Checks if the security notification balloon has been already shown (only
537 // once for a profile). It is reset on DidStartReceivingAudioOnUIThread.
538 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
539 profile_->GetRequestContext();
540 const bool show_notification = !profile_->GetPrefs()->GetBoolean(
541 prefs::kSpeechInputTrayNotificationShown);
542
538 BrowserThread::PostTask( 543 BrowserThread::PostTask(
539 BrowserThread::IO, FROM_HERE, 544 BrowserThread::IO, FROM_HERE,
540 base::Bind(&SpeechInputExtensionManager::StartOnIOThread, this, 545 base::Bind(&SpeechInputExtensionManager::StartOnIOThread, this,
541 profile_->GetRequestContext(), language, grammar, 546 url_request_context_getter, extension_name, language, grammar,
542 filter_profanities)); 547 filter_profanities, show_notification));
543 return true; 548 return true;
544 } 549 }
545 550
546 void SpeechInputExtensionManager::StartOnIOThread( 551 void SpeechInputExtensionManager::StartOnIOThread(
547 net::URLRequestContextGetter* context_getter, 552 scoped_refptr<net::URLRequestContextGetter> context_getter,
553 const string16& extension_name,
548 const std::string& language, 554 const std::string& language,
549 const std::string& grammar, 555 const std::string& grammar,
550 bool filter_profanities) { 556 bool filter_profanities,
557 bool show_notification) {
551 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 558 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
552 VLOG(1) << "Requesting start (IO thread)"; 559 VLOG(1) << "Requesting start (IO thread)";
553 560
554 // Everything put inside the lock to ensure the validity of context_getter, 561 // Everything put inside the lock to ensure the validity of context_getter,
555 // guaranteed while not in the shutdown state. Any ongoing or recognition 562 // guaranteed while not in the shutdown state. Any ongoing or recognition
556 // request will be requested to be aborted when entering the shutdown state. 563 // request will be requested to be aborted when entering the shutdown state.
557 base::AutoLock auto_lock(state_lock_); 564 base::AutoLock auto_lock(state_lock_);
558 if (state_ == kShutdown) 565 if (state_ == kShutdown)
559 return; 566 return;
560 567
568 // TODO(primiano) These two checks below could be avoided, since they are
569 // already handled in the speech recognition classes. However, since the
570 // speech input extensions tests are bypassing the manager, we need them to
571 // pass the tests. A complete unit test which puts all the pieces together,
572 // mocking just the endpoints (the audio input controller and the URL fetcher)
573 // should be written.
561 if (!GetSpeechInputExtensionInterface()->HasAudioInputDevices()) { 574 if (!GetSpeechInputExtensionInterface()->HasAudioInputDevices()) {
562 BrowserThread::PostTask( 575 BrowserThread::PostTask(
563 BrowserThread::UI, FROM_HERE, 576 BrowserThread::UI, FROM_HERE,
564 base::Bind(&SpeechInputExtensionManager::DispatchError, this, 577 base::Bind(&SpeechInputExtensionManager::DispatchError, this,
565 std::string(kErrorNoRecordingDeviceFound), false)); 578 std::string(kErrorNoRecordingDeviceFound), false));
566 return; 579 return;
567 } 580 }
568 581
569 if (GetSpeechInputExtensionInterface()->IsCapturingAudio()) { 582 if (GetSpeechInputExtensionInterface()->IsCapturingAudio()) {
570 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 583 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
571 base::Bind(&SpeechInputExtensionManager::DispatchError, this, 584 base::Bind(&SpeechInputExtensionManager::DispatchError, this,
572 std::string(kErrorRecordingDeviceInUse), false)); 585 std::string(kErrorRecordingDeviceInUse), false));
573 return; 586 return;
574 } 587 }
575 588
576 GetSpeechInputExtensionInterface()->StartRecording( 589 GetSpeechInputExtensionInterface()->StartRecording(this,
577 this, context_getter, kSpeechInputSessionId, language, grammar, 590 context_getter,
578 filter_profanities); 591 extension_name,
592 language,
593 grammar,
594 filter_profanities,
595 show_notification);
579 } 596 }
580 597
581 bool SpeechInputExtensionManager::HasAudioInputDevices() { 598 bool SpeechInputExtensionManager::HasAudioInputDevices() {
582 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 599 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
583 return SpeechRecognitionManager::GetInstance()->HasAudioInputDevices(); 600 return SpeechRecognitionManager::GetInstance()->HasAudioInputDevices();
584 } 601 }
585 602
586 bool SpeechInputExtensionManager::IsCapturingAudio() { 603 bool SpeechInputExtensionManager::IsCapturingAudio() {
587 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 604 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
588 return SpeechRecognitionManager::GetInstance()->IsCapturingAudio(); 605 return SpeechRecognitionManager::GetInstance()->IsCapturingAudio();
589 } 606 }
590 607
591 void SpeechInputExtensionManager::IsRecording( 608 void SpeechInputExtensionManager::IsRecording(
592 const IsRecordingCallback& callback) { 609 const IsRecordingCallback& callback) {
593 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 610 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
594 BrowserThread::PostTask( 611 BrowserThread::PostTask(
595 BrowserThread::IO, FROM_HERE, 612 BrowserThread::IO, FROM_HERE,
596 base::Bind(&SpeechInputExtensionManager::IsRecordingOnIOThread, 613 base::Bind(&SpeechInputExtensionManager::IsRecordingOnIOThread,
597 this, callback)); 614 this, callback));
598 } 615 }
599 616
600 void SpeechInputExtensionManager::IsRecordingOnIOThread( 617 void SpeechInputExtensionManager::IsRecordingOnIOThread(
601 const IsRecordingCallback& callback) { 618 const IsRecordingCallback& callback) {
602 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 619 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
603 620
604 bool result = GetSpeechInputExtensionInterface()->IsCapturingAudio(); 621 bool result = GetSpeechInputExtensionInterface()->IsCapturingAudio();
622
605 BrowserThread::PostTask( 623 BrowserThread::PostTask(
606 BrowserThread::UI, FROM_HERE, 624 BrowserThread::UI, FROM_HERE,
607 base::Bind(&SpeechInputExtensionManager::IsRecordingOnUIThread, 625 base::Bind(&SpeechInputExtensionManager::IsRecordingOnUIThread,
608 this, callback, result)); 626 this, callback, result));
609 } 627 }
610 628
611 void SpeechInputExtensionManager::IsRecordingOnUIThread( 629 void SpeechInputExtensionManager::IsRecordingOnUIThread(
612 const IsRecordingCallback& callback, 630 const IsRecordingCallback& callback,
613 bool result) { 631 bool result) {
614 BrowserThread::CurrentlyOn(BrowserThread::UI); 632 BrowserThread::CurrentlyOn(BrowserThread::UI);
615 callback.Run(result); 633 callback.Run(result);
616 } 634 }
617 635
618 void SpeechInputExtensionManager::StartRecording( 636 void SpeechInputExtensionManager::StartRecording(
619 content::SpeechRecognitionEventListener* listener, 637 content::SpeechRecognitionEventListener* listener,
620 net::URLRequestContextGetter* context_getter, 638 net::URLRequestContextGetter* context_getter,
621 int session_id, 639 const string16& extension_name,
622 const std::string& language, 640 const std::string& language,
623 const std::string& grammar, 641 const std::string& grammar,
624 bool filter_profanities) { 642 bool filter_profanities,
643 bool show_notification) {
625 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 644 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
626 DCHECK(!recognizer_); 645
627 recognizer_ = content::SpeechRecognizer::Create( 646 content::SpeechRecognitionSessionContext context;
628 listener, session_id, language, grammar, context_getter, 647 context.requested_by_page_element = false;
629 filter_profanities, "", ""); 648 context.is_first_request_for_context = show_notification;
630 recognizer_->StartRecognition(); 649 context.context_name = extension_name;
650
651 content::SpeechRecognitionSessionConfig config;
652 // config.is_one_shot = true; // TODO(primiano) Uncomment when CL2.0 lands.
653 config.language = language;
654 config.grammars.push_back(content::SpeechRecognitionGrammar(grammar));
655 config.initial_context = context;
656 config.url_request_context_getter = context_getter;
657 config.filter_profanities = filter_profanities;
658 config.event_listener = listener;
659
660 DCHECK(!is_recognition_in_progress_);
661 SpeechRecognitionManager& manager = *SpeechRecognitionManager::GetInstance();
662 speech_recognition_session_id_ =
663 manager.CreateSession(config);
664 DCHECK_NE(speech_recognition_session_id_,
665 SpeechRecognitionManager::kSessionIDInvalid);
666 is_recognition_in_progress_ = true;
667 manager.StartSession(speech_recognition_session_id_);
631 } 668 }
632 669
633 bool SpeechInputExtensionManager::HasValidRecognizer() { 670 bool SpeechInputExtensionManager::HasValidRecognizer() {
634 return !!recognizer_; 671 if (!is_recognition_in_progress_)
672 return false;
673 return SpeechRecognitionManager::GetInstance()->IsCapturingAudio();
635 } 674 }
636 675
637 bool SpeechInputExtensionManager::Stop(const std::string& extension_id, 676 bool SpeechInputExtensionManager::Stop(const std::string& extension_id,
638 std::string* error) { 677 std::string* error) {
639 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 678 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
640 DCHECK(error); 679 DCHECK(error);
641 VLOG(1) << "Requesting stop (UI thread)"; 680 VLOG(1) << "Requesting stop (UI thread)";
642 681
643 base::AutoLock auto_lock(state_lock_); 682 base::AutoLock auto_lock(state_lock_);
644 if (state_ == kShutdown || 683 if (state_ == kShutdown ||
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 GetSpeechInputExtensionInterface()->StopRecording(false); 724 GetSpeechInputExtensionInterface()->StopRecording(false);
686 725
687 if (state_ == kShutdown) 726 if (state_ == kShutdown)
688 return; 727 return;
689 728
690 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 729 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
691 base::Bind(&SpeechInputExtensionManager::StopSucceededOnUIThread, this)); 730 base::Bind(&SpeechInputExtensionManager::StopSucceededOnUIThread, this));
692 } 731 }
693 732
694 void SpeechInputExtensionManager::StopRecording(bool recognition_failed) { 733 void SpeechInputExtensionManager::StopRecording(bool recognition_failed) {
695 if (recognizer_) { 734 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
696 // Recognition is already cancelled in case of failure. 735 if (!is_recognition_in_progress_)
697 // Double-cancelling leads to assertion failures. 736 return;
698 if (!recognition_failed) 737 DCHECK_NE(speech_recognition_session_id_,
699 recognizer_->AbortRecognition(); 738 SpeechRecognitionManager::kSessionIDInvalid);
700 recognizer_.release(); 739 SpeechRecognitionManager::GetInstance()->AbortSession(
701 } 740 speech_recognition_session_id_);
702 } 741 }
703 742
704 void SpeechInputExtensionManager::StopSucceededOnUIThread() { 743 void SpeechInputExtensionManager::StopSucceededOnUIThread() {
705 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 744 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
706 VLOG(1) << "Stop succeeded (UI thread)"; 745 VLOG(1) << "Stop succeeded (UI thread)";
707 746
708 base::AutoLock auto_lock(state_lock_); 747 base::AutoLock auto_lock(state_lock_);
709 if (state_ == kShutdown) 748 if (state_ == kShutdown)
710 return; 749 return;
711 750
712 std::string extension_id = extension_id_in_use_; 751 std::string extension_id = extension_id_in_use_;
713 ResetToIdleState(); 752 ResetToIdleState();
714 753
715 DCHECK(notification_.get());
716 notification_->Hide();
717
718 content::NotificationService::current()->Notify( 754 content::NotificationService::current()->Notify(
719 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED, 755 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED,
720 // Guarded by the state_ == kShutdown check. 756 // Guarded by the state_ == kShutdown check.
721 content::Source<Profile>(profile_), 757 content::Source<Profile>(profile_),
722 content::Details<std::string>(&extension_id)); 758 content::Details<std::string>(&extension_id));
723 } 759 }
724 760
725 void SpeechInputExtensionManager::OnAudioLevelsChange(int session_id, 761 void SpeechInputExtensionManager::OnAudioLevelsChange(int session_id,
726 float volume, 762 float volume,
727 float noise_volume) { 763 float noise_volume) {}
728 DCHECK_EQ(session_id, kSpeechInputSessionId);
729 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
730 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
731 base::Bind(&SpeechInputExtensionManager::SetInputVolumeOnUIThread,
732 this, volume));
733 }
734
735 void SpeechInputExtensionManager::SetInputVolumeOnUIThread(
736 float volume) {
737 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
738 DCHECK(notification_.get());
739 notification_->SetVUMeterVolume(volume);
740 }
OLDNEW
« no previous file with comments | « chrome/browser/speech/speech_input_extension_manager.h ('k') | content/browser/speech/speech_recognition_manager_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698