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.
5 #include "content/browser/speech/input_tag_speech_dispatcher_host.h"
8 #include "base/lazy_instance.h"
9 #include "content/browser/browser_plugin/browser_plugin_guest.h"
10 #include "content/browser/renderer_host/render_view_host_impl.h"
11 #include "content/browser/speech/speech_recognition_manager_impl.h"
12 #include "content/browser/web_contents/web_contents_impl.h"
13 #include "content/common/speech_recognition_messages.h"
14 #include "content/public/browser/speech_recognition_manager_delegate.h"
15 #include "content/public/browser/speech_recognition_session_config.h"
16 #include "content/public/browser/speech_recognition_session_context.h"
19 const uint32 kMaxHypothesesForSpeechInputTag = 6;
24 InputTagSpeechDispatcherHost::InputTagSpeechDispatcherHost(
26 int render_process_id,
27 net::URLRequestContextGetter* url_request_context_getter)
28 : is_guest_(is_guest),
29 render_process_id_(render_process_id),
30 url_request_context_getter_(url_request_context_getter) {
31 // Do not add any non-trivial initialization here, instead do it lazily when
32 // required (e.g. see the method |SpeechRecognitionManager::GetInstance()|) or
33 // add an Init() method.
36 InputTagSpeechDispatcherHost::~InputTagSpeechDispatcherHost() {
37 SpeechRecognitionManager::GetInstance()->AbortAllSessionsForListener(this);
40 bool InputTagSpeechDispatcherHost::OnMessageReceived(
41 const IPC::Message& message, bool* message_was_ok) {
43 IPC_BEGIN_MESSAGE_MAP_EX(InputTagSpeechDispatcherHost, message,
45 IPC_MESSAGE_HANDLER(InputTagSpeechHostMsg_StartRecognition,
47 IPC_MESSAGE_HANDLER(InputTagSpeechHostMsg_CancelRecognition,
49 IPC_MESSAGE_HANDLER(InputTagSpeechHostMsg_StopRecording,
51 IPC_MESSAGE_UNHANDLED(handled = false)
56 void InputTagSpeechDispatcherHost::OverrideThreadForMessage(
57 const IPC::Message& message,
58 BrowserThread::ID* thread) {
59 if (message.type() == InputTagSpeechHostMsg_StartRecognition::ID)
60 *thread = BrowserThread::UI;
63 void InputTagSpeechDispatcherHost::OnStartRecognition(
64 const InputTagSpeechHostMsg_StartRecognition_Params& params) {
65 InputTagSpeechHostMsg_StartRecognition_Params input_params(params);
66 int render_process_id = render_process_id_;
67 // The chrome layer is mostly oblivious to BrowserPlugin guests and so it
68 // cannot correctly place the speech bubble relative to a guest. Thus, we
69 // set up the speech recognition context relative to the embedder.
70 int guest_render_view_id = MSG_ROUTING_NONE;
72 RenderViewHostImpl* render_view_host =
73 RenderViewHostImpl::FromID(render_process_id_, params.render_view_id);
74 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
75 WebContents::FromRenderViewHost(render_view_host));
76 BrowserPluginGuest* guest = web_contents->GetBrowserPluginGuest();
77 input_params.element_rect.set_origin(
78 guest->GetScreenCoordinates(input_params.element_rect.origin()));
79 guest_render_view_id = params.render_view_id;
81 guest->embedder_web_contents()->GetRenderProcessHost()->GetID();
82 input_params.render_view_id =
83 guest->embedder_web_contents()->GetRoutingID();
85 bool filter_profanities =
86 SpeechRecognitionManagerImpl::GetInstance() &&
87 SpeechRecognitionManagerImpl::GetInstance()->delegate() &&
88 SpeechRecognitionManagerImpl::GetInstance()->delegate()->
89 FilterProfanities(render_process_id_);
91 BrowserThread::PostTask(
92 BrowserThread::IO, FROM_HERE,
94 &InputTagSpeechDispatcherHost::StartRecognitionOnIO,
102 void InputTagSpeechDispatcherHost::StartRecognitionOnIO(
103 int render_process_id,
104 int guest_render_view_id,
105 const InputTagSpeechHostMsg_StartRecognition_Params& params,
106 bool filter_profanities) {
107 SpeechRecognitionSessionContext context;
108 context.render_process_id = render_process_id;
109 context.render_view_id = params.render_view_id;
110 context.guest_render_view_id = guest_render_view_id;
111 // Keep context.embedder_render_process_id and context.embedder_render_view_id
113 context.request_id = params.request_id;
114 context.element_rect = params.element_rect;
116 SpeechRecognitionSessionConfig config;
117 config.language = params.language;
118 if (!params.grammar.empty()) {
119 config.grammars.push_back(SpeechRecognitionGrammar(params.grammar));
121 config.max_hypotheses = kMaxHypothesesForSpeechInputTag;
122 config.origin_url = params.origin_url;
123 config.initial_context = context;
124 config.url_request_context_getter = url_request_context_getter_.get();
125 config.filter_profanities = filter_profanities;
126 config.event_listener = this;
128 int session_id = SpeechRecognitionManager::GetInstance()->CreateSession(
130 DCHECK_NE(session_id, SpeechRecognitionManager::kSessionIDInvalid);
131 SpeechRecognitionManager::GetInstance()->StartSession(session_id);
134 void InputTagSpeechDispatcherHost::OnCancelRecognition(int render_view_id,
136 int session_id = SpeechRecognitionManager::GetInstance()->GetSession(
137 render_process_id_, render_view_id, request_id);
139 // The renderer might provide an invalid |request_id| if the session was not
140 // started as expected, e.g., due to unsatisfied security requirements.
141 if (session_id != SpeechRecognitionManager::kSessionIDInvalid)
142 SpeechRecognitionManager::GetInstance()->AbortSession(session_id);
145 void InputTagSpeechDispatcherHost::OnStopRecording(int render_view_id,
147 int session_id = SpeechRecognitionManager::GetInstance()->GetSession(
148 render_process_id_, render_view_id, request_id);
150 // The renderer might provide an invalid |request_id| if the session was not
151 // started as expected, e.g., due to unsatisfied security requirements.
152 if (session_id != SpeechRecognitionManager::kSessionIDInvalid) {
153 SpeechRecognitionManager::GetInstance()->StopAudioCaptureForSession(
158 // -------- SpeechRecognitionEventListener interface implementation -----------
159 void InputTagSpeechDispatcherHost::OnRecognitionResults(
161 const SpeechRecognitionResults& results) {
162 DVLOG(1) << "InputTagSpeechDispatcherHost::OnRecognitionResults enter";
164 const SpeechRecognitionSessionContext& context =
165 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
168 context.guest_render_view_id == MSG_ROUTING_NONE ?
169 context.render_view_id : context.guest_render_view_id;
170 Send(new InputTagSpeechMsg_SetRecognitionResults(
174 DVLOG(1) << "InputTagSpeechDispatcherHost::OnRecognitionResults exit";
177 void InputTagSpeechDispatcherHost::OnAudioEnd(int session_id) {
178 DVLOG(1) << "InputTagSpeechDispatcherHost::OnAudioEnd enter";
180 const SpeechRecognitionSessionContext& context =
181 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
183 context.guest_render_view_id == MSG_ROUTING_NONE ?
184 context.render_view_id : context.guest_render_view_id;
185 Send(new InputTagSpeechMsg_RecordingComplete(render_view_id,
186 context.request_id));
187 DVLOG(1) << "InputTagSpeechDispatcherHost::OnAudioEnd exit";
190 void InputTagSpeechDispatcherHost::OnRecognitionEnd(int session_id) {
191 DVLOG(1) << "InputTagSpeechDispatcherHost::OnRecognitionEnd enter";
192 const SpeechRecognitionSessionContext& context =
193 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
195 context.guest_render_view_id == MSG_ROUTING_NONE ?
196 context.render_view_id : context.guest_render_view_id;
197 Send(new InputTagSpeechMsg_RecognitionComplete(render_view_id,
198 context.request_id));
199 DVLOG(1) << "InputTagSpeechDispatcherHost::OnRecognitionEnd exit";
202 // The events below are currently not used by x-webkit-speech implementation.
203 void InputTagSpeechDispatcherHost::OnRecognitionStart(int session_id) {}
204 void InputTagSpeechDispatcherHost::OnAudioStart(int session_id) {}
205 void InputTagSpeechDispatcherHost::OnSoundStart(int session_id) {}
206 void InputTagSpeechDispatcherHost::OnSoundEnd(int session_id) {}
207 void InputTagSpeechDispatcherHost::OnRecognitionError(
209 const SpeechRecognitionError& error) {}
210 void InputTagSpeechDispatcherHost::OnAudioLevelsChange(
211 int session_id, float volume, float noise_volume) {}
212 void InputTagSpeechDispatcherHost::OnEnvironmentEstimationComplete(
215 } // namespace content