OLD | NEW |
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 "content/browser/speech/speech_input_manager.h" |
6 | 6 |
7 #include "content/browser/browser_thread.h" | 7 #include "content/browser/browser_thread.h" |
8 #include "media/audio/audio_manager.h" | 8 #include "media/audio/audio_manager.h" |
9 | 9 |
10 namespace speech_input { | 10 namespace speech_input { |
11 | 11 |
12 SpeechInputManager::SpeechInputManager() : censor_results_(true) { | 12 SpeechInputManager::SpeechInputManager() |
| 13 : can_report_metrics_(false), |
| 14 censor_results_(true), |
| 15 recording_caller_id_(0) { |
13 } | 16 } |
14 | 17 |
15 SpeechInputManager::~SpeechInputManager() { | 18 SpeechInputManager::~SpeechInputManager() { |
| 19 while (requests_.begin() != requests_.end()) |
| 20 CancelRecognition(requests_.begin()->first); |
| 21 } |
| 22 |
| 23 bool SpeechInputManager::HasPendingRequest(int caller_id) const { |
| 24 return requests_.find(caller_id) != requests_.end(); |
| 25 } |
| 26 |
| 27 SpeechInputManagerDelegate* SpeechInputManager::GetDelegate( |
| 28 int caller_id) const { |
| 29 return requests_.find(caller_id)->second.delegate; |
16 } | 30 } |
17 | 31 |
18 void SpeechInputManager::ShowAudioInputSettings() { | 32 void SpeechInputManager::ShowAudioInputSettings() { |
19 // Since AudioManager::ShowAudioInputSettings can potentially launch external | 33 // Since AudioManager::ShowAudioInputSettings can potentially launch external |
20 // processes, do that in the FILE thread to not block the calling threads. | 34 // processes, do that in the FILE thread to not block the calling threads. |
21 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { | 35 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { |
22 BrowserThread::PostTask( | 36 BrowserThread::PostTask( |
23 BrowserThread::FILE, FROM_HERE, | 37 BrowserThread::FILE, FROM_HERE, |
24 NewRunnableFunction(&SpeechInputManager::ShowAudioInputSettings)); | 38 NewRunnableFunction(&SpeechInputManager::ShowAudioInputSettings)); |
25 return; | 39 return; |
26 } | 40 } |
27 | 41 |
28 DCHECK(AudioManager::GetAudioManager()->CanShowAudioInputSettings()); | 42 DCHECK(AudioManager::GetAudioManager()->CanShowAudioInputSettings()); |
29 if (AudioManager::GetAudioManager()->CanShowAudioInputSettings()) | 43 if (AudioManager::GetAudioManager()->CanShowAudioInputSettings()) |
30 AudioManager::GetAudioManager()->ShowAudioInputSettings(); | 44 AudioManager::GetAudioManager()->ShowAudioInputSettings(); |
31 } | 45 } |
32 | 46 |
| 47 void SpeechInputManager::StartRecognition( |
| 48 SpeechInputManagerDelegate* delegate, |
| 49 int caller_id, |
| 50 int render_process_id, |
| 51 int render_view_id, |
| 52 const gfx::Rect& element_rect, |
| 53 const std::string& language, |
| 54 const std::string& grammar, |
| 55 const std::string& origin_url) { |
| 56 DCHECK(!HasPendingRequest(caller_id)); |
| 57 |
| 58 ShowRecognitionRequested( |
| 59 caller_id, render_process_id, render_view_id, element_rect); |
| 60 GetRequestInfo(&can_report_metrics_, &request_info_); |
| 61 |
| 62 SpeechInputRequest* request = &requests_[caller_id]; |
| 63 request->delegate = delegate; |
| 64 request->recognizer = new SpeechRecognizer( |
| 65 this, caller_id, language, grammar, censor_results(), |
| 66 request_info_, can_report_metrics_ ? origin_url : ""); |
| 67 request->is_active = false; |
| 68 |
| 69 StartRecognitionForRequest(caller_id); |
| 70 } |
| 71 |
| 72 void SpeechInputManager::StartRecognitionForRequest(int caller_id) { |
| 73 DCHECK(HasPendingRequest(caller_id)); |
| 74 |
| 75 // If we are currently recording audio for another caller, abort that cleanly. |
| 76 if (recording_caller_id_) |
| 77 CancelRecognitionAndInformDelegate(recording_caller_id_); |
| 78 |
| 79 if (!AudioManager::GetAudioManager()->HasAudioInputDevices()) { |
| 80 ShowNoMicError(caller_id); |
| 81 } else { |
| 82 recording_caller_id_ = caller_id; |
| 83 requests_[caller_id].is_active = true; |
| 84 requests_[caller_id].recognizer->StartRecording(); |
| 85 ShowWarmUp(caller_id); |
| 86 } |
| 87 } |
| 88 |
| 89 void SpeechInputManager::CancelRecognition(int caller_id) { |
| 90 DCHECK(HasPendingRequest(caller_id)); |
| 91 if (requests_[caller_id].is_active) |
| 92 requests_[caller_id].recognizer->CancelRecognition(); |
| 93 requests_.erase(caller_id); |
| 94 if (recording_caller_id_ == caller_id) |
| 95 recording_caller_id_ = 0; |
| 96 DoClose(caller_id); |
| 97 } |
| 98 |
| 99 void SpeechInputManager::CancelAllRequestsWithDelegate( |
| 100 SpeechInputManagerDelegate* delegate) { |
| 101 SpeechRecognizerMap::iterator it = requests_.begin(); |
| 102 while (it != requests_.end()) { |
| 103 if (it->second.delegate == delegate) { |
| 104 CancelRecognition(it->first); |
| 105 // This map will have very few elements so it is simpler to restart. |
| 106 it = requests_.begin(); |
| 107 } else { |
| 108 ++it; |
| 109 } |
| 110 } |
| 111 } |
| 112 |
| 113 void SpeechInputManager::StopRecording(int caller_id) { |
| 114 DCHECK(HasPendingRequest(caller_id)); |
| 115 requests_[caller_id].recognizer->StopRecording(); |
| 116 } |
| 117 |
| 118 void SpeechInputManager::SetRecognitionResult( |
| 119 int caller_id, bool error, const SpeechInputResultArray& result) { |
| 120 DCHECK(HasPendingRequest(caller_id)); |
| 121 GetDelegate(caller_id)->SetRecognitionResult(caller_id, result); |
| 122 } |
| 123 |
| 124 void SpeechInputManager::DidCompleteRecording(int caller_id) { |
| 125 DCHECK(recording_caller_id_ == caller_id); |
| 126 DCHECK(HasPendingRequest(caller_id)); |
| 127 recording_caller_id_ = 0; |
| 128 GetDelegate(caller_id)->DidCompleteRecording(caller_id); |
| 129 ShowRecognizing(caller_id); |
| 130 } |
| 131 |
| 132 void SpeechInputManager::DidCompleteRecognition(int caller_id) { |
| 133 GetDelegate(caller_id)->DidCompleteRecognition(caller_id); |
| 134 requests_.erase(caller_id); |
| 135 DoClose(caller_id); |
| 136 } |
| 137 |
| 138 void SpeechInputManager::OnRecognizerError( |
| 139 int caller_id, SpeechRecognizer::ErrorCode error) { |
| 140 if (caller_id == recording_caller_id_) |
| 141 recording_caller_id_ = 0; |
| 142 requests_[caller_id].is_active = false; |
| 143 ShowRecognizerError(caller_id, error); |
| 144 } |
| 145 |
| 146 void SpeechInputManager::DidStartReceivingAudio(int caller_id) { |
| 147 DCHECK(HasPendingRequest(caller_id)); |
| 148 DCHECK(recording_caller_id_ == caller_id); |
| 149 ShowRecording(caller_id); |
| 150 } |
| 151 |
| 152 void SpeechInputManager::DidCompleteEnvironmentEstimation(int caller_id) { |
| 153 DCHECK(HasPendingRequest(caller_id)); |
| 154 DCHECK(recording_caller_id_ == caller_id); |
| 155 } |
| 156 |
| 157 void SpeechInputManager::SetInputVolume(int caller_id, float volume, |
| 158 float noise_volume) { |
| 159 DCHECK(HasPendingRequest(caller_id)); |
| 160 DCHECK_EQ(recording_caller_id_, caller_id); |
| 161 ShowInputVolume(caller_id, volume, noise_volume); |
| 162 } |
| 163 |
| 164 void SpeechInputManager::CancelRecognitionAndInformDelegate( |
| 165 int caller_id) { |
| 166 SpeechInputManagerDelegate* cur_delegate = GetDelegate(caller_id); |
| 167 CancelRecognition(caller_id); |
| 168 cur_delegate->DidCompleteRecording(caller_id); |
| 169 cur_delegate->DidCompleteRecognition(caller_id); |
| 170 } |
| 171 |
| 172 void SpeechInputManager::OnFocusChanged(int caller_id) { |
| 173 // Ignore if the caller id was not in our active recognizers list because the |
| 174 // user might have clicked more than once, or recognition could have been |
| 175 // ended due to other reasons before the user click was processed. |
| 176 if (HasPendingRequest(caller_id)) { |
| 177 // If this is an ongoing recording or if we were displaying an error message |
| 178 // to the user, abort it since user has switched focus. Otherwise |
| 179 // recognition has started and keep that going so user can start speaking to |
| 180 // another element while this gets the results in parallel. |
| 181 if (recording_caller_id_ == caller_id || !requests_[caller_id].is_active) { |
| 182 CancelRecognitionAndInformDelegate(caller_id); |
| 183 } |
| 184 } |
| 185 } |
| 186 |
33 } // namespace speech_input | 187 } // namespace speech_input |
OLD | NEW |