speech_input_manager.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
3bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// found in the LICENSE file.
4bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
5bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/speech/speech_input_manager.h"
6bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
7bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "app/l10n_util.h"
8bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "base/ref_counted.h"
9bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "base/singleton.h"
10731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/browser_thread.h"
11bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/speech/speech_input_bubble_controller.h"
12bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/speech/speech_recognizer.h"
13bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/tab_contents/infobar_delegate.h"
14bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/tab_contents/tab_contents.h"
15bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/tab_contents/tab_util.h"
16bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "grit/generated_resources.h"
17bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "media/audio/audio_manager.h"
18bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include <map>
19bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
20bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsennamespace speech_input {
21bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
22bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenclass SpeechInputManagerImpl : public SpeechInputManager,
23bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                               public SpeechInputBubbleControllerDelegate,
24bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                               public SpeechRecognizerDelegate {
25bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen public:
26bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // SpeechInputManager methods.
27bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual void StartRecognition(SpeechInputManagerDelegate* delegate,
28bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                int caller_id,
29bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                int render_process_id,
30bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                int render_view_id,
31bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                const gfx::Rect& element_rect);
32bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual void CancelRecognition(int caller_id);
33bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual void StopRecording(int caller_id);
34bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
35bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // SpeechRecognizer::Delegate methods.
36bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual void SetRecognitionResult(int caller_id, bool error,
37bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                    const string16& value);
38bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual void DidCompleteRecording(int caller_id);
39bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual void DidCompleteRecognition(int caller_id);
40bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual void OnRecognizerError(int caller_id,
41bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                 SpeechRecognizer::ErrorCode error);
42bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual void DidCompleteEnvironmentEstimation(int caller_id);
43bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual void SetInputVolume(int caller_id, float volume);
44bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
45bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // SpeechInputBubbleController::Delegate methods.
46bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual void InfoBubbleButtonClicked(int caller_id,
47bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                       SpeechInputBubble::Button button);
48bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual void InfoBubbleFocusChanged(int caller_id);
49bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
50bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen private:
51bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  struct SpeechInputRequest {
52bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    SpeechInputManagerDelegate* delegate;
53bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    scoped_refptr<SpeechRecognizer> recognizer;
54bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    bool is_active;  // Set to true when recording or recognition is going on.
55bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  };
56bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
57bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // Private constructor to enforce singleton.
58bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  friend struct DefaultSingletonTraits<SpeechInputManagerImpl>;
59bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  SpeechInputManagerImpl();
60bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  virtual ~SpeechInputManagerImpl();
61bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
62bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bool HasPendingRequest(int caller_id) const;
63bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  SpeechInputManagerDelegate* GetDelegate(int caller_id) const;
64bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
65bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  void CancelRecognitionAndInformDelegate(int caller_id);
66bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
67bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // Starts/restarts recognition for an existing request.
68bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  void StartRecognitionForRequest(int caller_id);
69bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
70bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  SpeechInputManagerDelegate* delegate_;
71bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  typedef std::map<int, SpeechInputRequest> SpeechRecognizerMap;
72bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  SpeechRecognizerMap requests_;
73bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  int recording_caller_id_;
74bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  scoped_refptr<SpeechInputBubbleController> bubble_controller_;
75bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen};
76bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
77bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian MonsenSpeechInputManager* SpeechInputManager::Get() {
78bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  return Singleton<SpeechInputManagerImpl>::get();
79bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
80bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
81bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian MonsenSpeechInputManagerImpl::SpeechInputManagerImpl()
82bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    : recording_caller_id_(0),
83bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      bubble_controller_(new SpeechInputBubbleController(
84bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen          ALLOW_THIS_IN_INITIALIZER_LIST(this))) {
85bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
86bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
87bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian MonsenSpeechInputManagerImpl::~SpeechInputManagerImpl() {
88bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  while (requests_.begin() != requests_.end())
89bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    CancelRecognition(requests_.begin()->first);
90bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
91bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
92bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenbool SpeechInputManagerImpl::HasPendingRequest(int caller_id) const {
93bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  return requests_.find(caller_id) != requests_.end();
94bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
95bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
96bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian MonsenSpeechInputManagerDelegate* SpeechInputManagerImpl::GetDelegate(
97bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    int caller_id) const {
98bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  return requests_.find(caller_id)->second.delegate;
99bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
100bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
101bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SpeechInputManagerImpl::StartRecognition(
102bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    SpeechInputManagerDelegate* delegate,
103bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    int caller_id,
104bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    int render_process_id,
105bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    int render_view_id,
106bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    const gfx::Rect& element_rect) {
107bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(!HasPendingRequest(caller_id));
108bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
109bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_controller_->CreateBubble(caller_id, render_process_id, render_view_id,
110bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                   element_rect);
111bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
112bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  SpeechInputRequest* request = &requests_[caller_id];
113bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  request->delegate = delegate;
114bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  request->recognizer = new SpeechRecognizer(this, caller_id);
115bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  request->is_active = false;
116bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
117bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  StartRecognitionForRequest(caller_id);
118bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
119bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
120bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SpeechInputManagerImpl::StartRecognitionForRequest(int caller_id) {
121bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(HasPendingRequest(caller_id));
122bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
123bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // If we are currently recording audio for another caller, abort that cleanly.
124bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  if (recording_caller_id_)
125bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    CancelRecognitionAndInformDelegate(recording_caller_id_);
126bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
127bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  if (!AudioManager::GetAudioManager()->HasAudioInputDevices()) {
128bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    bubble_controller_->SetBubbleMessage(
129bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen        caller_id, l10n_util::GetStringUTF16(IDS_SPEECH_INPUT_NO_MIC));
130bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  } else {
131bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    recording_caller_id_ = caller_id;
132bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    requests_[caller_id].is_active = true;
133bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    requests_[caller_id].recognizer->StartRecording();
134bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  }
135bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
136bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
137bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SpeechInputManagerImpl::CancelRecognition(int caller_id) {
138bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(HasPendingRequest(caller_id));
139bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  if (requests_[caller_id].is_active)
140bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    requests_[caller_id].recognizer->CancelRecognition();
141bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  requests_.erase(caller_id);
142bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  if (recording_caller_id_ == caller_id)
143bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    recording_caller_id_ = 0;
144bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_controller_->CloseBubble(caller_id);
145bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
146bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
147bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SpeechInputManagerImpl::StopRecording(int caller_id) {
148bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(HasPendingRequest(caller_id));
149bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  requests_[caller_id].recognizer->StopRecording();
150bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
151bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
152bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SpeechInputManagerImpl::SetRecognitionResult(int caller_id,
153bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                                  bool error,
154bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                                  const string16& value) {
155bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(HasPendingRequest(caller_id));
156bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  GetDelegate(caller_id)->SetRecognitionResult(caller_id,
157bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                               (error ? string16() : value));
158bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
159bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
160bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SpeechInputManagerImpl::DidCompleteRecording(int caller_id) {
161bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(recording_caller_id_ == caller_id);
162bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(HasPendingRequest(caller_id));
163bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  recording_caller_id_ = 0;
164bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  GetDelegate(caller_id)->DidCompleteRecording(caller_id);
165bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_controller_->SetBubbleRecognizingMode(caller_id);
166bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
167bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
168bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SpeechInputManagerImpl::DidCompleteRecognition(int caller_id) {
169bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  GetDelegate(caller_id)->DidCompleteRecognition(caller_id);
170bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  requests_.erase(caller_id);
171bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_controller_->CloseBubble(caller_id);
172bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
173bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
174bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SpeechInputManagerImpl::OnRecognizerError(
175bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    int caller_id, SpeechRecognizer::ErrorCode error) {
176bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  if (caller_id == recording_caller_id_)
177bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    recording_caller_id_ = 0;
178bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
179bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  requests_[caller_id].is_active = false;
180bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
181bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  int message_id;
182bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  switch (error) {
183bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    case SpeechRecognizer::RECOGNIZER_ERROR_CAPTURE:
184bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      message_id = IDS_SPEECH_INPUT_ERROR;
185bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      break;
186bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    case SpeechRecognizer::RECOGNIZER_ERROR_NO_SPEECH:
187bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      message_id = IDS_SPEECH_INPUT_NO_SPEECH;
188bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      break;
189bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    case SpeechRecognizer::RECOGNIZER_ERROR_NO_RESULTS:
190bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      message_id = IDS_SPEECH_INPUT_NO_RESULTS;
191bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      break;
192bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    default:
193bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      NOTREACHED() << "unknown error " << error;
194bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      return;
195bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  }
196bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_controller_->SetBubbleMessage(caller_id,
197bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                       l10n_util::GetStringUTF16(message_id));
198bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
199bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
200bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SpeechInputManagerImpl::DidCompleteEnvironmentEstimation(int caller_id) {
201bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(HasPendingRequest(caller_id));
202bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(recording_caller_id_ == caller_id);
203bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
204bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // Speech recognizer has gathered enough background audio so we can ask the
205bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // user to start speaking.
206bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_controller_->SetBubbleRecordingMode(caller_id);
207bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
208bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
209bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SpeechInputManagerImpl::SetInputVolume(int caller_id, float volume) {
210bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(HasPendingRequest(caller_id));
211bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK_EQ(recording_caller_id_, caller_id);
212bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
213bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  bubble_controller_->SetBubbleInputVolume(caller_id, volume);
214bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
215bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
216bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SpeechInputManagerImpl::CancelRecognitionAndInformDelegate(int caller_id) {
217bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  SpeechInputManagerDelegate* cur_delegate = GetDelegate(caller_id);
218bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  CancelRecognition(caller_id);
219bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  cur_delegate->DidCompleteRecording(caller_id);
220bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  cur_delegate->DidCompleteRecognition(caller_id);
221bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
222bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
223bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SpeechInputManagerImpl::InfoBubbleButtonClicked(
224bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    int caller_id, SpeechInputBubble::Button button) {
225731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
226bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // Ignore if the caller id was not in our active recognizers list because the
227bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // user might have clicked more than once, or recognition could have been
228bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // cancelled due to other reasons before the user click was processed.
229bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  if (!HasPendingRequest(caller_id))
230bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    return;
231bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
232bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  if (button == SpeechInputBubble::BUTTON_CANCEL) {
233bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    CancelRecognitionAndInformDelegate(caller_id);
234bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  } else if (button == SpeechInputBubble::BUTTON_TRY_AGAIN) {
235bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    StartRecognitionForRequest(caller_id);
236bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  }
237bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
238bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
239bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SpeechInputManagerImpl::InfoBubbleFocusChanged(int caller_id) {
240731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
241bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // Ignore if the caller id was not in our active recognizers list because the
242bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // user might have clicked more than once, or recognition could have been
243bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // ended due to other reasons before the user click was processed.
244bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  if (HasPendingRequest(caller_id)) {
245bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    // If this is an ongoing recording or if we were displaying an error message
246bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    // to the user, abort it since user has switched focus. Otherwise
247bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    // recognition has started and keep that going so user can start speaking to
248bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    // another element while this gets the results in parallel.
249bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    if (recording_caller_id_ == caller_id || !requests_[caller_id].is_active) {
250bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      CancelRecognitionAndInformDelegate(caller_id);
251bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    }
252bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  }
253bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
254bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
255bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}  // namespace speech_input
256