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 "chrome/browser/extensions/speech_input/extension_speech_input_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/speech_input/extension_speech_input_api_cons
tants.h" | 12 #include "chrome/browser/extensions/extension_service.h" |
| 13 #include "chrome/browser/prefs/pref_service.h" |
13 #include "chrome/browser/profiles/profile.h" | 14 #include "chrome/browser/profiles/profile.h" |
14 #include "chrome/browser/profiles/profile_dependency_manager.h" | 15 #include "chrome/browser/profiles/profile_dependency_manager.h" |
15 #include "chrome/browser/profiles/profile_keyed_service.h" | 16 #include "chrome/browser/profiles/profile_keyed_service.h" |
16 #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_input_extension_notification.h" |
17 #include "chrome/common/chrome_notification_types.h" | 19 #include "chrome/common/chrome_notification_types.h" |
18 #include "chrome/common/extensions/extension.h" | 20 #include "chrome/common/extensions/extension.h" |
| 21 #include "chrome/common/pref_names.h" |
19 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
20 #include "content/public/browser/notification_service.h" | 23 #include "content/public/browser/notification_service.h" |
21 | 24 |
22 using content::BrowserThread; | 25 using content::BrowserThread; |
23 | |
24 using namespace speech_input; | 26 using namespace speech_input; |
25 | 27 |
26 namespace constants = extension_speech_input_api_constants; | 28 namespace { |
27 | 29 |
28 namespace { | 30 const char kErrorNoRecordingDeviceFound[] = "noRecordingDeviceFound"; |
| 31 const char kErrorRecordingDeviceInUse[] = "recordingDeviceInUse"; |
| 32 const char kErrorUnableToStart[] = "unableToStart"; |
| 33 const char kErrorRequestDenied[] = "requestDenied"; |
| 34 const char kErrorRequestInProgress[] = "requestInProgress"; |
| 35 const char kErrorInvalidOperation[] = "invalidOperation"; |
| 36 |
| 37 const char kErrorCodeKey[] = "code"; |
| 38 const char kErrorCaptureError[] = "captureError"; |
| 39 const char kErrorNetworkError[] = "networkError"; |
| 40 const char kErrorNoSpeechHeard[] = "noSpeechHeard"; |
| 41 const char kErrorNoResults[] = "noResults"; |
| 42 |
| 43 const char kUtteranceKey[] = "utterance"; |
| 44 const char kConfidenceKey[] = "confidence"; |
| 45 const char kHypothesesKey[] = "hypotheses"; |
| 46 |
| 47 const char kOnErrorEvent[] = "experimental.speechInput.onError"; |
| 48 const char kOnResultEvent[] = "experimental.speechInput.onResult"; |
| 49 const char kOnSoundStartEvent[] = "experimental.speechInput.onSoundStart"; |
| 50 const char kOnSoundEndEvent[] = "experimental.speechInput.onSoundEnd"; |
29 | 51 |
30 // Caller id provided to the speech recognizer. Since only one extension can | 52 // Caller id provided to the speech recognizer. Since only one extension can |
31 // be recording on the same time a constant value is enough as id. | 53 // be recording on the same time a constant value is enough as id. |
32 static const int kSpeechCallerId = 1; | 54 static const int kSpeechCallerId = 1; |
33 | 55 |
34 // Wrap an ExtensionSpeechInputManager using scoped_refptr to avoid | 56 // Wrap an SpeechInputExtensionManager using scoped_refptr to avoid |
35 // assertion failures on destruction because of not using release(). | 57 // assertion failures on destruction because of not using release(). |
36 class ExtensionSpeechInputManagerWrapper : public ProfileKeyedService { | 58 class SpeechInputExtensionManagerWrapper : public ProfileKeyedService { |
37 public: | 59 public: |
38 explicit ExtensionSpeechInputManagerWrapper( | 60 explicit SpeechInputExtensionManagerWrapper( |
39 ExtensionSpeechInputManager* manager) | 61 SpeechInputExtensionManager* manager) |
40 : manager_(manager) {} | 62 : manager_(manager) {} |
41 | 63 |
42 virtual ~ExtensionSpeechInputManagerWrapper() {} | 64 virtual ~SpeechInputExtensionManagerWrapper() {} |
43 | 65 |
44 ExtensionSpeechInputManager* manager() const { return manager_.get(); } | 66 SpeechInputExtensionManager* manager() const { return manager_.get(); } |
45 | 67 |
46 private: | 68 private: |
47 // Methods from ProfileKeyedService. | 69 // Methods from ProfileKeyedService. |
48 virtual void Shutdown() OVERRIDE { | 70 virtual void Shutdown() OVERRIDE { |
49 manager()->ShutdownOnUIThread(); | 71 manager()->ShutdownOnUIThread(); |
50 } | 72 } |
51 | 73 |
52 scoped_refptr<ExtensionSpeechInputManager> manager_; | 74 scoped_refptr<SpeechInputExtensionManager> manager_; |
53 }; | 75 }; |
54 | 76 |
55 } | 77 } |
56 | 78 |
57 // Factory for ExtensionSpeechInputManagers as profile keyed services. | 79 // Factory for SpeechInputExtensionManagers as profile keyed services. |
58 class ExtensionSpeechInputManager::Factory : public ProfileKeyedServiceFactory { | 80 class SpeechInputExtensionManager::Factory : public ProfileKeyedServiceFactory { |
59 public: | 81 public: |
60 static void Initialize(); | 82 static void Initialize(); |
61 static Factory* GetInstance(); | 83 static Factory* GetInstance(); |
62 | 84 |
63 ExtensionSpeechInputManagerWrapper* GetForProfile(Profile* profile); | 85 SpeechInputExtensionManagerWrapper* GetForProfile(Profile* profile); |
64 | 86 |
65 private: | 87 private: |
66 friend struct DefaultSingletonTraits<Factory>; | 88 friend struct DefaultSingletonTraits<Factory>; |
67 | 89 |
68 Factory(); | 90 Factory(); |
69 virtual ~Factory(); | 91 virtual ~Factory(); |
70 | 92 |
71 // ProfileKeyedServiceFactory methods: | 93 // ProfileKeyedServiceFactory methods: |
72 virtual ProfileKeyedService* BuildServiceInstanceFor( | 94 virtual ProfileKeyedService* BuildServiceInstanceFor( |
73 Profile* profile) const OVERRIDE; | 95 Profile* profile) const OVERRIDE; |
74 virtual bool ServiceRedirectedInIncognito() OVERRIDE { return false; } | 96 virtual bool ServiceRedirectedInIncognito() OVERRIDE { return false; } |
75 virtual bool ServiceIsNULLWhileTesting() OVERRIDE { return true; } | 97 virtual bool ServiceIsNULLWhileTesting() OVERRIDE { return true; } |
76 virtual bool ServiceIsCreatedWithProfile() OVERRIDE { return true; } | 98 virtual bool ServiceIsCreatedWithProfile() OVERRIDE { return true; } |
77 | 99 |
78 DISALLOW_COPY_AND_ASSIGN(Factory); | 100 DISALLOW_COPY_AND_ASSIGN(Factory); |
79 }; | 101 }; |
80 | 102 |
81 void ExtensionSpeechInputManager::Factory::Initialize() { | 103 void SpeechInputExtensionManager::Factory::Initialize() { |
82 GetInstance(); | 104 GetInstance(); |
83 } | 105 } |
84 | 106 |
85 ExtensionSpeechInputManager::Factory* | 107 SpeechInputExtensionManager::Factory* |
86 ExtensionSpeechInputManager::Factory::GetInstance() { | 108 SpeechInputExtensionManager::Factory::GetInstance() { |
87 return Singleton<ExtensionSpeechInputManager::Factory>::get(); | 109 return Singleton<SpeechInputExtensionManager::Factory>::get(); |
88 } | 110 } |
89 | 111 |
90 ExtensionSpeechInputManagerWrapper* | 112 SpeechInputExtensionManagerWrapper* |
91 ExtensionSpeechInputManager::Factory::GetForProfile( | 113 SpeechInputExtensionManager::Factory::GetForProfile( |
92 Profile* profile) { | 114 Profile* profile) { |
93 return static_cast<ExtensionSpeechInputManagerWrapper*>( | 115 return static_cast<SpeechInputExtensionManagerWrapper*>( |
94 GetServiceForProfile(profile, true)); | 116 GetServiceForProfile(profile, true)); |
95 } | 117 } |
96 | 118 |
97 ExtensionSpeechInputManager::Factory::Factory() | 119 SpeechInputExtensionManager::Factory::Factory() |
98 : ProfileKeyedServiceFactory(ProfileDependencyManager::GetInstance()) { | 120 : ProfileKeyedServiceFactory(ProfileDependencyManager::GetInstance()) { |
99 } | 121 } |
100 | 122 |
101 ExtensionSpeechInputManager::Factory::~Factory() { | 123 SpeechInputExtensionManager::Factory::~Factory() { |
102 } | 124 } |
103 | 125 |
104 ProfileKeyedService* | 126 ProfileKeyedService* |
105 ExtensionSpeechInputManager::Factory::BuildServiceInstanceFor( | 127 SpeechInputExtensionManager::Factory::BuildServiceInstanceFor( |
106 Profile* profile) const { | 128 Profile* profile) const { |
107 scoped_refptr<ExtensionSpeechInputManager> manager( | 129 scoped_refptr<SpeechInputExtensionManager> manager( |
108 new ExtensionSpeechInputManager(profile)); | 130 new SpeechInputExtensionManager(profile)); |
109 return new ExtensionSpeechInputManagerWrapper(manager); | 131 return new SpeechInputExtensionManagerWrapper(manager); |
110 } | 132 } |
111 | 133 |
112 ExtensionSpeechInterface::ExtensionSpeechInterface() { | 134 SpeechInputExtensionInterface::SpeechInputExtensionInterface() { |
113 } | 135 } |
114 | 136 |
115 ExtensionSpeechInterface::~ExtensionSpeechInterface() { | 137 SpeechInputExtensionInterface::~SpeechInputExtensionInterface() { |
116 } | 138 } |
117 | 139 |
118 ExtensionSpeechInputManager::ExtensionSpeechInputManager(Profile* profile) | 140 SpeechInputExtensionManager::SpeechInputExtensionManager(Profile* profile) |
119 : profile_(profile), | 141 : profile_(profile), |
120 state_(kIdle), | 142 state_(kIdle), |
121 speech_interface_(NULL) { | 143 speech_interface_(NULL) { |
122 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | 144 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
123 content::Source<Profile>(profile_)); | 145 content::Source<Profile>(profile_)); |
124 } | 146 } |
125 | 147 |
126 ExtensionSpeechInputManager::~ExtensionSpeechInputManager() { | 148 SpeechInputExtensionManager::~SpeechInputExtensionManager() { |
127 } | 149 } |
128 | 150 |
129 ExtensionSpeechInputManager* ExtensionSpeechInputManager::GetForProfile( | 151 SpeechInputExtensionManager* SpeechInputExtensionManager::GetForProfile( |
130 Profile* profile) { | 152 Profile* profile) { |
131 ExtensionSpeechInputManagerWrapper *wrapper = | 153 SpeechInputExtensionManagerWrapper *wrapper = |
132 Factory::GetInstance()->GetForProfile(profile); | 154 Factory::GetInstance()->GetForProfile(profile); |
133 if (!wrapper) | 155 if (!wrapper) |
134 return NULL; | 156 return NULL; |
135 return wrapper->manager(); | 157 return wrapper->manager(); |
136 } | 158 } |
137 | 159 |
138 void ExtensionSpeechInputManager::InitializeFactory() { | 160 void SpeechInputExtensionManager::InitializeFactory() { |
139 Factory::Initialize(); | 161 Factory::Initialize(); |
140 } | 162 } |
141 | 163 |
142 void ExtensionSpeechInputManager::Observe(int type, | 164 void SpeechInputExtensionManager::Observe(int type, |
143 const content::NotificationSource& source, | 165 const content::NotificationSource& source, |
144 const content::NotificationDetails& details) { | 166 const content::NotificationDetails& details) { |
145 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) { | 167 if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) { |
146 ExtensionUnloaded( | 168 ExtensionUnloaded( |
147 content::Details<UnloadedExtensionInfo>(details)->extension->id()); | 169 content::Details<UnloadedExtensionInfo>(details)->extension->id()); |
148 } else { | 170 } else { |
149 NOTREACHED(); | 171 NOTREACHED(); |
150 } | 172 } |
151 } | 173 } |
152 | 174 |
153 void ExtensionSpeechInputManager::ShutdownOnUIThread() { | 175 void SpeechInputExtensionManager::ShutdownOnUIThread() { |
154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
155 VLOG(1) << "Profile shutting down."; | 177 VLOG(1) << "Profile shutting down."; |
156 | 178 |
157 base::AutoLock auto_lock(state_lock_); | 179 base::AutoLock auto_lock(state_lock_); |
158 DCHECK(state_ != kShutdown); | 180 DCHECK(state_ != kShutdown); |
159 if (state_ != kIdle) { | 181 if (state_ != kIdle) { |
| 182 DCHECK(notification_.get()); |
| 183 notification_->Hide(); |
160 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 184 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
161 base::Bind(&ExtensionSpeechInputManager::ForceStopOnIOThread, this)); | 185 base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); |
162 } | 186 } |
163 state_ = kShutdown; | 187 state_ = kShutdown; |
164 VLOG(1) << "Entering the shutdown sink state."; | 188 VLOG(1) << "Entering the shutdown sink state."; |
165 registrar_.RemoveAll(); | 189 registrar_.RemoveAll(); |
166 profile_ = NULL; | 190 profile_ = NULL; |
167 } | 191 } |
168 | 192 |
169 void ExtensionSpeechInputManager::ExtensionUnloaded( | 193 void SpeechInputExtensionManager::ExtensionUnloaded( |
170 const std::string& extension_id) { | 194 const std::string& extension_id) { |
171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
172 | 196 |
173 base::AutoLock auto_lock(state_lock_); | 197 base::AutoLock auto_lock(state_lock_); |
174 if (state_ == kShutdown) | 198 if (state_ == kShutdown) |
175 return; | 199 return; |
176 | 200 |
177 VLOG(1) << "Extension unloaded. Requesting to enforce stop..."; | 201 VLOG(1) << "Extension unloaded. Requesting to enforce stop..."; |
178 if (extension_id_in_use_ == extension_id) { | 202 if (extension_id_in_use_ == extension_id) { |
179 if (state_ != kIdle) { | 203 if (state_ != kIdle) { |
180 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 204 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
181 base::Bind(&ExtensionSpeechInputManager::ForceStopOnIOThread, this)); | 205 base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); |
182 } | 206 } |
183 } | 207 } |
184 } | 208 } |
185 | 209 |
186 void ExtensionSpeechInputManager::SetExtensionSpeechInterface( | 210 void SpeechInputExtensionManager::SetSpeechInputExtensionInterface( |
187 ExtensionSpeechInterface* interface) { | 211 SpeechInputExtensionInterface* interface) { |
188 speech_interface_ = interface; | 212 speech_interface_ = interface; |
189 } | 213 } |
190 | 214 |
191 ExtensionSpeechInterface* | 215 SpeechInputExtensionInterface* |
192 ExtensionSpeechInputManager::GetExtensionSpeechInterface() { | 216 SpeechInputExtensionManager::GetSpeechInputExtensionInterface() { |
193 return speech_interface_ ? speech_interface_ : this; | 217 return speech_interface_ ? speech_interface_ : this; |
194 } | 218 } |
195 | 219 |
196 void ExtensionSpeechInputManager::ResetToIdleState() { | 220 void SpeechInputExtensionManager::ResetToIdleState() { |
197 VLOG(1) << "State changed to idle. Deassociating any extensions."; | 221 VLOG(1) << "State changed to idle. Deassociating any extensions."; |
198 state_ = kIdle; | 222 state_ = kIdle; |
199 extension_id_in_use_.clear(); | 223 extension_id_in_use_.clear(); |
200 } | 224 } |
201 | 225 |
202 void ExtensionSpeechInputManager::SetRecognitionResult( | 226 void SpeechInputExtensionManager::SetRecognitionResult( |
203 int caller_id, | 227 int caller_id, |
204 const SpeechInputResult& result) { | 228 const SpeechInputResult& result) { |
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 229 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
206 DCHECK_EQ(caller_id, kSpeechCallerId); | 230 DCHECK_EQ(caller_id, kSpeechCallerId); |
207 | 231 |
208 // Stopping will start the disassociation with the extension. | 232 // Stopping will start the disassociation with the extension. |
209 // Make a copy to report the results to the proper one. | 233 // Make a copy to report the results to the proper one. |
210 std::string extension_id = extension_id_in_use_; | 234 std::string extension_id = extension_id_in_use_; |
211 ForceStopOnIOThread(); | 235 ForceStopOnIOThread(); |
212 | 236 |
213 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 237 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
214 base::Bind(&ExtensionSpeechInputManager::SetRecognitionResultOnUIThread, | 238 base::Bind(&SpeechInputExtensionManager::SetRecognitionResultOnUIThread, |
215 this, result, extension_id)); | 239 this, result, extension_id)); |
216 } | 240 } |
217 | 241 |
218 void ExtensionSpeechInputManager::SetRecognitionResultOnUIThread( | 242 void SpeechInputExtensionManager::SetRecognitionResultOnUIThread( |
219 const SpeechInputResult& result, const std::string& extension_id) { | 243 const SpeechInputResult& result, const std::string& extension_id) { |
220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
221 | 245 |
222 ListValue args; | 246 ListValue args; |
223 DictionaryValue* js_event = new DictionaryValue(); | 247 DictionaryValue* js_event = new DictionaryValue(); |
224 args.Append(js_event); | 248 args.Append(js_event); |
225 | 249 |
226 ListValue* js_hypothesis_array = new ListValue(); | 250 ListValue* js_hypothesis_array = new ListValue(); |
227 js_event->Set(constants::kHypothesesKey, js_hypothesis_array); | 251 js_event->Set(kHypothesesKey, js_hypothesis_array); |
228 | 252 |
229 for (size_t i = 0; i < result.hypotheses.size(); ++i) { | 253 for (size_t i = 0; i < result.hypotheses.size(); ++i) { |
230 const SpeechInputHypothesis& hypothesis = result.hypotheses[i]; | 254 const SpeechInputHypothesis& hypothesis = result.hypotheses[i]; |
231 | 255 |
232 DictionaryValue* js_hypothesis_object = new DictionaryValue(); | 256 DictionaryValue* js_hypothesis_object = new DictionaryValue(); |
233 js_hypothesis_array->Append(js_hypothesis_object); | 257 js_hypothesis_array->Append(js_hypothesis_object); |
234 | 258 |
235 js_hypothesis_object->SetString(constants::kUtteranceKey, | 259 js_hypothesis_object->SetString(kUtteranceKey, |
236 UTF16ToUTF8(hypothesis.utterance)); | 260 UTF16ToUTF8(hypothesis.utterance)); |
237 js_hypothesis_object->SetDouble(constants::kConfidenceKey, | 261 js_hypothesis_object->SetDouble(kConfidenceKey, |
238 hypothesis.confidence); | 262 hypothesis.confidence); |
239 } | 263 } |
240 | 264 |
241 std::string json_args; | 265 std::string json_args; |
242 base::JSONWriter::Write(&args, false, &json_args); | 266 base::JSONWriter::Write(&args, false, &json_args); |
243 VLOG(1) << "Results: " << json_args; | 267 VLOG(1) << "Results: " << json_args; |
244 DispatchEventToExtension(extension_id, constants::kOnResultEvent, json_args); | 268 DispatchEventToExtension(extension_id, kOnResultEvent, json_args); |
245 } | 269 } |
246 | 270 |
247 void ExtensionSpeechInputManager::DidStartReceivingAudio(int caller_id) { | 271 void SpeechInputExtensionManager::DidStartReceivingAudio(int caller_id) { |
248 VLOG(1) << "DidStartReceivingAudio"; | 272 VLOG(1) << "DidStartReceivingAudio"; |
249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
250 DCHECK_EQ(caller_id, kSpeechCallerId); | 274 DCHECK_EQ(caller_id, kSpeechCallerId); |
251 | 275 |
252 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 276 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
253 base::Bind(&ExtensionSpeechInputManager::DidStartReceivingAudioOnUIThread, | 277 base::Bind(&SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread, |
254 this)); | 278 this)); |
255 } | 279 } |
256 | 280 |
257 void ExtensionSpeechInputManager::DidCompleteRecording(int caller_id) { | 281 void SpeechInputExtensionManager::DidCompleteRecording(int caller_id) { |
258 DCHECK_EQ(caller_id, kSpeechCallerId); | 282 DCHECK_EQ(caller_id, kSpeechCallerId); |
259 } | 283 } |
260 | 284 |
261 void ExtensionSpeechInputManager::DidCompleteRecognition(int caller_id) { | 285 void SpeechInputExtensionManager::DidCompleteRecognition(int caller_id) { |
262 DCHECK_EQ(caller_id, kSpeechCallerId); | 286 DCHECK_EQ(caller_id, kSpeechCallerId); |
263 } | 287 } |
264 | 288 |
265 void ExtensionSpeechInputManager::DidStartReceivingAudioOnUIThread() { | 289 void SpeechInputExtensionManager::DidStartReceivingAudioOnUIThread() { |
266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
267 | 291 |
268 base::AutoLock auto_lock(state_lock_); | 292 base::AutoLock auto_lock(state_lock_); |
269 if (state_ == kShutdown) | 293 if (state_ == kShutdown) |
270 return; | 294 return; |
271 | 295 |
272 DCHECK_EQ(state_, kStarting); | 296 DCHECK_EQ(state_, kStarting); |
273 VLOG(1) << "State changed to recording"; | 297 VLOG(1) << "State changed to recording"; |
274 state_ = kRecording; | 298 state_ = kRecording; |
275 | 299 |
| 300 const Extension* extension = profile_->GetExtensionService()-> |
| 301 GetExtensionById(extension_id_in_use_, true); |
| 302 DCHECK(extension); |
| 303 |
| 304 bool show_notification = !profile_->GetPrefs()->GetBoolean( |
| 305 prefs::kSpeechInputTrayNotificationShown); |
| 306 |
| 307 if (!notification_.get()) |
| 308 notification_.reset(new SpeechInputExtensionNotification(profile_)); |
| 309 notification_->Show(extension, show_notification); |
| 310 |
| 311 if (show_notification) { |
| 312 profile_->GetPrefs()->SetBoolean( |
| 313 prefs::kSpeechInputTrayNotificationShown, true); |
| 314 } |
| 315 |
276 VLOG(1) << "Sending start notification"; | 316 VLOG(1) << "Sending start notification"; |
277 content::NotificationService::current()->Notify( | 317 content::NotificationService::current()->Notify( |
278 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED, | 318 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STARTED, |
279 content::Source<Profile>(profile_), | 319 content::Source<Profile>(profile_), |
280 content::Details<std::string>(&extension_id_in_use_)); | 320 content::Details<std::string>(&extension_id_in_use_)); |
281 } | 321 } |
282 | 322 |
283 void ExtensionSpeechInputManager::OnRecognizerError( | 323 void SpeechInputExtensionManager::OnRecognizerError( |
284 int caller_id, SpeechInputError error) { | 324 int caller_id, SpeechInputError error) { |
285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
286 DCHECK_EQ(caller_id, kSpeechCallerId); | 326 DCHECK_EQ(caller_id, kSpeechCallerId); |
287 VLOG(1) << "OnRecognizerError: " << error; | 327 VLOG(1) << "OnRecognizerError: " << error; |
288 | 328 |
289 base::AutoLock auto_lock(state_lock_); | 329 base::AutoLock auto_lock(state_lock_); |
290 if (state_ == kShutdown) | 330 if (state_ == kShutdown) |
291 return; | 331 return; |
292 | 332 |
293 // Release the recognizer object. | 333 // Release the recognizer object. |
294 GetExtensionSpeechInterface()->StopRecording(true); | 334 GetSpeechInputExtensionInterface()->StopRecording(true); |
295 | 335 |
296 std::string event_error_code; | 336 std::string event_error_code; |
297 bool report_to_event = true; | 337 bool report_to_event = true; |
298 | 338 |
299 switch (error) { | 339 switch (error) { |
300 case kErrorNone: | 340 case kErrorNone: |
301 break; | 341 break; |
302 | 342 |
303 case kErrorAudio: | 343 case kErrorAudio: |
304 if (state_ == kStarting) { | 344 if (state_ == kStarting) { |
305 event_error_code = constants::kErrorUnableToStart; | 345 event_error_code = kErrorUnableToStart; |
306 report_to_event = false; | 346 report_to_event = false; |
307 } else { | 347 } else { |
308 event_error_code = constants::kErrorCaptureError; | 348 event_error_code = kErrorCaptureError; |
309 } | 349 } |
310 break; | 350 break; |
311 | 351 |
312 case kErrorNetwork: | 352 case kErrorNetwork: |
313 event_error_code = constants::kErrorNetworkError; | 353 event_error_code = kErrorNetworkError; |
314 break; | 354 break; |
315 | 355 |
316 case kErrorBadGrammar: | 356 case kErrorBadGrammar: |
317 // No error is returned on invalid language, for example. | 357 // No error is returned on invalid language, for example. |
318 // To avoid confusion about when this is would be fired, the invalid | 358 // To avoid confusion about when this is would be fired, the invalid |
319 // params error is not being exposed to the onError event. | 359 // params error is not being exposed to the onError event. |
320 event_error_code = constants::kErrorUnableToStart; | 360 event_error_code = kErrorUnableToStart; |
321 break; | 361 break; |
322 | 362 |
323 case kErrorNoSpeech: | 363 case kErrorNoSpeech: |
324 event_error_code = constants::kErrorNoSpeechHeard; | 364 event_error_code = kErrorNoSpeechHeard; |
325 break; | 365 break; |
326 | 366 |
327 case kErrorNoMatch: | 367 case kErrorNoMatch: |
328 event_error_code = constants::kErrorNoResults; | 368 event_error_code = kErrorNoResults; |
329 break; | 369 break; |
330 | 370 |
331 // The remaining kErrorAborted case should never be returned by the server. | 371 // The remaining kErrorAborted case should never be returned by the server. |
332 default: | 372 default: |
333 NOTREACHED(); | 373 NOTREACHED(); |
334 } | 374 } |
335 | 375 |
336 if (!event_error_code.empty()) { | 376 if (!event_error_code.empty()) { |
337 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 377 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
338 base::Bind(&ExtensionSpeechInputManager::DispatchError, | 378 base::Bind(&SpeechInputExtensionManager::DispatchError, |
339 this, event_error_code, report_to_event)); | 379 this, event_error_code, report_to_event)); |
340 } | 380 } |
341 } | 381 } |
342 | 382 |
343 void ExtensionSpeechInputManager::DidCompleteEnvironmentEstimation( | 383 void SpeechInputExtensionManager::DidCompleteEnvironmentEstimation( |
344 int caller_id) { | 384 int caller_id) { |
345 DCHECK_EQ(caller_id, kSpeechCallerId); | 385 DCHECK_EQ(caller_id, kSpeechCallerId); |
346 } | 386 } |
347 | 387 |
348 void ExtensionSpeechInputManager::DidStartReceivingSpeech(int caller_id) { | 388 void SpeechInputExtensionManager::DidStartReceivingSpeech(int caller_id) { |
349 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 389 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
350 DCHECK_EQ(caller_id, kSpeechCallerId); | 390 DCHECK_EQ(caller_id, kSpeechCallerId); |
351 VLOG(1) << "DidStartReceivingSpeech"; | 391 VLOG(1) << "DidStartReceivingSpeech"; |
352 | 392 |
353 std::string json_args; | 393 std::string json_args; |
354 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 394 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
355 base::Bind(&ExtensionSpeechInputManager::DispatchEventToExtension, | 395 base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension, |
356 this, extension_id_in_use_, std::string(constants::kOnSoundStartEvent), | 396 this, extension_id_in_use_, std::string(kOnSoundStartEvent), |
357 json_args)); | 397 json_args)); |
358 } | 398 } |
359 | 399 |
360 void ExtensionSpeechInputManager::DidStopReceivingSpeech(int caller_id) { | 400 void SpeechInputExtensionManager::DidStopReceivingSpeech(int caller_id) { |
361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 401 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
362 DCHECK_EQ(caller_id, kSpeechCallerId); | 402 DCHECK_EQ(caller_id, kSpeechCallerId); |
363 VLOG(1) << "DidStopReceivingSpeech"; | 403 VLOG(1) << "DidStopReceivingSpeech"; |
364 | 404 |
365 std::string json_args; | 405 std::string json_args; |
366 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 406 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
367 base::Bind(&ExtensionSpeechInputManager::DispatchEventToExtension, | 407 base::Bind(&SpeechInputExtensionManager::DispatchEventToExtension, |
368 this, extension_id_in_use_, std::string(constants::kOnSoundEndEvent), | 408 this, extension_id_in_use_, std::string(kOnSoundEndEvent), |
369 json_args)); | 409 json_args)); |
370 } | 410 } |
371 | 411 |
372 void ExtensionSpeechInputManager::DispatchEventToExtension( | 412 void SpeechInputExtensionManager::DispatchEventToExtension( |
373 const std::string& extension_id, const std::string& event, | 413 const std::string& extension_id, const std::string& event, |
374 const std::string& json_args) { | 414 const std::string& json_args) { |
375 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 415 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
376 | 416 |
377 base::AutoLock auto_lock(state_lock_); | 417 base::AutoLock auto_lock(state_lock_); |
378 if (state_ == kShutdown) | 418 if (state_ == kShutdown) |
379 return; | 419 return; |
380 | 420 |
381 if (profile_ && profile_->GetExtensionEventRouter()) { | 421 if (profile_ && profile_->GetExtensionEventRouter()) { |
382 std::string final_args; | 422 std::string final_args; |
383 if (json_args.empty()) { | 423 if (json_args.empty()) { |
384 ListValue args; | 424 ListValue args; |
385 base::JSONWriter::Write(&args, false, &final_args); | 425 base::JSONWriter::Write(&args, false, &final_args); |
386 } else { | 426 } else { |
387 final_args = json_args; | 427 final_args = json_args; |
388 } | 428 } |
389 | 429 |
390 profile_->GetExtensionEventRouter()->DispatchEventToExtension( | 430 profile_->GetExtensionEventRouter()->DispatchEventToExtension( |
391 extension_id, event, final_args, profile_, GURL()); | 431 extension_id, event, final_args, profile_, GURL()); |
392 } | 432 } |
393 } | 433 } |
394 | 434 |
395 void ExtensionSpeechInputManager::DispatchError( | 435 void SpeechInputExtensionManager::DispatchError( |
396 const std::string& error, bool dispatch_event) { | 436 const std::string& error, bool dispatch_event) { |
397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 437 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
398 | 438 |
399 std::string extension_id; | 439 std::string extension_id; |
400 { | 440 { |
401 base::AutoLock auto_lock(state_lock_); | 441 base::AutoLock auto_lock(state_lock_); |
402 if (state_ == kShutdown) | 442 if (state_ == kShutdown) |
403 return; | 443 return; |
404 | 444 |
| 445 if (state_ == kRecording) { |
| 446 DCHECK(notification_.get()); |
| 447 notification_->Hide(); |
| 448 } |
| 449 |
405 extension_id = extension_id_in_use_; | 450 extension_id = extension_id_in_use_; |
406 ResetToIdleState(); | 451 ResetToIdleState(); |
407 | 452 |
408 // Will set the error property in the ongoing extension function calls. | 453 // Will set the error property in the ongoing extension function calls. |
409 ExtensionError details(extension_id, error); | 454 ExtensionError details(extension_id, error); |
410 content::NotificationService::current()->Notify( | 455 content::NotificationService::current()->Notify( |
411 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_FAILED, | 456 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_FAILED, |
412 content::Source<Profile>(profile_), | 457 content::Source<Profile>(profile_), |
413 content::Details<ExtensionError>(&details)); | 458 content::Details<ExtensionError>(&details)); |
414 } | 459 } |
415 | 460 |
416 // Used for errors that are also reported via the onError event. | 461 // Used for errors that are also reported via the onError event. |
417 if (dispatch_event) { | 462 if (dispatch_event) { |
418 ListValue args; | 463 ListValue args; |
419 DictionaryValue *js_error = new DictionaryValue(); | 464 DictionaryValue *js_error = new DictionaryValue(); |
420 args.Append(js_error); | 465 args.Append(js_error); |
421 js_error->SetString(constants::kErrorCodeKey, error); | 466 js_error->SetString(kErrorCodeKey, error); |
422 std::string json_args; | 467 std::string json_args; |
423 base::JSONWriter::Write(&args, false, &json_args); | 468 base::JSONWriter::Write(&args, false, &json_args); |
424 DispatchEventToExtension(extension_id, | 469 DispatchEventToExtension(extension_id, |
425 constants::kOnErrorEvent, json_args); | 470 kOnErrorEvent, json_args); |
426 } | 471 } |
427 } | 472 } |
428 | 473 |
429 bool ExtensionSpeechInputManager::Start(const std::string& extension_id, | 474 bool SpeechInputExtensionManager::Start(const std::string& extension_id, |
430 const std::string& language, const std::string& grammar, | 475 const std::string& language, const std::string& grammar, |
431 bool filter_profanities, std::string* error) { | 476 bool filter_profanities, std::string* error) { |
432 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 477 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
433 DCHECK(error); | 478 DCHECK(error); |
434 VLOG(1) << "Requesting start (UI thread)"; | 479 VLOG(1) << "Requesting start (UI thread)"; |
435 | 480 |
436 base::AutoLock auto_lock(state_lock_); | 481 base::AutoLock auto_lock(state_lock_); |
437 if (state_ == kShutdown || | 482 if (state_ == kShutdown || |
438 (!extension_id_in_use_.empty() && extension_id_in_use_ != extension_id)) { | 483 (!extension_id_in_use_.empty() && extension_id_in_use_ != extension_id)) { |
439 *error = constants::kErrorRequestDenied; | 484 *error = kErrorRequestDenied; |
440 return false; | 485 return false; |
441 } | 486 } |
442 | 487 |
443 switch (state_) { | 488 switch (state_) { |
444 case kIdle: | 489 case kIdle: |
445 break; | 490 break; |
446 | 491 |
447 case kStarting: | 492 case kStarting: |
448 *error = constants::kErrorRequestInProgress; | 493 *error = kErrorRequestInProgress; |
449 return false; | 494 return false; |
450 | 495 |
451 case kRecording: | 496 case kRecording: |
452 case kStopping: | 497 case kStopping: |
453 *error = constants::kErrorInvalidOperation; | 498 *error = kErrorInvalidOperation; |
454 return false; | 499 return false; |
455 | 500 |
456 default: | 501 default: |
457 NOTREACHED(); | 502 NOTREACHED(); |
458 } | 503 } |
459 | 504 |
460 extension_id_in_use_ = extension_id; | 505 extension_id_in_use_ = extension_id; |
461 VLOG(1) << "State changed to starting"; | 506 VLOG(1) << "State changed to starting"; |
462 state_ = kStarting; | 507 state_ = kStarting; |
463 | 508 |
464 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 509 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
465 base::Bind(&ExtensionSpeechInputManager::StartOnIOThread, this, | 510 base::Bind(&SpeechInputExtensionManager::StartOnIOThread, this, |
466 profile_->GetRequestContext(), language, grammar, filter_profanities)); | 511 profile_->GetRequestContext(), language, grammar, filter_profanities)); |
467 return true; | 512 return true; |
468 } | 513 } |
469 | 514 |
470 void ExtensionSpeechInputManager::StartOnIOThread( | 515 void SpeechInputExtensionManager::StartOnIOThread( |
471 net::URLRequestContextGetter* context_getter, | 516 net::URLRequestContextGetter* context_getter, |
472 const std::string& language, const std::string& grammar, | 517 const std::string& language, const std::string& grammar, |
473 bool filter_profanities) { | 518 bool filter_profanities) { |
474 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
475 VLOG(1) << "Requesting start (IO thread)"; | 520 VLOG(1) << "Requesting start (IO thread)"; |
476 | 521 |
477 // Everything put inside the lock to ensure the validity of context_getter, | 522 // Everything put inside the lock to ensure the validity of context_getter, |
478 // guaranteed while not in the shutdown state. Any ongoing or recognition | 523 // guaranteed while not in the shutdown state. Any ongoing or recognition |
479 // request will be requested to be aborted when entering the shutdown state. | 524 // request will be requested to be aborted when entering the shutdown state. |
480 base::AutoLock auto_lock(state_lock_); | 525 base::AutoLock auto_lock(state_lock_); |
481 if (state_ == kShutdown) | 526 if (state_ == kShutdown) |
482 return; | 527 return; |
483 | 528 |
484 if (!GetExtensionSpeechInterface()->HasAudioInputDevices()) { | 529 if (!GetSpeechInputExtensionInterface()->HasAudioInputDevices()) { |
485 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 530 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
486 base::Bind(&ExtensionSpeechInputManager::DispatchError, this, | 531 base::Bind(&SpeechInputExtensionManager::DispatchError, this, |
487 std::string(constants::kErrorNoRecordingDeviceFound), false)); | 532 std::string(kErrorNoRecordingDeviceFound), false)); |
488 return; | 533 return; |
489 } | 534 } |
490 | 535 |
491 if (GetExtensionSpeechInterface()->IsRecordingInProcess()) { | 536 if (GetSpeechInputExtensionInterface()->IsRecordingInProcess()) { |
492 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 537 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
493 base::Bind(&ExtensionSpeechInputManager::DispatchError, this, | 538 base::Bind(&SpeechInputExtensionManager::DispatchError, this, |
494 std::string(constants::kErrorRecordingDeviceInUse), false)); | 539 std::string(kErrorRecordingDeviceInUse), false)); |
495 return; | 540 return; |
496 } | 541 } |
497 | 542 |
498 GetExtensionSpeechInterface()->StartRecording(this, context_getter, | 543 GetSpeechInputExtensionInterface()->StartRecording(this, context_getter, |
499 kSpeechCallerId, language, grammar, filter_profanities); | 544 kSpeechCallerId, language, grammar, filter_profanities); |
500 } | 545 } |
501 | 546 |
502 bool ExtensionSpeechInputManager::HasAudioInputDevices() { | 547 bool SpeechInputExtensionManager::HasAudioInputDevices() { |
503 return AudioManager::GetAudioManager()->HasAudioInputDevices(); | 548 return AudioManager::GetAudioManager()->HasAudioInputDevices(); |
504 } | 549 } |
505 | 550 |
506 bool ExtensionSpeechInputManager::IsRecordingInProcess() { | 551 bool SpeechInputExtensionManager::IsRecordingInProcess() { |
507 // Thread-safe query. | 552 // Thread-safe query. |
508 return AudioManager::GetAudioManager()->IsRecordingInProcess(); | 553 return AudioManager::GetAudioManager()->IsRecordingInProcess(); |
509 } | 554 } |
510 | 555 |
511 bool ExtensionSpeechInputManager::IsRecording() { | 556 bool SpeechInputExtensionManager::IsRecording() { |
512 return GetExtensionSpeechInterface()->IsRecordingInProcess(); | 557 return GetSpeechInputExtensionInterface()->IsRecordingInProcess(); |
513 } | 558 } |
514 | 559 |
515 void ExtensionSpeechInputManager::StartRecording( | 560 void SpeechInputExtensionManager::StartRecording( |
516 speech_input::SpeechRecognizerDelegate* delegate, | 561 speech_input::SpeechRecognizerDelegate* delegate, |
517 net::URLRequestContextGetter* context_getter, int caller_id, | 562 net::URLRequestContextGetter* context_getter, int caller_id, |
518 const std::string& language, const std::string& grammar, | 563 const std::string& language, const std::string& grammar, |
519 bool filter_profanities) { | 564 bool filter_profanities) { |
520 DCHECK(!recognizer_); | 565 DCHECK(!recognizer_); |
521 recognizer_ = new SpeechRecognizer(delegate, caller_id, language, grammar, | 566 recognizer_ = new SpeechRecognizer(delegate, caller_id, language, grammar, |
522 context_getter, filter_profanities, "", ""); | 567 context_getter, filter_profanities, "", ""); |
523 recognizer_->StartRecording(); | 568 recognizer_->StartRecording(); |
524 } | 569 } |
525 | 570 |
526 bool ExtensionSpeechInputManager::HasValidRecognizer() { | 571 bool SpeechInputExtensionManager::HasValidRecognizer() { |
527 // Conditional expression used to avoid a performance warning on windows. | 572 // Conditional expression used to avoid a performance warning on windows. |
528 return recognizer_ ? true : false; | 573 return recognizer_ ? true : false; |
529 } | 574 } |
530 | 575 |
531 bool ExtensionSpeechInputManager::Stop(const std::string& extension_id, | 576 bool SpeechInputExtensionManager::Stop(const std::string& extension_id, |
532 std::string* error) { | 577 std::string* error) { |
533 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 578 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
534 DCHECK(error); | 579 DCHECK(error); |
535 VLOG(1) << "Requesting stop (UI thread)"; | 580 VLOG(1) << "Requesting stop (UI thread)"; |
536 | 581 |
537 base::AutoLock auto_lock(state_lock_); | 582 base::AutoLock auto_lock(state_lock_); |
538 if (state_ == kShutdown || | 583 if (state_ == kShutdown || |
539 (!extension_id_in_use_.empty() && extension_id_in_use_ != extension_id)) { | 584 (!extension_id_in_use_.empty() && extension_id_in_use_ != extension_id)) { |
540 *error = constants::kErrorRequestDenied; | 585 *error = kErrorRequestDenied; |
541 return false; | 586 return false; |
542 } | 587 } |
543 | 588 |
544 switch (state_) { | 589 switch (state_) { |
545 case kRecording: | 590 case kRecording: |
546 break; | 591 break; |
547 | 592 |
548 case kStopping: | 593 case kStopping: |
549 *error = constants::kErrorRequestInProgress; | 594 *error = kErrorRequestInProgress; |
550 return false; | 595 return false; |
551 | 596 |
552 case kIdle: | 597 case kIdle: |
553 case kStarting: | 598 case kStarting: |
554 *error = constants::kErrorInvalidOperation; | 599 *error = kErrorInvalidOperation; |
555 return false; | 600 return false; |
556 | 601 |
557 default: | 602 default: |
558 NOTREACHED(); | 603 NOTREACHED(); |
559 } | 604 } |
560 | 605 |
561 // Guarded by the state lock. | 606 // Guarded by the state lock. |
562 DCHECK(GetExtensionSpeechInterface()->HasValidRecognizer()); | 607 DCHECK(GetSpeechInputExtensionInterface()->HasValidRecognizer()); |
563 | 608 |
564 VLOG(1) << "State changed to stopping"; | 609 VLOG(1) << "State changed to stopping"; |
565 state_ = kStopping; | 610 state_ = kStopping; |
566 | 611 |
567 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 612 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
568 base::Bind(&ExtensionSpeechInputManager::ForceStopOnIOThread, this)); | 613 base::Bind(&SpeechInputExtensionManager::ForceStopOnIOThread, this)); |
569 return true; | 614 return true; |
570 } | 615 } |
571 | 616 |
572 void ExtensionSpeechInputManager::ForceStopOnIOThread() { | 617 void SpeechInputExtensionManager::ForceStopOnIOThread() { |
573 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 618 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
574 VLOG(1) << "Requesting forced stop (IO thread)"; | 619 VLOG(1) << "Requesting forced stop (IO thread)"; |
575 | 620 |
576 base::AutoLock auto_lock(state_lock_); | 621 base::AutoLock auto_lock(state_lock_); |
577 DCHECK(state_ != kIdle); | 622 DCHECK(state_ != kIdle); |
578 | 623 |
579 GetExtensionSpeechInterface()->StopRecording(false); | 624 GetSpeechInputExtensionInterface()->StopRecording(false); |
580 | 625 |
581 if (state_ == kShutdown) | 626 if (state_ == kShutdown) |
582 return; | 627 return; |
583 | 628 |
584 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 629 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
585 base::Bind(&ExtensionSpeechInputManager::StopSucceededOnUIThread, this)); | 630 base::Bind(&SpeechInputExtensionManager::StopSucceededOnUIThread, this)); |
586 } | 631 } |
587 | 632 |
588 void ExtensionSpeechInputManager::StopRecording(bool recognition_failed) { | 633 void SpeechInputExtensionManager::StopRecording(bool recognition_failed) { |
589 if (recognizer_) { | 634 if (recognizer_) { |
590 // Recognition is already cancelled in case of failure. | 635 // Recognition is already cancelled in case of failure. |
591 // Double-cancelling leads to assertion failures. | 636 // Double-cancelling leads to assertion failures. |
592 if (!recognition_failed) | 637 if (!recognition_failed) |
593 recognizer_->CancelRecognition(); | 638 recognizer_->CancelRecognition(); |
594 recognizer_.release(); | 639 recognizer_.release(); |
595 } | 640 } |
596 } | 641 } |
597 | 642 |
598 void ExtensionSpeechInputManager::StopSucceededOnUIThread() { | 643 void SpeechInputExtensionManager::StopSucceededOnUIThread() { |
599 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 644 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
600 VLOG(1) << "Stop succeeded (UI thread)"; | 645 VLOG(1) << "Stop succeeded (UI thread)"; |
601 | 646 |
602 base::AutoLock auto_lock(state_lock_); | 647 base::AutoLock auto_lock(state_lock_); |
603 if (state_ == kShutdown) | 648 if (state_ == kShutdown) |
604 return; | 649 return; |
605 | 650 |
606 std::string extension_id = extension_id_in_use_; | 651 std::string extension_id = extension_id_in_use_; |
607 ResetToIdleState(); | 652 ResetToIdleState(); |
608 | 653 |
| 654 DCHECK(notification_.get()); |
| 655 notification_->Hide(); |
| 656 |
609 content::NotificationService::current()->Notify( | 657 content::NotificationService::current()->Notify( |
610 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED, | 658 chrome::NOTIFICATION_EXTENSION_SPEECH_INPUT_RECORDING_STOPPED, |
611 // Guarded by the state_ == kShutdown check. | 659 // Guarded by the state_ == kShutdown check. |
612 content::Source<Profile>(profile_), | 660 content::Source<Profile>(profile_), |
613 content::Details<std::string>(&extension_id)); | 661 content::Details<std::string>(&extension_id)); |
614 } | 662 } |
| 663 |
| 664 void SpeechInputExtensionManager::SetInputVolume(int caller_id, |
| 665 float volume, |
| 666 float noise_volume) { |
| 667 DCHECK_EQ(caller_id, kSpeechCallerId); |
| 668 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 669 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 670 base::Bind(&SpeechInputExtensionManager::SetInputVolumeOnUIThread, |
| 671 this, volume)); |
| 672 } |
| 673 |
| 674 void SpeechInputExtensionManager::SetInputVolumeOnUIThread( |
| 675 float volume) { |
| 676 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 677 DCHECK(notification_.get()); |
| 678 notification_->SetVUMeterVolume(volume); |
| 679 } |
OLD | NEW |