| 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 |