OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/browser/speech/speech_input_dispatcher_host.h" | |
6 | |
7 #include "base/lazy_instance.h" | |
8 #include "content/browser/speech/speech_input_manager_impl.h" | |
9 #include "content/browser/speech/speech_recognizer_impl.h" | |
10 #include "content/common/speech_input_messages.h" | |
11 #include "content/public/browser/speech_input_preferences.h" | |
12 | |
13 using content::BrowserThread; | |
14 | |
15 namespace speech_input { | |
16 | |
17 //----------------------------- SpeechInputCallers ----------------------------- | |
18 | |
19 // A singleton class to map the tuple | |
20 // (render-process-id, render-view-id, requestid) to a single ID which is passed | |
21 // through rest of the speech code. | |
22 class SpeechInputDispatcherHost::SpeechInputCallers { | |
23 public: | |
24 // Creates a new ID for a given tuple. | |
25 int CreateId(int render_process_id, int render_view_id, int request_id); | |
26 | |
27 // Returns the ID for a tuple assuming the ID was created earlier. | |
28 int GetId(int render_process_id, int render_view_id, int request_id); | |
29 | |
30 // Removes the ID and associated tuple from the map. | |
31 void RemoveId(int id); | |
32 | |
33 // Getters for the various tuple elements for the given ID. | |
34 int render_process_id(int id); | |
35 int render_view_id(int id); | |
36 int request_id(int id); | |
37 | |
38 private: | |
39 struct CallerInfo { | |
40 int render_process_id; | |
41 int render_view_id; | |
42 int request_id; | |
43 }; | |
44 friend struct base::DefaultLazyInstanceTraits<SpeechInputCallers>; | |
45 | |
46 SpeechInputCallers(); | |
47 | |
48 std::map<int, CallerInfo> callers_; | |
49 int next_id_; | |
50 }; | |
51 | |
52 static base::LazyInstance<SpeechInputDispatcherHost::SpeechInputCallers> | |
53 g_speech_input_callers = LAZY_INSTANCE_INITIALIZER; | |
54 | |
55 SpeechInputDispatcherHost::SpeechInputCallers::SpeechInputCallers() | |
56 : next_id_(1) { | |
57 } | |
58 | |
59 int SpeechInputDispatcherHost::SpeechInputCallers::GetId(int render_process_id, | |
60 int render_view_id, | |
61 int request_id) { | |
62 for (std::map<int, CallerInfo>::iterator it = callers_.begin(); | |
63 it != callers_.end(); it++) { | |
64 const CallerInfo& item = it->second; | |
65 if (item.render_process_id == render_process_id && | |
66 item.render_view_id == render_view_id && | |
67 item.request_id == request_id) { | |
68 return it->first; | |
69 } | |
70 } | |
71 | |
72 // Not finding an entry here is valid since a cancel/stop may have been issued | |
73 // by the renderer and before it received our response the user may have | |
74 // clicked the button to stop again. The caller of this method should take | |
75 // care of this case. | |
76 return 0; | |
77 } | |
78 | |
79 int SpeechInputDispatcherHost::SpeechInputCallers::CreateId( | |
80 int render_process_id, | |
81 int render_view_id, | |
82 int request_id) { | |
83 CallerInfo info; | |
84 info.render_process_id = render_process_id; | |
85 info.render_view_id = render_view_id; | |
86 info.request_id = request_id; | |
87 callers_[next_id_] = info; | |
88 return next_id_++; | |
89 } | |
90 | |
91 void SpeechInputDispatcherHost::SpeechInputCallers::RemoveId(int id) { | |
92 callers_.erase(id); | |
93 } | |
94 | |
95 int SpeechInputDispatcherHost::SpeechInputCallers::render_process_id(int id) { | |
96 return callers_[id].render_process_id; | |
97 } | |
98 | |
99 int SpeechInputDispatcherHost::SpeechInputCallers::render_view_id(int id) { | |
100 return callers_[id].render_view_id; | |
101 } | |
102 | |
103 int SpeechInputDispatcherHost::SpeechInputCallers::request_id(int id) { | |
104 return callers_[id].request_id; | |
105 } | |
106 | |
107 //-------------------------- SpeechInputDispatcherHost ------------------------- | |
108 | |
109 SpeechInputManagerImpl* SpeechInputDispatcherHost::manager_; | |
110 | |
111 void SpeechInputDispatcherHost::set_manager(SpeechInputManagerImpl* manager) { | |
112 manager_ = manager; | |
113 } | |
114 | |
115 SpeechInputDispatcherHost::SpeechInputDispatcherHost( | |
116 int render_process_id, | |
117 net::URLRequestContextGetter* context_getter, | |
118 content::SpeechInputPreferences* speech_input_preferences, | |
119 AudioManager* audio_manager) | |
120 : render_process_id_(render_process_id), | |
121 may_have_pending_requests_(false), | |
122 context_getter_(context_getter), | |
123 speech_input_preferences_(speech_input_preferences), | |
124 audio_manager_(audio_manager) { | |
125 // This is initialized by Browser. Do not add any non-trivial | |
126 // initialization here, instead do it lazily when required (e.g. see the | |
127 // method |manager()|) or add an Init() method. | |
128 } | |
129 | |
130 SpeechInputDispatcherHost::~SpeechInputDispatcherHost() { | |
131 // If the renderer crashed for some reason or if we didn't receive a proper | |
132 // Cancel/Stop call for an existing session, cancel such active sessions now. | |
133 // We first check if this dispatcher received any speech IPC requst so that | |
134 // we don't end up creating the speech input manager for web pages which don't | |
135 // use speech input. | |
136 if (may_have_pending_requests_) | |
137 manager()->CancelAllRequestsWithDelegate(this); | |
138 } | |
139 | |
140 SpeechInputManagerImpl* SpeechInputDispatcherHost::manager() { | |
141 if (manager_) | |
142 return manager_; | |
143 #if defined(ENABLE_INPUT_SPEECH) | |
144 return SpeechInputManagerImpl::GetInstance(); | |
145 #else | |
146 return NULL; | |
147 #endif | |
148 } | |
149 | |
150 bool SpeechInputDispatcherHost::OnMessageReceived( | |
151 const IPC::Message& message, bool* message_was_ok) { | |
152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
153 bool handled = true; | |
154 IPC_BEGIN_MESSAGE_MAP_EX(SpeechInputDispatcherHost, message, | |
155 *message_was_ok) | |
156 IPC_MESSAGE_HANDLER(SpeechInputHostMsg_StartRecognition, | |
157 OnStartRecognition) | |
158 IPC_MESSAGE_HANDLER(SpeechInputHostMsg_CancelRecognition, | |
159 OnCancelRecognition) | |
160 IPC_MESSAGE_HANDLER(SpeechInputHostMsg_StopRecording, | |
161 OnStopRecording) | |
162 IPC_MESSAGE_UNHANDLED(handled = false) | |
163 IPC_END_MESSAGE_MAP() | |
164 if (handled) | |
165 may_have_pending_requests_ = true; | |
166 return handled; | |
167 } | |
168 | |
169 void SpeechInputDispatcherHost::OnStartRecognition( | |
170 const SpeechInputHostMsg_StartRecognition_Params ¶ms) { | |
171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
172 int caller_id = g_speech_input_callers.Get().CreateId( | |
173 render_process_id_, params.render_view_id, params.request_id); | |
174 manager()->StartRecognition(this, caller_id, | |
175 render_process_id_, | |
176 params.render_view_id, params.element_rect, | |
177 params.language, params.grammar, | |
178 params.origin_url, | |
179 context_getter_.get(), | |
180 speech_input_preferences_.get()); | |
181 } | |
182 | |
183 void SpeechInputDispatcherHost::OnCancelRecognition(int render_view_id, | |
184 int request_id) { | |
185 int caller_id = g_speech_input_callers.Get().GetId( | |
186 render_process_id_, render_view_id, request_id); | |
187 if (caller_id) { | |
188 manager()->CancelRecognition(caller_id); | |
189 // Request sequence ended so remove mapping. | |
190 g_speech_input_callers.Get().RemoveId(caller_id); | |
191 } | |
192 } | |
193 | |
194 void SpeechInputDispatcherHost::OnStopRecording(int render_view_id, | |
195 int request_id) { | |
196 int caller_id = g_speech_input_callers.Get().GetId( | |
197 render_process_id_, render_view_id, request_id); | |
198 if (caller_id) | |
199 manager()->StopRecording(caller_id); | |
200 } | |
201 | |
202 void SpeechInputDispatcherHost::SetRecognitionResult( | |
203 int caller_id, const content::SpeechInputResult& result) { | |
204 VLOG(1) << "SpeechInputDispatcherHost::SetRecognitionResult enter"; | |
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
206 int caller_render_view_id = | |
207 g_speech_input_callers.Get().render_view_id(caller_id); | |
208 int caller_request_id = g_speech_input_callers.Get().request_id(caller_id); | |
209 Send(new SpeechInputMsg_SetRecognitionResult(caller_render_view_id, | |
210 caller_request_id, | |
211 result)); | |
212 VLOG(1) << "SpeechInputDispatcherHost::SetRecognitionResult exit"; | |
213 } | |
214 | |
215 void SpeechInputDispatcherHost::DidCompleteRecording(int caller_id) { | |
216 VLOG(1) << "SpeechInputDispatcherHost::DidCompleteRecording enter"; | |
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
218 int caller_render_view_id = | |
219 g_speech_input_callers.Get().render_view_id(caller_id); | |
220 int caller_request_id = g_speech_input_callers.Get().request_id(caller_id); | |
221 Send(new SpeechInputMsg_RecordingComplete(caller_render_view_id, | |
222 caller_request_id)); | |
223 VLOG(1) << "SpeechInputDispatcherHost::DidCompleteRecording exit"; | |
224 } | |
225 | |
226 void SpeechInputDispatcherHost::DidCompleteRecognition(int caller_id) { | |
227 VLOG(1) << "SpeechInputDispatcherHost::DidCompleteRecognition enter"; | |
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
229 int caller_render_view_id = | |
230 g_speech_input_callers.Get().render_view_id(caller_id); | |
231 int caller_request_id = g_speech_input_callers.Get().request_id(caller_id); | |
232 Send(new SpeechInputMsg_RecognitionComplete(caller_render_view_id, | |
233 caller_request_id)); | |
234 // Request sequence ended, so remove mapping. | |
235 g_speech_input_callers.Get().RemoveId(caller_id); | |
236 VLOG(1) << "SpeechInputDispatcherHost::DidCompleteRecognition exit"; | |
237 } | |
238 | |
239 } // namespace speech_input | |
OLD | NEW |