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

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

Issue 7729001: Get rid of link dependency from content to chrome. Make it get the SpeechInputManager through the... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/speech/speech_input_manager.h" 5 #include "chrome/browser/speech/chrome_speech_input_manager.h"
6 6
7 #include <map>
8 #include <string> 7 #include <string>
9 8
10 #include "base/lazy_instance.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/synchronization/lock.h" 9 #include "base/synchronization/lock.h"
13 #include "base/threading/thread_restrictions.h" 10 #include "base/threading/thread_restrictions.h"
14 #include "base/utf_string_conversions.h" 11 #include "base/utf_string_conversions.h"
15 #include "chrome/browser/browser_process.h" 12 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/prefs/pref_service.h" 13 #include "chrome/browser/prefs/pref_service.h"
17 #include "chrome/browser/speech/speech_input_bubble_controller.h"
18 #include "chrome/browser/tab_contents/tab_util.h" 14 #include "chrome/browser/tab_contents/tab_util.h"
19 #include "chrome/common/chrome_switches.h" 15 #include "chrome/common/chrome_switches.h"
20 #include "chrome/common/pref_names.h" 16 #include "chrome/common/pref_names.h"
21 #include "content/browser/browser_thread.h" 17 #include "content/browser/browser_thread.h"
22 #include "content/browser/speech/speech_recognizer.h"
23 #include "grit/generated_resources.h" 18 #include "grit/generated_resources.h"
24 #include "media/audio/audio_manager.h" 19 #include "media/audio/audio_manager.h"
25 #include "ui/base/l10n/l10n_util.h" 20 #include "ui/base/l10n/l10n_util.h"
26 21
27 #if defined(OS_WIN) 22 #if defined(OS_WIN)
28 #include "chrome/installer/util/wmi.h" 23 #include "chrome/installer/util/wmi.h"
29 #endif 24 #endif
30 25
31 namespace speech_input { 26 namespace speech_input {
32 27
33 namespace {
34
35 // Asynchronously fetches the PC and audio hardware/driver info if 28 // Asynchronously fetches the PC and audio hardware/driver info if
36 // the user has opted into UMA. This information is sent with speech input 29 // the user has opted into UMA. This information is sent with speech input
37 // requests to the server for identifying and improving quality issues with 30 // requests to the server for identifying and improving quality issues with
38 // specific device configurations. 31 // specific device configurations.
39 class OptionalRequestInfo 32 class ChromeSpeechInputManager::OptionalRequestInfo
40 : public base::RefCountedThreadSafe<OptionalRequestInfo> { 33 : public base::RefCountedThreadSafe<OptionalRequestInfo> {
41 public: 34 public:
42 OptionalRequestInfo() : can_report_metrics_(false) {} 35 OptionalRequestInfo() : can_report_metrics_(false) {}
43 36
44 void Refresh() { 37 void Refresh() {
45 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 38 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
46 // UMA opt-in can be checked only from the UI thread, so switch to that. 39 // UMA opt-in can be checked only from the UI thread, so switch to that.
47 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 40 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
48 NewRunnableMethod(this, 41 NewRunnableMethod(this,
49 &OptionalRequestInfo::CheckUMAAndGetHardwareInfo)); 42 &OptionalRequestInfo::CheckUMAAndGetHardwareInfo));
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 } 77 }
85 78
86 private: 79 private:
87 base::Lock lock_; 80 base::Lock lock_;
88 std::string value_; 81 std::string value_;
89 bool can_report_metrics_; 82 bool can_report_metrics_;
90 83
91 DISALLOW_COPY_AND_ASSIGN(OptionalRequestInfo); 84 DISALLOW_COPY_AND_ASSIGN(OptionalRequestInfo);
92 }; 85 };
93 86
94 class SpeechInputManagerImpl : public SpeechInputManager, 87 ChromeSpeechInputManager* ChromeSpeechInputManager::GetInstance() {
95 public SpeechInputBubbleControllerDelegate, 88 return Singleton<ChromeSpeechInputManager>::get();
96 public SpeechRecognizerDelegate {
97 public:
98 // SpeechInputManager methods.
99 virtual void StartRecognition(SpeechInputManagerDelegate* delegate,
100 int caller_id,
101 int render_process_id,
102 int render_view_id,
103 const gfx::Rect& element_rect,
104 const std::string& language,
105 const std::string& grammar,
106 const std::string& origin_url);
107 virtual void CancelRecognition(int caller_id);
108 virtual void StopRecording(int caller_id);
109 virtual void CancelAllRequestsWithDelegate(
110 SpeechInputManagerDelegate* delegate);
111
112 // SpeechRecognizer::Delegate methods.
113 virtual void DidStartReceivingAudio(int caller_id);
114 virtual void SetRecognitionResult(int caller_id,
115 bool error,
116 const SpeechInputResultArray& result);
117 virtual void DidCompleteRecording(int caller_id);
118 virtual void DidCompleteRecognition(int caller_id);
119 virtual void OnRecognizerError(int caller_id,
120 SpeechRecognizer::ErrorCode error);
121 virtual void DidCompleteEnvironmentEstimation(int caller_id);
122 virtual void SetInputVolume(int caller_id, float volume, float noise_volume);
123
124 // SpeechInputBubbleController::Delegate methods.
125 virtual void InfoBubbleButtonClicked(int caller_id,
126 SpeechInputBubble::Button button);
127 virtual void InfoBubbleFocusChanged(int caller_id);
128
129 private:
130 struct SpeechInputRequest {
131 SpeechInputManagerDelegate* delegate;
132 scoped_refptr<SpeechRecognizer> recognizer;
133 bool is_active; // Set to true when recording or recognition is going on.
134 };
135
136 // Private constructor to enforce singleton.
137 friend struct base::DefaultLazyInstanceTraits<SpeechInputManagerImpl>;
138 SpeechInputManagerImpl();
139 virtual ~SpeechInputManagerImpl();
140
141 bool HasPendingRequest(int caller_id) const;
142 SpeechInputManagerDelegate* GetDelegate(int caller_id) const;
143
144 void CancelRecognitionAndInformDelegate(int caller_id);
145
146 // Starts/restarts recognition for an existing request.
147 void StartRecognitionForRequest(int caller_id);
148
149 typedef std::map<int, SpeechInputRequest> SpeechRecognizerMap;
150 SpeechRecognizerMap requests_;
151 int recording_caller_id_;
152 scoped_refptr<SpeechInputBubbleController> bubble_controller_;
153 scoped_refptr<OptionalRequestInfo> optional_request_info_;
154 };
155
156 base::LazyInstance<SpeechInputManagerImpl> g_speech_input_manager_impl(
157 base::LINKER_INITIALIZED);
158
159 } // namespace
160
161 SpeechInputManager* SpeechInputManager::Get() {
162 return g_speech_input_manager_impl.Pointer();
163 } 89 }
164 90
165 void SpeechInputManager::ShowAudioInputSettings() { 91 ChromeSpeechInputManager::ChromeSpeechInputManager()
166 // Since AudioManager::ShowAudioInputSettings can potentially launch external
167 // processes, do that in the FILE thread to not block the calling threads.
168 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
169 BrowserThread::PostTask(
170 BrowserThread::FILE, FROM_HERE,
171 NewRunnableFunction(&SpeechInputManager::ShowAudioInputSettings));
172 return;
173 }
174
175 DCHECK(AudioManager::GetAudioManager()->CanShowAudioInputSettings());
176 if (AudioManager::GetAudioManager()->CanShowAudioInputSettings())
177 AudioManager::GetAudioManager()->ShowAudioInputSettings();
178 }
179
180 SpeechInputManagerImpl::SpeechInputManagerImpl()
181 : recording_caller_id_(0), 92 : recording_caller_id_(0),
182 bubble_controller_(new SpeechInputBubbleController( 93 bubble_controller_(new SpeechInputBubbleController(
183 ALLOW_THIS_IN_INITIALIZER_LIST(this))) { 94 ALLOW_THIS_IN_INITIALIZER_LIST(this))) {
184 } 95 }
185 96
186 SpeechInputManagerImpl::~SpeechInputManagerImpl() { 97 ChromeSpeechInputManager::~ChromeSpeechInputManager() {
187 while (requests_.begin() != requests_.end()) 98 while (requests_.begin() != requests_.end())
188 CancelRecognition(requests_.begin()->first); 99 CancelRecognition(requests_.begin()->first);
189 } 100 }
190 101
191 bool SpeechInputManagerImpl::HasPendingRequest(int caller_id) const { 102 bool ChromeSpeechInputManager::HasPendingRequest(int caller_id) const {
192 return requests_.find(caller_id) != requests_.end(); 103 return requests_.find(caller_id) != requests_.end();
193 } 104 }
194 105
195 SpeechInputManagerDelegate* SpeechInputManagerImpl::GetDelegate( 106 SpeechInputManagerDelegate* ChromeSpeechInputManager::GetDelegate(
196 int caller_id) const { 107 int caller_id) const {
197 return requests_.find(caller_id)->second.delegate; 108 return requests_.find(caller_id)->second.delegate;
198 } 109 }
199 110
200 void SpeechInputManagerImpl::StartRecognition( 111 void ChromeSpeechInputManager::StartRecognition(
201 SpeechInputManagerDelegate* delegate, 112 SpeechInputManagerDelegate* delegate,
202 int caller_id, 113 int caller_id,
203 int render_process_id, 114 int render_process_id,
204 int render_view_id, 115 int render_view_id,
205 const gfx::Rect& element_rect, 116 const gfx::Rect& element_rect,
206 const std::string& language, 117 const std::string& language,
207 const std::string& grammar, 118 const std::string& grammar,
208 const std::string& origin_url) { 119 const std::string& origin_url) {
209 DCHECK(!HasPendingRequest(caller_id)); 120 DCHECK(!HasPendingRequest(caller_id));
210 121
(...skipping 16 matching lines...) Expand all
227 request->delegate = delegate; 138 request->delegate = delegate;
228 request->recognizer = new SpeechRecognizer( 139 request->recognizer = new SpeechRecognizer(
229 this, caller_id, language, grammar, censor_results(), 140 this, caller_id, language, grammar, censor_results(),
230 optional_request_info_->value(), 141 optional_request_info_->value(),
231 optional_request_info_->can_report_metrics() ? origin_url : ""); 142 optional_request_info_->can_report_metrics() ? origin_url : "");
232 request->is_active = false; 143 request->is_active = false;
233 144
234 StartRecognitionForRequest(caller_id); 145 StartRecognitionForRequest(caller_id);
235 } 146 }
236 147
237 void SpeechInputManagerImpl::StartRecognitionForRequest(int caller_id) { 148 void ChromeSpeechInputManager::StartRecognitionForRequest(int caller_id) {
238 DCHECK(HasPendingRequest(caller_id)); 149 DCHECK(HasPendingRequest(caller_id));
239 150
240 // If we are currently recording audio for another caller, abort that cleanly. 151 // If we are currently recording audio for another caller, abort that cleanly.
241 if (recording_caller_id_) 152 if (recording_caller_id_)
242 CancelRecognitionAndInformDelegate(recording_caller_id_); 153 CancelRecognitionAndInformDelegate(recording_caller_id_);
243 154
244 if (!AudioManager::GetAudioManager()->HasAudioInputDevices()) { 155 if (!AudioManager::GetAudioManager()->HasAudioInputDevices()) {
245 bubble_controller_->SetBubbleMessage( 156 bubble_controller_->SetBubbleMessage(
246 caller_id, l10n_util::GetStringUTF16(IDS_SPEECH_INPUT_NO_MIC)); 157 caller_id, l10n_util::GetStringUTF16(IDS_SPEECH_INPUT_NO_MIC));
247 } else { 158 } else {
248 recording_caller_id_ = caller_id; 159 recording_caller_id_ = caller_id;
249 requests_[caller_id].is_active = true; 160 requests_[caller_id].is_active = true;
250 requests_[caller_id].recognizer->StartRecording(); 161 requests_[caller_id].recognizer->StartRecording();
251 bubble_controller_->SetBubbleWarmUpMode(caller_id); 162 bubble_controller_->SetBubbleWarmUpMode(caller_id);
252 } 163 }
253 } 164 }
254 165
255 void SpeechInputManagerImpl::CancelRecognition(int caller_id) { 166 void ChromeSpeechInputManager::CancelRecognition(int caller_id) {
256 DCHECK(HasPendingRequest(caller_id)); 167 DCHECK(HasPendingRequest(caller_id));
257 if (requests_[caller_id].is_active) 168 if (requests_[caller_id].is_active)
258 requests_[caller_id].recognizer->CancelRecognition(); 169 requests_[caller_id].recognizer->CancelRecognition();
259 requests_.erase(caller_id); 170 requests_.erase(caller_id);
260 if (recording_caller_id_ == caller_id) 171 if (recording_caller_id_ == caller_id)
261 recording_caller_id_ = 0; 172 recording_caller_id_ = 0;
262 bubble_controller_->CloseBubble(caller_id); 173 bubble_controller_->CloseBubble(caller_id);
263 } 174 }
264 175
265 void SpeechInputManagerImpl::CancelAllRequestsWithDelegate( 176 void ChromeSpeechInputManager::CancelAllRequestsWithDelegate(
266 SpeechInputManagerDelegate* delegate) { 177 SpeechInputManagerDelegate* delegate) {
267 SpeechRecognizerMap::iterator it = requests_.begin(); 178 SpeechRecognizerMap::iterator it = requests_.begin();
268 while (it != requests_.end()) { 179 while (it != requests_.end()) {
269 if (it->second.delegate == delegate) { 180 if (it->second.delegate == delegate) {
270 CancelRecognition(it->first); 181 CancelRecognition(it->first);
271 // This map will have very few elements so it is simpler to restart. 182 // This map will have very few elements so it is simpler to restart.
272 it = requests_.begin(); 183 it = requests_.begin();
273 } else { 184 } else {
274 ++it; 185 ++it;
275 } 186 }
276 } 187 }
277 } 188 }
278 189
279 void SpeechInputManagerImpl::StopRecording(int caller_id) { 190 void ChromeSpeechInputManager::StopRecording(int caller_id) {
280 DCHECK(HasPendingRequest(caller_id)); 191 DCHECK(HasPendingRequest(caller_id));
281 requests_[caller_id].recognizer->StopRecording(); 192 requests_[caller_id].recognizer->StopRecording();
282 } 193 }
283 194
284 void SpeechInputManagerImpl::SetRecognitionResult( 195 void ChromeSpeechInputManager::SetRecognitionResult(
285 int caller_id, bool error, const SpeechInputResultArray& result) { 196 int caller_id, bool error, const SpeechInputResultArray& result) {
286 DCHECK(HasPendingRequest(caller_id)); 197 DCHECK(HasPendingRequest(caller_id));
287 GetDelegate(caller_id)->SetRecognitionResult(caller_id, result); 198 GetDelegate(caller_id)->SetRecognitionResult(caller_id, result);
288 } 199 }
289 200
290 void SpeechInputManagerImpl::DidCompleteRecording(int caller_id) { 201 void ChromeSpeechInputManager::DidCompleteRecording(int caller_id) {
291 DCHECK(recording_caller_id_ == caller_id); 202 DCHECK(recording_caller_id_ == caller_id);
292 DCHECK(HasPendingRequest(caller_id)); 203 DCHECK(HasPendingRequest(caller_id));
293 recording_caller_id_ = 0; 204 recording_caller_id_ = 0;
294 GetDelegate(caller_id)->DidCompleteRecording(caller_id); 205 GetDelegate(caller_id)->DidCompleteRecording(caller_id);
295 bubble_controller_->SetBubbleRecognizingMode(caller_id); 206 bubble_controller_->SetBubbleRecognizingMode(caller_id);
296 } 207 }
297 208
298 void SpeechInputManagerImpl::DidCompleteRecognition(int caller_id) { 209 void ChromeSpeechInputManager::DidCompleteRecognition(int caller_id) {
299 GetDelegate(caller_id)->DidCompleteRecognition(caller_id); 210 GetDelegate(caller_id)->DidCompleteRecognition(caller_id);
300 requests_.erase(caller_id); 211 requests_.erase(caller_id);
301 bubble_controller_->CloseBubble(caller_id); 212 bubble_controller_->CloseBubble(caller_id);
302 } 213 }
303 214
304 void SpeechInputManagerImpl::OnRecognizerError( 215 void ChromeSpeechInputManager::OnRecognizerError(
305 int caller_id, SpeechRecognizer::ErrorCode error) { 216 int caller_id, SpeechRecognizer::ErrorCode error) {
306 if (caller_id == recording_caller_id_) 217 if (caller_id == recording_caller_id_)
307 recording_caller_id_ = 0; 218 recording_caller_id_ = 0;
308 219
309 requests_[caller_id].is_active = false; 220 requests_[caller_id].is_active = false;
310 221
311 struct ErrorMessageMapEntry { 222 struct ErrorMessageMapEntry {
312 SpeechRecognizer::ErrorCode error; 223 SpeechRecognizer::ErrorCode error;
313 int message_id; 224 int message_id;
314 }; 225 };
(...skipping 13 matching lines...) Expand all
328 bubble_controller_->SetBubbleMessage( 239 bubble_controller_->SetBubbleMessage(
329 caller_id, 240 caller_id,
330 l10n_util::GetStringUTF16(error_message_map[i].message_id)); 241 l10n_util::GetStringUTF16(error_message_map[i].message_id));
331 return; 242 return;
332 } 243 }
333 } 244 }
334 245
335 NOTREACHED() << "unknown error " << error; 246 NOTREACHED() << "unknown error " << error;
336 } 247 }
337 248
338 void SpeechInputManagerImpl::DidStartReceivingAudio(int caller_id) { 249 void ChromeSpeechInputManager::DidStartReceivingAudio(int caller_id) {
339 DCHECK(HasPendingRequest(caller_id)); 250 DCHECK(HasPendingRequest(caller_id));
340 DCHECK(recording_caller_id_ == caller_id); 251 DCHECK(recording_caller_id_ == caller_id);
341 bubble_controller_->SetBubbleRecordingMode(caller_id); 252 bubble_controller_->SetBubbleRecordingMode(caller_id);
342 } 253 }
343 254
344 void SpeechInputManagerImpl::DidCompleteEnvironmentEstimation(int caller_id) { 255 void ChromeSpeechInputManager::DidCompleteEnvironmentEstimation(int caller_id) {
345 DCHECK(HasPendingRequest(caller_id)); 256 DCHECK(HasPendingRequest(caller_id));
346 DCHECK(recording_caller_id_ == caller_id); 257 DCHECK(recording_caller_id_ == caller_id);
347 } 258 }
348 259
349 void SpeechInputManagerImpl::SetInputVolume(int caller_id, float volume, 260 void ChromeSpeechInputManager::SetInputVolume(int caller_id, float volume,
350 float noise_volume) { 261 float noise_volume) {
351 DCHECK(HasPendingRequest(caller_id)); 262 DCHECK(HasPendingRequest(caller_id));
352 DCHECK_EQ(recording_caller_id_, caller_id); 263 DCHECK_EQ(recording_caller_id_, caller_id);
353 264
354 bubble_controller_->SetBubbleInputVolume(caller_id, volume, noise_volume); 265 bubble_controller_->SetBubbleInputVolume(caller_id, volume, noise_volume);
355 } 266 }
356 267
357 void SpeechInputManagerImpl::CancelRecognitionAndInformDelegate(int caller_id) { 268 void ChromeSpeechInputManager::CancelRecognitionAndInformDelegate(
269 int caller_id) {
358 SpeechInputManagerDelegate* cur_delegate = GetDelegate(caller_id); 270 SpeechInputManagerDelegate* cur_delegate = GetDelegate(caller_id);
359 CancelRecognition(caller_id); 271 CancelRecognition(caller_id);
360 cur_delegate->DidCompleteRecording(caller_id); 272 cur_delegate->DidCompleteRecording(caller_id);
361 cur_delegate->DidCompleteRecognition(caller_id); 273 cur_delegate->DidCompleteRecognition(caller_id);
362 } 274 }
363 275
364 void SpeechInputManagerImpl::InfoBubbleButtonClicked( 276 void ChromeSpeechInputManager::InfoBubbleButtonClicked(
365 int caller_id, SpeechInputBubble::Button button) { 277 int caller_id, SpeechInputBubble::Button button) {
366 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
367 // Ignore if the caller id was not in our active recognizers list because the 279 // Ignore if the caller id was not in our active recognizers list because the
368 // user might have clicked more than once, or recognition could have been 280 // user might have clicked more than once, or recognition could have been
369 // cancelled due to other reasons before the user click was processed. 281 // cancelled due to other reasons before the user click was processed.
370 if (!HasPendingRequest(caller_id)) 282 if (!HasPendingRequest(caller_id))
371 return; 283 return;
372 284
373 if (button == SpeechInputBubble::BUTTON_CANCEL) { 285 if (button == SpeechInputBubble::BUTTON_CANCEL) {
374 CancelRecognitionAndInformDelegate(caller_id); 286 CancelRecognitionAndInformDelegate(caller_id);
375 } else if (button == SpeechInputBubble::BUTTON_TRY_AGAIN) { 287 } else if (button == SpeechInputBubble::BUTTON_TRY_AGAIN) {
376 StartRecognitionForRequest(caller_id); 288 StartRecognitionForRequest(caller_id);
377 } 289 }
378 } 290 }
379 291
380 void SpeechInputManagerImpl::InfoBubbleFocusChanged(int caller_id) { 292 void ChromeSpeechInputManager::InfoBubbleFocusChanged(int caller_id) {
381 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
382 // Ignore if the caller id was not in our active recognizers list because the 294 // Ignore if the caller id was not in our active recognizers list because the
383 // user might have clicked more than once, or recognition could have been 295 // user might have clicked more than once, or recognition could have been
384 // ended due to other reasons before the user click was processed. 296 // ended due to other reasons before the user click was processed.
385 if (HasPendingRequest(caller_id)) { 297 if (HasPendingRequest(caller_id)) {
386 // If this is an ongoing recording or if we were displaying an error message 298 // If this is an ongoing recording or if we were displaying an error message
387 // to the user, abort it since user has switched focus. Otherwise 299 // to the user, abort it since user has switched focus. Otherwise
388 // recognition has started and keep that going so user can start speaking to 300 // recognition has started and keep that going so user can start speaking to
389 // another element while this gets the results in parallel. 301 // another element while this gets the results in parallel.
390 if (recording_caller_id_ == caller_id || !requests_[caller_id].is_active) { 302 if (recording_caller_id_ == caller_id || !requests_[caller_id].is_active) {
391 CancelRecognitionAndInformDelegate(caller_id); 303 CancelRecognitionAndInformDelegate(caller_id);
392 } 304 }
393 } 305 }
394 } 306 }
395 307
396 } // namespace speech_input 308 } // namespace speech_input
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698