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 void SpeechRecognitionDispatcherHost::OnDestruct() const {
46 BrowserThread::DeleteOnIOThread::Destruct(this);
49 bool SpeechRecognitionDispatcherHost::OnMessageReceived(
50 const IPC::Message
& message
) {
52 IPC_BEGIN_MESSAGE_MAP(SpeechRecognitionDispatcherHost
, message
)
53 IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_StartRequest
,
55 IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_AbortRequest
,
57 IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_StopCaptureRequest
,
59 IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_AbortAllRequests
,
61 IPC_MESSAGE_UNHANDLED(handled
= false)
66 void SpeechRecognitionDispatcherHost::OverrideThreadForMessage(
67 const IPC::Message
& message
,
68 BrowserThread::ID
* thread
) {
69 if (message
.type() == SpeechRecognitionHostMsg_StartRequest::ID
)
70 *thread
= BrowserThread::UI
;
73 void SpeechRecognitionDispatcherHost::OnChannelClosing() {
74 weak_factory_
.InvalidateWeakPtrs();
77 void SpeechRecognitionDispatcherHost::OnStartRequest(
78 const SpeechRecognitionHostMsg_StartRequest_Params
& params
) {
79 SpeechRecognitionHostMsg_StartRequest_Params
input_params(params
);
81 // Check that the origin specified by the renderer process is one
82 // that it is allowed to access.
83 if (params
.origin_url
!= "null" &&
84 !ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
85 render_process_id_
, GURL(params
.origin_url
))) {
86 LOG(ERROR
) << "SRDH::OnStartRequest, disallowed origin: "
91 int embedder_render_process_id
= 0;
92 int embedder_render_view_id
= MSG_ROUTING_NONE
;
93 RenderViewHostImpl
* render_view_host
=
94 RenderViewHostImpl::FromID(render_process_id_
, params
.render_view_id
);
95 if (!render_view_host
) {
96 // RVH can be null if the tab was closed while continuous mode speech
97 // recognition was running. This seems to happen on mac.
98 LOG(WARNING
) << "SRDH::OnStartRequest, RenderViewHost does not exist";
101 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
102 WebContents::FromRenderViewHost(render_view_host
));
103 BrowserPluginGuest
* guest
= web_contents
->GetBrowserPluginGuest();
105 // If the speech API request was from a guest, save the context of the
106 // embedder since we will use it to decide permission.
107 embedder_render_process_id
=
108 guest
->embedder_web_contents()->GetRenderProcessHost()->GetID();
109 DCHECK_NE(embedder_render_process_id
, 0);
110 embedder_render_view_id
=
111 guest
->embedder_web_contents()->GetRenderViewHost()->GetRoutingID();
112 DCHECK_NE(embedder_render_view_id
, MSG_ROUTING_NONE
);
115 // TODO(lazyboy): Check if filter_profanities should use |render_process_id|
116 // instead of |render_process_id_|.
117 bool filter_profanities
=
118 SpeechRecognitionManagerImpl::GetInstance() &&
119 SpeechRecognitionManagerImpl::GetInstance()->delegate() &&
120 SpeechRecognitionManagerImpl::GetInstance()->delegate()->
121 FilterProfanities(render_process_id_
);
123 // TODO(miu): This is a hack to allow SpeechRecognition to operate with the
124 // MediaStreamManager, which partitions requests per RenderFrame, not per
125 // RenderView. http://crbug.com/390749
126 const int params_render_frame_id
= render_view_host
?
127 render_view_host
->GetMainFrame()->GetRoutingID() : MSG_ROUTING_NONE
;
129 BrowserThread::PostTask(
132 base::Bind(&SpeechRecognitionDispatcherHost::OnStartRequestOnIO
,
134 embedder_render_process_id
,
135 embedder_render_view_id
,
137 params_render_frame_id
,
138 filter_profanities
));
141 void SpeechRecognitionDispatcherHost::OnStartRequestOnIO(
142 int embedder_render_process_id
,
143 int embedder_render_view_id
,
144 const SpeechRecognitionHostMsg_StartRequest_Params
& params
,
145 int params_render_frame_id
,
146 bool filter_profanities
) {
147 SpeechRecognitionSessionContext context
;
148 context
.context_name
= params
.origin_url
;
149 context
.render_process_id
= render_process_id_
;
150 context
.render_view_id
= params
.render_view_id
;
151 context
.render_frame_id
= params_render_frame_id
;
152 context
.embedder_render_process_id
= embedder_render_process_id
;
153 context
.embedder_render_view_id
= embedder_render_view_id
;
154 if (embedder_render_process_id
)
155 context
.guest_render_view_id
= params
.render_view_id
;
156 context
.request_id
= params
.request_id
;
158 SpeechRecognitionSessionConfig config
;
159 config
.is_legacy_api
= false;
160 config
.language
= params
.language
;
161 config
.grammars
= params
.grammars
;
162 config
.max_hypotheses
= params
.max_hypotheses
;
163 config
.origin_url
= params
.origin_url
;
164 config
.initial_context
= context
;
165 config
.url_request_context_getter
= context_getter_
.get();
166 config
.filter_profanities
= filter_profanities
;
167 config
.continuous
= params
.continuous
;
168 config
.interim_results
= params
.interim_results
;
169 config
.event_listener
= AsWeakPtr();
171 int session_id
= SpeechRecognitionManager::GetInstance()->CreateSession(
173 DCHECK_NE(session_id
, SpeechRecognitionManager::kSessionIDInvalid
);
174 SpeechRecognitionManager::GetInstance()->StartSession(session_id
);
177 void SpeechRecognitionDispatcherHost::OnAbortRequest(int render_view_id
,
179 int session_id
= SpeechRecognitionManager::GetInstance()->GetSession(
180 render_process_id_
, render_view_id
, request_id
);
182 // The renderer might provide an invalid |request_id| if the session was not
183 // started as expected, e.g., due to unsatisfied security requirements.
184 if (session_id
!= SpeechRecognitionManager::kSessionIDInvalid
)
185 SpeechRecognitionManager::GetInstance()->AbortSession(session_id
);
188 void SpeechRecognitionDispatcherHost::OnAbortAllRequests(int render_view_id
) {
189 SpeechRecognitionManager::GetInstance()->AbortAllSessionsForRenderView(
190 render_process_id_
, render_view_id
);
193 void SpeechRecognitionDispatcherHost::OnStopCaptureRequest(
194 int render_view_id
, int request_id
) {
195 int session_id
= SpeechRecognitionManager::GetInstance()->GetSession(
196 render_process_id_
, render_view_id
, request_id
);
198 // The renderer might provide an invalid |request_id| if the session was not
199 // started as expected, e.g., due to unsatisfied security requirements.
200 if (session_id
!= SpeechRecognitionManager::kSessionIDInvalid
) {
201 SpeechRecognitionManager::GetInstance()->StopAudioCaptureForSession(
206 // -------- SpeechRecognitionEventListener interface implementation -----------
208 void SpeechRecognitionDispatcherHost::OnRecognitionStart(int session_id
) {
209 const SpeechRecognitionSessionContext
& context
=
210 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id
);
211 Send(new SpeechRecognitionMsg_Started(context
.render_view_id
,
212 context
.request_id
));
215 void SpeechRecognitionDispatcherHost::OnAudioStart(int session_id
) {
216 const SpeechRecognitionSessionContext
& context
=
217 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id
);
218 Send(new SpeechRecognitionMsg_AudioStarted(context
.render_view_id
,
219 context
.request_id
));
222 void SpeechRecognitionDispatcherHost::OnSoundStart(int session_id
) {
223 const SpeechRecognitionSessionContext
& context
=
224 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id
);
225 Send(new SpeechRecognitionMsg_SoundStarted(context
.render_view_id
,
226 context
.request_id
));
229 void SpeechRecognitionDispatcherHost::OnSoundEnd(int session_id
) {
230 const SpeechRecognitionSessionContext
& context
=
231 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id
);
232 Send(new SpeechRecognitionMsg_SoundEnded(context
.render_view_id
,
233 context
.request_id
));
236 void SpeechRecognitionDispatcherHost::OnAudioEnd(int session_id
) {
237 const SpeechRecognitionSessionContext
& context
=
238 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id
);
239 Send(new SpeechRecognitionMsg_AudioEnded(context
.render_view_id
,
240 context
.request_id
));
243 void SpeechRecognitionDispatcherHost::OnRecognitionEnd(int session_id
) {
244 const SpeechRecognitionSessionContext
& context
=
245 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id
);
246 Send(new SpeechRecognitionMsg_Ended(context
.render_view_id
,
247 context
.request_id
));
250 void SpeechRecognitionDispatcherHost::OnRecognitionResults(
252 const SpeechRecognitionResults
& results
) {
253 const SpeechRecognitionSessionContext
& context
=
254 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id
);
255 Send(new SpeechRecognitionMsg_ResultRetrieved(context
.render_view_id
,
260 void SpeechRecognitionDispatcherHost::OnRecognitionError(
262 const SpeechRecognitionError
& error
) {
263 const SpeechRecognitionSessionContext
& context
=
264 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id
);
265 Send(new SpeechRecognitionMsg_ErrorOccurred(context
.render_view_id
,
270 // The events below are currently not used by speech JS APIs implementation.
271 void SpeechRecognitionDispatcherHost::OnAudioLevelsChange(int session_id
,
273 float noise_volume
) {
276 void SpeechRecognitionDispatcherHost::OnEnvironmentEstimationComplete(
280 } // namespace content