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/speech_recognition_dispatcher_host.h"
8 #include "base/command_line.h"
9 #include "base/lazy_instance.h"
10 #include "content/browser/browser_plugin/browser_plugin_guest.h"
11 #include "content/browser/child_process_security_policy_impl.h"
12 #include "content/browser/renderer_host/render_view_host_impl.h"
13 #include "content/browser/speech/speech_recognition_manager_impl.h"
14 #include "content/browser/web_contents/web_contents_impl.h"
15 #include "content/common/speech_recognition_messages.h"
16 #include "content/public/browser/speech_recognition_manager_delegate.h"
17 #include "content/public/browser/speech_recognition_session_config.h"
18 #include "content/public/browser/speech_recognition_session_context.h"
19 #include "content/public/common/content_switches.h"
23 SpeechRecognitionDispatcherHost::SpeechRecognitionDispatcherHost(
24 int render_process_id,
25 net::URLRequestContextGetter* context_getter)
26 : BrowserMessageFilter(SpeechRecognitionMsgStart),
27 render_process_id_(render_process_id),
28 context_getter_(context_getter),
30 // Do not add any non-trivial initialization here, instead do it lazily when
31 // required (e.g. see the method |SpeechRecognitionManager::GetInstance()|) or
32 // add an Init() method.
35 SpeechRecognitionDispatcherHost::~SpeechRecognitionDispatcherHost() {
36 SpeechRecognitionManager::GetInstance()->AbortAllSessionsForRenderProcess(
40 base::WeakPtr<SpeechRecognitionDispatcherHost>
41 SpeechRecognitionDispatcherHost::AsWeakPtr() {
42 return weak_factory_.GetWeakPtr();
45 bool SpeechRecognitionDispatcherHost::OnMessageReceived(
46 const IPC::Message& message) {
48 IPC_BEGIN_MESSAGE_MAP(SpeechRecognitionDispatcherHost, message)
49 IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_StartRequest,
51 IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_AbortRequest,
53 IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_StopCaptureRequest,
55 IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_AbortAllRequests,
57 IPC_MESSAGE_UNHANDLED(handled = false)
62 void SpeechRecognitionDispatcherHost::OverrideThreadForMessage(
63 const IPC::Message& message,
64 BrowserThread::ID* thread) {
65 if (message.type() == SpeechRecognitionHostMsg_StartRequest::ID)
66 *thread = BrowserThread::UI;
69 void SpeechRecognitionDispatcherHost::OnChannelClosing() {
70 weak_factory_.InvalidateWeakPtrs();
73 void SpeechRecognitionDispatcherHost::OnStartRequest(
74 const SpeechRecognitionHostMsg_StartRequest_Params& params) {
75 SpeechRecognitionHostMsg_StartRequest_Params input_params(params);
77 // Check that the origin specified by the renderer process is one
78 // that it is allowed to access.
79 if (params.origin_url != "null" &&
80 !ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
81 render_process_id_, GURL(params.origin_url))) {
82 LOG(ERROR) << "SRDH::OnStartRequest, disallowed origin: "
87 int embedder_render_process_id = 0;
88 int embedder_render_view_id = MSG_ROUTING_NONE;
89 RenderViewHostImpl* render_view_host =
90 RenderViewHostImpl::FromID(render_process_id_, params.render_view_id);
91 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
92 WebContents::FromRenderViewHost(render_view_host));
93 BrowserPluginGuest* guest = web_contents->GetBrowserPluginGuest();
95 // If the speech API request was from a guest, save the context of the
96 // embedder since we will use it to decide permission.
97 embedder_render_process_id =
98 guest->embedder_web_contents()->GetRenderProcessHost()->GetID();
99 DCHECK_NE(embedder_render_process_id, 0);
100 embedder_render_view_id =
101 guest->embedder_web_contents()->GetRenderViewHost()->GetRoutingID();
102 DCHECK_NE(embedder_render_view_id, MSG_ROUTING_NONE);
105 // TODO(lazyboy): Check if filter_profanities should use |render_process_id|
106 // instead of |render_process_id_|.
107 bool filter_profanities =
108 SpeechRecognitionManagerImpl::GetInstance() &&
109 SpeechRecognitionManagerImpl::GetInstance()->delegate() &&
110 SpeechRecognitionManagerImpl::GetInstance()->delegate()->
111 FilterProfanities(render_process_id_);
113 BrowserThread::PostTask(
116 base::Bind(&SpeechRecognitionDispatcherHost::OnStartRequestOnIO,
118 embedder_render_process_id,
119 embedder_render_view_id,
121 filter_profanities));
124 void SpeechRecognitionDispatcherHost::OnStartRequestOnIO(
125 int embedder_render_process_id,
126 int embedder_render_view_id,
127 const SpeechRecognitionHostMsg_StartRequest_Params& params,
128 bool filter_profanities) {
129 SpeechRecognitionSessionContext context;
130 context.context_name = params.origin_url;
131 context.render_process_id = render_process_id_;
132 context.render_view_id = params.render_view_id;
133 context.embedder_render_process_id = embedder_render_process_id;
134 context.embedder_render_view_id = embedder_render_view_id;
135 if (embedder_render_process_id)
136 context.guest_render_view_id = params.render_view_id;
137 context.request_id = params.request_id;
139 SpeechRecognitionSessionConfig config;
140 config.is_legacy_api = false;
141 config.language = params.language;
142 config.grammars = params.grammars;
143 config.max_hypotheses = params.max_hypotheses;
144 config.origin_url = params.origin_url;
145 config.initial_context = context;
146 config.url_request_context_getter = context_getter_.get();
147 config.filter_profanities = filter_profanities;
148 config.continuous = params.continuous;
149 config.interim_results = params.interim_results;
150 config.event_listener = AsWeakPtr();
152 int session_id = SpeechRecognitionManager::GetInstance()->CreateSession(
154 DCHECK_NE(session_id, SpeechRecognitionManager::kSessionIDInvalid);
155 SpeechRecognitionManager::GetInstance()->StartSession(session_id);
158 void SpeechRecognitionDispatcherHost::OnAbortRequest(int render_view_id,
160 int session_id = SpeechRecognitionManager::GetInstance()->GetSession(
161 render_process_id_, render_view_id, request_id);
163 // The renderer might provide an invalid |request_id| if the session was not
164 // started as expected, e.g., due to unsatisfied security requirements.
165 if (session_id != SpeechRecognitionManager::kSessionIDInvalid)
166 SpeechRecognitionManager::GetInstance()->AbortSession(session_id);
169 void SpeechRecognitionDispatcherHost::OnAbortAllRequests(int render_view_id) {
170 SpeechRecognitionManager::GetInstance()->AbortAllSessionsForRenderView(
171 render_process_id_, render_view_id);
174 void SpeechRecognitionDispatcherHost::OnStopCaptureRequest(
175 int render_view_id, int request_id) {
176 int session_id = SpeechRecognitionManager::GetInstance()->GetSession(
177 render_process_id_, render_view_id, request_id);
179 // The renderer might provide an invalid |request_id| if the session was not
180 // started as expected, e.g., due to unsatisfied security requirements.
181 if (session_id != SpeechRecognitionManager::kSessionIDInvalid) {
182 SpeechRecognitionManager::GetInstance()->StopAudioCaptureForSession(
187 // -------- SpeechRecognitionEventListener interface implementation -----------
189 void SpeechRecognitionDispatcherHost::OnRecognitionStart(int session_id) {
190 const SpeechRecognitionSessionContext& context =
191 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
192 Send(new SpeechRecognitionMsg_Started(context.render_view_id,
193 context.request_id));
196 void SpeechRecognitionDispatcherHost::OnAudioStart(int session_id) {
197 const SpeechRecognitionSessionContext& context =
198 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
199 Send(new SpeechRecognitionMsg_AudioStarted(context.render_view_id,
200 context.request_id));
203 void SpeechRecognitionDispatcherHost::OnSoundStart(int session_id) {
204 const SpeechRecognitionSessionContext& context =
205 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
206 Send(new SpeechRecognitionMsg_SoundStarted(context.render_view_id,
207 context.request_id));
210 void SpeechRecognitionDispatcherHost::OnSoundEnd(int session_id) {
211 const SpeechRecognitionSessionContext& context =
212 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
213 Send(new SpeechRecognitionMsg_SoundEnded(context.render_view_id,
214 context.request_id));
217 void SpeechRecognitionDispatcherHost::OnAudioEnd(int session_id) {
218 const SpeechRecognitionSessionContext& context =
219 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
220 Send(new SpeechRecognitionMsg_AudioEnded(context.render_view_id,
221 context.request_id));
224 void SpeechRecognitionDispatcherHost::OnRecognitionEnd(int session_id) {
225 const SpeechRecognitionSessionContext& context =
226 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
227 Send(new SpeechRecognitionMsg_Ended(context.render_view_id,
228 context.request_id));
231 void SpeechRecognitionDispatcherHost::OnRecognitionResults(
233 const SpeechRecognitionResults& results) {
234 const SpeechRecognitionSessionContext& context =
235 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
236 Send(new SpeechRecognitionMsg_ResultRetrieved(context.render_view_id,
241 void SpeechRecognitionDispatcherHost::OnRecognitionError(
243 const SpeechRecognitionError& error) {
244 const SpeechRecognitionSessionContext& context =
245 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
246 Send(new SpeechRecognitionMsg_ErrorOccurred(context.render_view_id,
251 // The events below are currently not used by speech JS APIs implementation.
252 void SpeechRecognitionDispatcherHost::OnAudioLevelsChange(int session_id,
254 float noise_volume) {
257 void SpeechRecognitionDispatcherHost::OnEnvironmentEstimationComplete(
261 } // namespace content