blob: 79f082961ae70f1de3ba293886cd6de4c8567ec3 [file] [log] [blame]
[email protected]64d09222012-05-25 10:10:341// 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
avi1023d012015-12-25 02:39:147#include <stddef.h>
8#include <stdint.h>
dcheng07945f632015-12-26 07:59:329#include <utility>
avi1023d012015-12-25 02:39:1410
[email protected]74ebfb12013-06-07 20:48:0011#include "base/strings/utf_string_conversions.h"
[email protected]64d09222012-05-25 10:10:3412#include "content/common/speech_recognition_messages.h"
13#include "content/renderer/render_view_impl.h"
[email protected]5c30b5e02013-05-30 03:46:0814#include "third_party/WebKit/public/platform/WebString.h"
15#include "third_party/WebKit/public/platform/WebVector.h"
[email protected]2255a9332013-06-17 05:12:3116#include "third_party/WebKit/public/web/WebSpeechGrammar.h"
17#include "third_party/WebKit/public/web/WebSpeechRecognitionParams.h"
18#include "third_party/WebKit/public/web/WebSpeechRecognitionResult.h"
19#include "third_party/WebKit/public/web/WebSpeechRecognizerClient.h"
[email protected]64d09222012-05-25 10:10:3420
[email protected]180ef242013-11-07 06:50:4621using blink::WebVector;
22using blink::WebString;
23using blink::WebSpeechGrammar;
24using blink::WebSpeechRecognitionHandle;
25using blink::WebSpeechRecognitionResult;
26using blink::WebSpeechRecognitionParams;
27using blink::WebSpeechRecognizerClient;
[email protected]64d09222012-05-25 10:10:3428
[email protected]e9ff79c2012-10-19 21:31:2629namespace content {
30
[email protected]64d09222012-05-25 10:10:3431SpeechRecognitionDispatcher::SpeechRecognitionDispatcher(
32 RenderViewImpl* render_view)
[email protected]e9ff79c2012-10-19 21:31:2633 : RenderViewObserver(render_view),
Ivan Kotenkov2c0d2bb32017-11-01 15:41:2834 recognizer_client_(nullptr),
burnik2eeb4662014-10-09 21:30:1635 next_id_(1) {}
[email protected]64d09222012-05-25 10:10:3436
burnik2eeb4662014-10-09 21:30:1637SpeechRecognitionDispatcher::~SpeechRecognitionDispatcher() {}
[email protected]64d09222012-05-25 10:10:3438
[email protected]e976c3c52014-07-24 17:41:5539void SpeechRecognitionDispatcher::AbortAllRecognitions() {
40 Send(new SpeechRecognitionHostMsg_AbortAllRequests(
41 routing_id()));
42}
43
[email protected]64d09222012-05-25 10:10:3444bool SpeechRecognitionDispatcher::OnMessageReceived(
45 const IPC::Message& message) {
46 bool handled = true;
47 IPC_BEGIN_MESSAGE_MAP(SpeechRecognitionDispatcher, message)
48 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_Started, OnRecognitionStarted)
49 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_AudioStarted, OnAudioStarted)
50 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_SoundStarted, OnSoundStarted)
51 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_SoundEnded, OnSoundEnded)
52 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_AudioEnded, OnAudioEnded)
53 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_ErrorOccurred, OnErrorOccurred)
54 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_Ended, OnRecognitionEnded)
[email protected]fc88c1e2012-12-04 09:54:3655 IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_ResultRetrieved,
56 OnResultsRetrieved)
[email protected]64d09222012-05-25 10:10:3457 IPC_MESSAGE_UNHANDLED(handled = false)
58 IPC_END_MESSAGE_MAP()
59 return handled;
60}
61
xjz694b50a92016-06-07 21:49:3762void SpeechRecognitionDispatcher::OnDestruct() {
63 delete this;
64}
65
Blink Reformat1c4d759e2017-04-09 16:34:5466void SpeechRecognitionDispatcher::Start(
[email protected]64d09222012-05-25 10:10:3467 const WebSpeechRecognitionHandle& handle,
68 const WebSpeechRecognitionParams& params,
69 WebSpeechRecognizerClient* recognizer_client) {
[email protected]64d09222012-05-25 10:10:3470 DCHECK(!recognizer_client_ || recognizer_client_ == recognizer_client);
71 recognizer_client_ = recognizer_client;
72
73 SpeechRecognitionHostMsg_StartRequest_Params msg_params;
Blink Reformat1c4d759e2017-04-09 16:34:5474 for (size_t i = 0; i < params.Grammars().size(); ++i) {
75 const WebSpeechGrammar& grammar = params.Grammars()[i];
76 msg_params.grammars.push_back(SpeechRecognitionGrammar(
77 grammar.Src().GetString().Utf8(), grammar.Weight()));
[email protected]64d09222012-05-25 10:10:3478 }
Blink Reformat1c4d759e2017-04-09 16:34:5479 msg_params.language = params.Language().Utf8();
80 msg_params.max_hypotheses = static_cast<uint32_t>(params.MaxAlternatives());
81 msg_params.continuous = params.Continuous();
82 msg_params.interim_results = params.InterimResults();
83 msg_params.origin_url = params.Origin().ToString().Utf8();
[email protected]64d09222012-05-25 10:10:3484 msg_params.render_view_id = routing_id();
[email protected]c766aa92012-06-22 16:57:1485 msg_params.request_id = GetOrCreateIDForHandle(handle);
Max Morin5f93cebd2017-11-06 18:51:4986
[email protected]c766aa92012-06-22 16:57:1487 // The handle mapping will be removed in |OnRecognitionEnd|.
[email protected]64d09222012-05-25 10:10:3488 Send(new SpeechRecognitionHostMsg_StartRequest(msg_params));
89}
90
Blink Reformat1c4d759e2017-04-09 16:34:5491void SpeechRecognitionDispatcher::Stop(
[email protected]64d09222012-05-25 10:10:3492 const WebSpeechRecognitionHandle& handle,
93 WebSpeechRecognizerClient* recognizer_client) {
[email protected]c766aa92012-06-22 16:57:1494 // Ignore a |stop| issued without a matching |start|.
95 if (recognizer_client_ != recognizer_client || !HandleExists(handle))
96 return;
97 Send(new SpeechRecognitionHostMsg_StopCaptureRequest(
98 routing_id(), GetOrCreateIDForHandle(handle)));
[email protected]64d09222012-05-25 10:10:3499}
100
Blink Reformat1c4d759e2017-04-09 16:34:54101void SpeechRecognitionDispatcher::Abort(
[email protected]64d09222012-05-25 10:10:34102 const WebSpeechRecognitionHandle& handle,
103 WebSpeechRecognizerClient* recognizer_client) {
[email protected]c766aa92012-06-22 16:57:14104 // Ignore an |abort| issued without a matching |start|.
105 if (recognizer_client_ != recognizer_client || !HandleExists(handle))
106 return;
107 Send(new SpeechRecognitionHostMsg_AbortRequest(
108 routing_id(), GetOrCreateIDForHandle(handle)));
[email protected]64d09222012-05-25 10:10:34109}
110
111void SpeechRecognitionDispatcher::OnRecognitionStarted(int request_id) {
Blink Reformat1c4d759e2017-04-09 16:34:54112 recognizer_client_->DidStart(GetHandleFromID(request_id));
[email protected]64d09222012-05-25 10:10:34113}
114
115void SpeechRecognitionDispatcher::OnAudioStarted(int request_id) {
Blink Reformat1c4d759e2017-04-09 16:34:54116 recognizer_client_->DidStartAudio(GetHandleFromID(request_id));
[email protected]64d09222012-05-25 10:10:34117}
118
119void SpeechRecognitionDispatcher::OnSoundStarted(int request_id) {
Blink Reformat1c4d759e2017-04-09 16:34:54120 recognizer_client_->DidStartSound(GetHandleFromID(request_id));
[email protected]64d09222012-05-25 10:10:34121}
122
123void SpeechRecognitionDispatcher::OnSoundEnded(int request_id) {
Blink Reformat1c4d759e2017-04-09 16:34:54124 recognizer_client_->DidEndSound(GetHandleFromID(request_id));
[email protected]64d09222012-05-25 10:10:34125}
126
127void SpeechRecognitionDispatcher::OnAudioEnded(int request_id) {
Blink Reformat1c4d759e2017-04-09 16:34:54128 recognizer_client_->DidEndAudio(GetHandleFromID(request_id));
[email protected]64d09222012-05-25 10:10:34129}
130
[email protected]9c4ca672012-08-02 11:32:45131static WebSpeechRecognizerClient::ErrorCode WebKitErrorCode(
[email protected]e9ff79c2012-10-19 21:31:26132 SpeechRecognitionErrorCode e) {
[email protected]9c4ca672012-08-02 11:32:45133 switch (e) {
[email protected]e9ff79c2012-10-19 21:31:26134 case SPEECH_RECOGNITION_ERROR_NONE:
[email protected]9c4ca672012-08-02 11:32:45135 NOTREACHED();
Blink Reformat1c4d759e2017-04-09 16:34:54136 return WebSpeechRecognizerClient::kOtherError;
djmix.kim99db7e02015-04-22 07:23:08137 case SPEECH_RECOGNITION_ERROR_NO_SPEECH:
Blink Reformat1c4d759e2017-04-09 16:34:54138 return WebSpeechRecognizerClient::kNoSpeechError;
[email protected]e9ff79c2012-10-19 21:31:26139 case SPEECH_RECOGNITION_ERROR_ABORTED:
Blink Reformat1c4d759e2017-04-09 16:34:54140 return WebSpeechRecognizerClient::kAbortedError;
djmix.kima8a4009e2015-04-23 07:33:40141 case SPEECH_RECOGNITION_ERROR_AUDIO_CAPTURE:
Blink Reformat1c4d759e2017-04-09 16:34:54142 return WebSpeechRecognizerClient::kAudioCaptureError;
[email protected]e9ff79c2012-10-19 21:31:26143 case SPEECH_RECOGNITION_ERROR_NETWORK:
Blink Reformat1c4d759e2017-04-09 16:34:54144 return WebSpeechRecognizerClient::kNetworkError;
[email protected]e9ff79c2012-10-19 21:31:26145 case SPEECH_RECOGNITION_ERROR_NOT_ALLOWED:
Blink Reformat1c4d759e2017-04-09 16:34:54146 return WebSpeechRecognizerClient::kNotAllowedError;
djmix.kim99db7e02015-04-22 07:23:08147 case SPEECH_RECOGNITION_ERROR_SERVICE_NOT_ALLOWED:
Blink Reformat1c4d759e2017-04-09 16:34:54148 return WebSpeechRecognizerClient::kServiceNotAllowedError;
djmix.kim99db7e02015-04-22 07:23:08149 case SPEECH_RECOGNITION_ERROR_BAD_GRAMMAR:
Blink Reformat1c4d759e2017-04-09 16:34:54150 return WebSpeechRecognizerClient::kBadGrammarError;
djmix.kim99db7e02015-04-22 07:23:08151 case SPEECH_RECOGNITION_ERROR_LANGUAGE_NOT_SUPPORTED:
Blink Reformat1c4d759e2017-04-09 16:34:54152 return WebSpeechRecognizerClient::kLanguageNotSupportedError;
[email protected]e9ff79c2012-10-19 21:31:26153 case SPEECH_RECOGNITION_ERROR_NO_MATCH:
[email protected]9c4ca672012-08-02 11:32:45154 NOTREACHED();
Blink Reformat1c4d759e2017-04-09 16:34:54155 return WebSpeechRecognizerClient::kOtherError;
[email protected]9c4ca672012-08-02 11:32:45156 }
157 NOTREACHED();
Blink Reformat1c4d759e2017-04-09 16:34:54158 return WebSpeechRecognizerClient::kOtherError;
[email protected]9c4ca672012-08-02 11:32:45159}
160
[email protected]64d09222012-05-25 10:10:34161void SpeechRecognitionDispatcher::OnErrorOccurred(
162 int request_id, const SpeechRecognitionError& error) {
[email protected]e9ff79c2012-10-19 21:31:26163 if (error.code == SPEECH_RECOGNITION_ERROR_NO_MATCH) {
Blink Reformat1c4d759e2017-04-09 16:34:54164 recognizer_client_->DidReceiveNoMatch(GetHandleFromID(request_id),
[email protected]64d09222012-05-25 10:10:34165 WebSpeechRecognitionResult());
166 } else {
Blink Reformat1c4d759e2017-04-09 16:34:54167 recognizer_client_->DidReceiveError(
[email protected]0a8d4275e2013-01-04 22:21:26168 GetHandleFromID(request_id),
169 WebString(), // TODO(primiano): message?
170 WebKitErrorCode(error.code));
[email protected]64d09222012-05-25 10:10:34171 }
172}
173
174void SpeechRecognitionDispatcher::OnRecognitionEnded(int request_id) {
[email protected]fc88c1e2012-12-04 09:54:36175 // TODO(tommi): It is possible that the handle isn't found in the array if
176 // the user just refreshed the page. It seems that we then get a notification
177 // for the previously loaded instance of the page.
178 HandleMap::iterator iter = handle_map_.find(request_id);
179 if (iter == handle_map_.end()) {
180 DLOG(ERROR) << "OnRecognitionEnded called for a handle that doesn't exist";
181 } else {
182 WebSpeechRecognitionHandle handle = iter->second;
183 // Note: we need to erase the handle from the map *before* calling didEnd.
184 // didEnd may call back synchronously to start a new recognition session,
185 // and we don't want to delete the handle from the map after that happens.
186 handle_map_.erase(request_id);
Blink Reformat1c4d759e2017-04-09 16:34:54187 recognizer_client_->DidEnd(handle);
[email protected]fc88c1e2012-12-04 09:54:36188 }
[email protected]64d09222012-05-25 10:10:34189}
190
[email protected]fc88c1e2012-12-04 09:54:36191void SpeechRecognitionDispatcher::OnResultsRetrieved(
192 int request_id, const SpeechRecognitionResults& results) {
193 size_t provisional_count = 0;
194 SpeechRecognitionResults::const_iterator it = results.begin();
195 for (; it != results.end(); ++it) {
196 if (it->is_provisional)
197 ++provisional_count;
[email protected]64d09222012-05-25 10:10:34198 }
[email protected]fc88c1e2012-12-04 09:54:36199
200 WebVector<WebSpeechRecognitionResult> provisional(provisional_count);
201 WebVector<WebSpeechRecognitionResult> final(
202 results.size() - provisional_count);
203
204 int provisional_index = 0, final_index = 0;
205 for (it = results.begin(); it != results.end(); ++it) {
206 const SpeechRecognitionResult& result = (*it);
207 WebSpeechRecognitionResult* webkit_result = result.is_provisional ?
208 &provisional[provisional_index++] : &final[final_index++];
209
210 const size_t num_hypotheses = result.hypotheses.size();
211 WebVector<WebString> transcripts(num_hypotheses);
212 WebVector<float> confidences(num_hypotheses);
213 for (size_t i = 0; i < num_hypotheses; ++i) {
Blink Reformat1c4d759e2017-04-09 16:34:54214 transcripts[i] = WebString::FromUTF16(result.hypotheses[i].utterance);
[email protected]fc88c1e2012-12-04 09:54:36215 confidences[i] = static_cast<float>(result.hypotheses[i].confidence);
216 }
Blink Reformat1c4d759e2017-04-09 16:34:54217 webkit_result->Assign(transcripts, confidences, !result.is_provisional);
[email protected]fc88c1e2012-12-04 09:54:36218 }
219
Blink Reformat1c4d759e2017-04-09 16:34:54220 recognizer_client_->DidReceiveResults(GetHandleFromID(request_id), final,
221 provisional);
[email protected]64d09222012-05-25 10:10:34222}
223
[email protected]c766aa92012-06-22 16:57:14224int SpeechRecognitionDispatcher::GetOrCreateIDForHandle(
[email protected]64d09222012-05-25 10:10:34225 const WebSpeechRecognitionHandle& handle) {
226 // Search first for an existing mapping.
227 for (HandleMap::iterator iter = handle_map_.begin();
228 iter != handle_map_.end();
229 ++iter) {
Blink Reformat1c4d759e2017-04-09 16:34:54230 if (iter->second.Equals(handle))
[email protected]64d09222012-05-25 10:10:34231 return iter->first;
232 }
233 // If no existing mapping found, create a new one.
234 const int new_id = next_id_;
235 handle_map_[new_id] = handle;
236 ++next_id_;
237 return new_id;
238}
239
[email protected]c766aa92012-06-22 16:57:14240bool SpeechRecognitionDispatcher::HandleExists(
241 const WebSpeechRecognitionHandle& handle) {
242 for (HandleMap::iterator iter = handle_map_.begin();
243 iter != handle_map_.end();
244 ++iter) {
Blink Reformat1c4d759e2017-04-09 16:34:54245 if (iter->second.Equals(handle))
[email protected]c766aa92012-06-22 16:57:14246 return true;
247 }
248 return false;
249}
250
[email protected]64d09222012-05-25 10:10:34251const WebSpeechRecognitionHandle& SpeechRecognitionDispatcher::GetHandleFromID(
252 int request_id) {
253 HandleMap::iterator iter = handle_map_.find(request_id);
mbarbella324a1692015-05-20 00:31:03254 CHECK(iter != handle_map_.end());
[email protected]64d09222012-05-25 10:10:34255 return iter->second;
256}
[email protected]e9ff79c2012-10-19 21:31:26257
258} // namespace content