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/renderer/speech_recognition_dispatcher.h" 6 7 #include "base/basictypes.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "content/common/speech_recognition_messages.h" 10 #include "content/renderer/render_view_impl.h" 11 #include "third_party/WebKit/public/platform/WebString.h" 12 #include "third_party/WebKit/public/platform/WebVector.h" 13 #include "third_party/WebKit/public/web/WebSpeechGrammar.h" 14 #include "third_party/WebKit/public/web/WebSpeechRecognitionParams.h" 15 #include "third_party/WebKit/public/web/WebSpeechRecognitionResult.h" 16 #include "third_party/WebKit/public/web/WebSpeechRecognizerClient.h" 17 18 using blink::WebVector; 19 using blink::WebString; 20 using blink::WebSpeechGrammar; 21 using blink::WebSpeechRecognitionHandle; 22 using blink::WebSpeechRecognitionResult; 23 using blink::WebSpeechRecognitionParams; 24 using blink::WebSpeechRecognizerClient; 25 26 namespace content { 27 28 SpeechRecognitionDispatcher::SpeechRecognitionDispatcher( 29 RenderViewImpl* render_view) 30 : RenderViewObserver(render_view), 31 recognizer_client_(NULL), 32 next_id_(1) { 33 } 34 35 SpeechRecognitionDispatcher::~SpeechRecognitionDispatcher() { 36 } 37 38 bool SpeechRecognitionDispatcher::OnMessageReceived( 39 const IPC::Message& message) { 40 bool handled = true; 41 IPC_BEGIN_MESSAGE_MAP(SpeechRecognitionDispatcher, message) 42 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_Started, OnRecognitionStarted) 43 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_AudioStarted, OnAudioStarted) 44 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_SoundStarted, OnSoundStarted) 45 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_SoundEnded, OnSoundEnded) 46 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_AudioEnded, OnAudioEnded) 47 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_ErrorOccurred, OnErrorOccurred) 48 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_Ended, OnRecognitionEnded) 49 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_ResultRetrieved, 50 OnResultsRetrieved) 51 IPC_MESSAGE_UNHANDLED(handled = false) 52 IPC_END_MESSAGE_MAP() 53 return handled; 54 } 55 56 void SpeechRecognitionDispatcher::start( 57 const WebSpeechRecognitionHandle& handle, 58 const WebSpeechRecognitionParams& params, 59 WebSpeechRecognizerClient* recognizer_client) { 60 DCHECK(!recognizer_client_ || recognizer_client_ == recognizer_client); 61 recognizer_client_ = recognizer_client; 62 63 SpeechRecognitionHostMsg_StartRequest_Params msg_params; 64 for (size_t i = 0; i < params.grammars().size(); ++i) { 65 const WebSpeechGrammar& grammar = params.grammars()[i]; 66 msg_params.grammars.push_back( 67 SpeechRecognitionGrammar(grammar.src().spec(), grammar.weight())); 68 } 69 msg_params.language = UTF16ToUTF8(params.language()); 70 msg_params.max_hypotheses = static_cast<uint32>(params.maxAlternatives()); 71 msg_params.continuous = params.continuous(); 72 msg_params.interim_results = params.interimResults(); 73 msg_params.origin_url = params.origin().toString().utf8(); 74 msg_params.render_view_id = routing_id(); 75 msg_params.request_id = GetOrCreateIDForHandle(handle); 76 // The handle mapping will be removed in |OnRecognitionEnd|. 77 Send(new SpeechRecognitionHostMsg_StartRequest(msg_params)); 78 } 79 80 void SpeechRecognitionDispatcher::stop( 81 const WebSpeechRecognitionHandle& handle, 82 WebSpeechRecognizerClient* recognizer_client) { 83 // Ignore a |stop| issued without a matching |start|. 84 if (recognizer_client_ != recognizer_client || !HandleExists(handle)) 85 return; 86 Send(new SpeechRecognitionHostMsg_StopCaptureRequest( 87 routing_id(), GetOrCreateIDForHandle(handle))); 88 } 89 90 void SpeechRecognitionDispatcher::abort( 91 const WebSpeechRecognitionHandle& handle, 92 WebSpeechRecognizerClient* recognizer_client) { 93 // Ignore an |abort| issued without a matching |start|. 94 if (recognizer_client_ != recognizer_client || !HandleExists(handle)) 95 return; 96 Send(new SpeechRecognitionHostMsg_AbortRequest( 97 routing_id(), GetOrCreateIDForHandle(handle))); 98 } 99 100 void SpeechRecognitionDispatcher::OnRecognitionStarted(int request_id) { 101 recognizer_client_->didStart(GetHandleFromID(request_id)); 102 } 103 104 void SpeechRecognitionDispatcher::OnAudioStarted(int request_id) { 105 recognizer_client_->didStartAudio(GetHandleFromID(request_id)); 106 } 107 108 void SpeechRecognitionDispatcher::OnSoundStarted(int request_id) { 109 recognizer_client_->didStartSound(GetHandleFromID(request_id)); 110 } 111 112 void SpeechRecognitionDispatcher::OnSoundEnded(int request_id) { 113 recognizer_client_->didEndSound(GetHandleFromID(request_id)); 114 } 115 116 void SpeechRecognitionDispatcher::OnAudioEnded(int request_id) { 117 recognizer_client_->didEndAudio(GetHandleFromID(request_id)); 118 } 119 120 static WebSpeechRecognizerClient::ErrorCode WebKitErrorCode( 121 SpeechRecognitionErrorCode e) { 122 switch (e) { 123 case SPEECH_RECOGNITION_ERROR_NONE: 124 NOTREACHED(); 125 return WebSpeechRecognizerClient::OtherError; 126 case SPEECH_RECOGNITION_ERROR_ABORTED: 127 return WebSpeechRecognizerClient::AbortedError; 128 case SPEECH_RECOGNITION_ERROR_AUDIO: 129 return WebSpeechRecognizerClient::AudioCaptureError; 130 case SPEECH_RECOGNITION_ERROR_NETWORK: 131 return WebSpeechRecognizerClient::NetworkError; 132 case SPEECH_RECOGNITION_ERROR_NOT_ALLOWED: 133 return WebSpeechRecognizerClient::NotAllowedError; 134 case SPEECH_RECOGNITION_ERROR_NO_SPEECH: 135 return WebSpeechRecognizerClient::NoSpeechError; 136 case SPEECH_RECOGNITION_ERROR_NO_MATCH: 137 NOTREACHED(); 138 return WebSpeechRecognizerClient::OtherError; 139 case SPEECH_RECOGNITION_ERROR_BAD_GRAMMAR: 140 return WebSpeechRecognizerClient::BadGrammarError; 141 } 142 NOTREACHED(); 143 return WebSpeechRecognizerClient::OtherError; 144 } 145 146 void SpeechRecognitionDispatcher::OnErrorOccurred( 147 int request_id, const SpeechRecognitionError& error) { 148 if (error.code == SPEECH_RECOGNITION_ERROR_NO_MATCH) { 149 recognizer_client_->didReceiveNoMatch(GetHandleFromID(request_id), 150 WebSpeechRecognitionResult()); 151 } else { 152 recognizer_client_->didReceiveError( 153 GetHandleFromID(request_id), 154 WebString(), // TODO(primiano): message? 155 WebKitErrorCode(error.code)); 156 } 157 } 158 159 void SpeechRecognitionDispatcher::OnRecognitionEnded(int request_id) { 160 // TODO(tommi): It is possible that the handle isn't found in the array if 161 // the user just refreshed the page. It seems that we then get a notification 162 // for the previously loaded instance of the page. 163 HandleMap::iterator iter = handle_map_.find(request_id); 164 if (iter == handle_map_.end()) { 165 DLOG(ERROR) << "OnRecognitionEnded called for a handle that doesn't exist"; 166 } else { 167 WebSpeechRecognitionHandle handle = iter->second; 168 // Note: we need to erase the handle from the map *before* calling didEnd. 169 // didEnd may call back synchronously to start a new recognition session, 170 // and we don't want to delete the handle from the map after that happens. 171 handle_map_.erase(request_id); 172 recognizer_client_->didEnd(handle); 173 } 174 } 175 176 void SpeechRecognitionDispatcher::OnResultsRetrieved( 177 int request_id, const SpeechRecognitionResults& results) { 178 size_t provisional_count = 0; 179 SpeechRecognitionResults::const_iterator it = results.begin(); 180 for (; it != results.end(); ++it) { 181 if (it->is_provisional) 182 ++provisional_count; 183 } 184 185 WebVector<WebSpeechRecognitionResult> provisional(provisional_count); 186 WebVector<WebSpeechRecognitionResult> final( 187 results.size() - provisional_count); 188 189 int provisional_index = 0, final_index = 0; 190 for (it = results.begin(); it != results.end(); ++it) { 191 const SpeechRecognitionResult& result = (*it); 192 WebSpeechRecognitionResult* webkit_result = result.is_provisional ? 193 &provisional[provisional_index++] : &final[final_index++]; 194 195 const size_t num_hypotheses = result.hypotheses.size(); 196 WebVector<WebString> transcripts(num_hypotheses); 197 WebVector<float> confidences(num_hypotheses); 198 for (size_t i = 0; i < num_hypotheses; ++i) { 199 transcripts[i] = result.hypotheses[i].utterance; 200 confidences[i] = static_cast<float>(result.hypotheses[i].confidence); 201 } 202 webkit_result->assign(transcripts, confidences, !result.is_provisional); 203 } 204 205 recognizer_client_->didReceiveResults( 206 GetHandleFromID(request_id), final, provisional); 207 } 208 209 210 int SpeechRecognitionDispatcher::GetOrCreateIDForHandle( 211 const WebSpeechRecognitionHandle& handle) { 212 // Search first for an existing mapping. 213 for (HandleMap::iterator iter = handle_map_.begin(); 214 iter != handle_map_.end(); 215 ++iter) { 216 if (iter->second.equals(handle)) 217 return iter->first; 218 } 219 // If no existing mapping found, create a new one. 220 const int new_id = next_id_; 221 handle_map_[new_id] = handle; 222 ++next_id_; 223 return new_id; 224 } 225 226 bool SpeechRecognitionDispatcher::HandleExists( 227 const WebSpeechRecognitionHandle& handle) { 228 for (HandleMap::iterator iter = handle_map_.begin(); 229 iter != handle_map_.end(); 230 ++iter) { 231 if (iter->second.equals(handle)) 232 return true; 233 } 234 return false; 235 } 236 237 const WebSpeechRecognitionHandle& SpeechRecognitionDispatcher::GetHandleFromID( 238 int request_id) { 239 HandleMap::iterator iter = handle_map_.find(request_id); 240 DCHECK(iter != handle_map_.end()); 241 return iter->second; 242 } 243 244 } // namespace content 245