Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / content / browser / speech / input_tag_speech_dispatcher_host.cc
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/browser/speech/input_tag_speech_dispatcher_host.h"
6
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "content/browser/browser_plugin/browser_plugin_guest.h"
10 #include "content/browser/child_process_security_policy_impl.h"
11 #include "content/browser/renderer_host/render_view_host_impl.h"
12 #include "content/browser/speech/speech_recognition_manager_impl.h"
13 #include "content/browser/web_contents/web_contents_impl.h"
14 #include "content/common/speech_recognition_messages.h"
15 #include "content/public/browser/speech_recognition_manager_delegate.h"
16 #include "content/public/browser/speech_recognition_session_config.h"
17 #include "content/public/browser/speech_recognition_session_context.h"
18
19 namespace {
20 const uint32 kMaxHypothesesForSpeechInputTag = 6;
21 }
22
23 namespace content {
24
25 InputTagSpeechDispatcherHost::InputTagSpeechDispatcherHost(
26     bool is_guest,
27     int render_process_id,
28     net::URLRequestContextGetter* url_request_context_getter)
29     : BrowserMessageFilter(SpeechRecognitionMsgStart),
30       is_guest_(is_guest),
31       render_process_id_(render_process_id),
32       url_request_context_getter_(url_request_context_getter),
33       weak_factory_(this) {
34   // Do not add any non-trivial initialization here, instead do it lazily when
35   // required (e.g. see the method |SpeechRecognitionManager::GetInstance()|) or
36   // add an Init() method.
37 }
38
39 InputTagSpeechDispatcherHost::~InputTagSpeechDispatcherHost() {
40   SpeechRecognitionManager::GetInstance()->AbortAllSessionsForRenderProcess(
41       render_process_id_);
42 }
43
44 base::WeakPtr<InputTagSpeechDispatcherHost>
45 InputTagSpeechDispatcherHost::AsWeakPtr() {
46   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
47   return weak_factory_.GetWeakPtr();
48 }
49
50 bool InputTagSpeechDispatcherHost::OnMessageReceived(
51     const IPC::Message& message, bool* message_was_ok) {
52   bool handled = true;
53   IPC_BEGIN_MESSAGE_MAP_EX(InputTagSpeechDispatcherHost, message,
54                            *message_was_ok)
55     IPC_MESSAGE_HANDLER(InputTagSpeechHostMsg_StartRecognition,
56                         OnStartRecognition)
57     IPC_MESSAGE_HANDLER(InputTagSpeechHostMsg_CancelRecognition,
58                         OnCancelRecognition)
59     IPC_MESSAGE_HANDLER(InputTagSpeechHostMsg_StopRecording,
60                         OnStopRecording)
61     IPC_MESSAGE_UNHANDLED(handled = false)
62   IPC_END_MESSAGE_MAP()
63   return handled;
64 }
65
66 void InputTagSpeechDispatcherHost::OverrideThreadForMessage(
67     const IPC::Message& message,
68     BrowserThread::ID* thread) {
69   if (message.type() == InputTagSpeechHostMsg_StartRecognition::ID)
70     *thread = BrowserThread::UI;
71 }
72
73 void InputTagSpeechDispatcherHost::OnChannelClosing() {
74   weak_factory_.InvalidateWeakPtrs();
75 }
76
77 void InputTagSpeechDispatcherHost::OnStartRecognition(
78     const InputTagSpeechHostMsg_StartRecognition_Params& params) {
79   InputTagSpeechHostMsg_StartRecognition_Params input_params(params);
80   int render_process_id = render_process_id_;
81
82   // Check that the origin specified by the renderer process is one
83   // that it is allowed to access.
84   if (params.origin_url != "null" &&
85       !ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
86           render_process_id, GURL(params.origin_url))) {
87     LOG(ERROR) << "ITSDH::OnStartRecognition, disallowed origin: "
88                << params.origin_url;
89     return;
90   }
91
92   // The chrome layer is mostly oblivious to BrowserPlugin guests and so it
93   // cannot correctly place the speech bubble relative to a guest. Thus, we
94   // set up the speech recognition context relative to the embedder.
95   int guest_render_view_id = MSG_ROUTING_NONE;
96   if (is_guest_) {
97     RenderViewHostImpl* render_view_host =
98         RenderViewHostImpl::FromID(render_process_id_, params.render_view_id);
99     WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
100         WebContents::FromRenderViewHost(render_view_host));
101     BrowserPluginGuest* guest = web_contents->GetBrowserPluginGuest();
102     input_params.element_rect.set_origin(
103         guest->GetScreenCoordinates(input_params.element_rect.origin()));
104     guest_render_view_id = params.render_view_id;
105     render_process_id =
106         guest->embedder_web_contents()->GetRenderProcessHost()->GetID();
107     input_params.render_view_id =
108         guest->embedder_web_contents()->GetRoutingID();
109   }
110   bool filter_profanities =
111       SpeechRecognitionManagerImpl::GetInstance() &&
112       SpeechRecognitionManagerImpl::GetInstance()->delegate() &&
113       SpeechRecognitionManagerImpl::GetInstance()->delegate()->
114           FilterProfanities(render_process_id_);
115
116  BrowserThread::PostTask(
117       BrowserThread::IO, FROM_HERE,
118       base::Bind(
119           &InputTagSpeechDispatcherHost::StartRecognitionOnIO,
120           this,
121           render_process_id,
122           guest_render_view_id,
123           input_params,
124           filter_profanities));
125 }
126
127 void InputTagSpeechDispatcherHost::StartRecognitionOnIO(
128     int render_process_id,
129     int guest_render_view_id,
130     const InputTagSpeechHostMsg_StartRecognition_Params& params,
131     bool filter_profanities) {
132   SpeechRecognitionSessionContext context;
133   context.render_process_id = render_process_id;
134   context.render_view_id = params.render_view_id;
135   context.guest_render_view_id = guest_render_view_id;
136   // Keep context.embedder_render_process_id and context.embedder_render_view_id
137   // unset.
138   context.request_id = params.request_id;
139   context.element_rect = params.element_rect;
140
141   SpeechRecognitionSessionConfig config;
142   config.language = params.language;
143   if (!params.grammar.empty()) {
144     config.grammars.push_back(SpeechRecognitionGrammar(params.grammar));
145   }
146   config.max_hypotheses = kMaxHypothesesForSpeechInputTag;
147   config.origin_url = params.origin_url;
148   config.initial_context = context;
149   config.url_request_context_getter = url_request_context_getter_.get();
150   config.filter_profanities = filter_profanities;
151   config.event_listener = AsWeakPtr();
152
153   int session_id = SpeechRecognitionManager::GetInstance()->CreateSession(
154       config);
155   DCHECK_NE(session_id, SpeechRecognitionManager::kSessionIDInvalid);
156   SpeechRecognitionManager::GetInstance()->StartSession(session_id);
157 }
158
159 void InputTagSpeechDispatcherHost::OnCancelRecognition(int render_view_id,
160                                                        int request_id) {
161   int session_id = SpeechRecognitionManager::GetInstance()->GetSession(
162       render_process_id_, render_view_id, request_id);
163
164   // The renderer might provide an invalid |request_id| if the session was not
165   // started as expected, e.g., due to unsatisfied security requirements.
166   if (session_id != SpeechRecognitionManager::kSessionIDInvalid)
167     SpeechRecognitionManager::GetInstance()->AbortSession(session_id);
168 }
169
170 void InputTagSpeechDispatcherHost::OnStopRecording(int render_view_id,
171                                                    int request_id) {
172   int session_id = SpeechRecognitionManager::GetInstance()->GetSession(
173       render_process_id_, render_view_id, request_id);
174
175   // The renderer might provide an invalid |request_id| if the session was not
176   // started as expected, e.g., due to unsatisfied security requirements.
177   if (session_id != SpeechRecognitionManager::kSessionIDInvalid) {
178     SpeechRecognitionManager::GetInstance()->StopAudioCaptureForSession(
179         session_id);
180   }
181 }
182
183 // -------- SpeechRecognitionEventListener interface implementation -----------
184 void InputTagSpeechDispatcherHost::OnRecognitionResults(
185     int session_id,
186     const SpeechRecognitionResults& results) {
187   DVLOG(1) << "InputTagSpeechDispatcherHost::OnRecognitionResults enter";
188
189   const SpeechRecognitionSessionContext& context =
190       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
191
192   int render_view_id =
193       context.guest_render_view_id == MSG_ROUTING_NONE ?
194           context.render_view_id : context.guest_render_view_id;
195   Send(new InputTagSpeechMsg_SetRecognitionResults(
196       render_view_id,
197       context.request_id,
198       results));
199   DVLOG(1) << "InputTagSpeechDispatcherHost::OnRecognitionResults exit";
200 }
201
202 void InputTagSpeechDispatcherHost::OnAudioEnd(int session_id) {
203   DVLOG(1) << "InputTagSpeechDispatcherHost::OnAudioEnd enter";
204
205   const SpeechRecognitionSessionContext& context =
206       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
207   int render_view_id =
208       context.guest_render_view_id == MSG_ROUTING_NONE ?
209           context.render_view_id : context.guest_render_view_id;
210   Send(new InputTagSpeechMsg_RecordingComplete(render_view_id,
211                                                context.request_id));
212   DVLOG(1) << "InputTagSpeechDispatcherHost::OnAudioEnd exit";
213 }
214
215 void InputTagSpeechDispatcherHost::OnRecognitionEnd(int session_id) {
216   DVLOG(1) << "InputTagSpeechDispatcherHost::OnRecognitionEnd enter";
217   const SpeechRecognitionSessionContext& context =
218       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
219   int render_view_id =
220       context.guest_render_view_id == MSG_ROUTING_NONE ?
221           context.render_view_id : context.guest_render_view_id;
222   Send(new InputTagSpeechMsg_RecognitionComplete(render_view_id,
223                                                  context.request_id));
224   DVLOG(1) << "InputTagSpeechDispatcherHost::OnRecognitionEnd exit";
225 }
226
227 // The events below are currently not used by x-webkit-speech implementation.
228 void InputTagSpeechDispatcherHost::OnRecognitionStart(int session_id) {}
229 void InputTagSpeechDispatcherHost::OnAudioStart(int session_id) {}
230 void InputTagSpeechDispatcherHost::OnSoundStart(int session_id) {}
231 void InputTagSpeechDispatcherHost::OnSoundEnd(int session_id) {}
232 void InputTagSpeechDispatcherHost::OnRecognitionError(
233     int session_id,
234     const SpeechRecognitionError& error) {}
235 void InputTagSpeechDispatcherHost::OnAudioLevelsChange(
236     int session_id, float volume, float noise_volume) {}
237 void InputTagSpeechDispatcherHost::OnEnvironmentEstimationComplete(
238     int session_id) {}
239
240 }  // namespace content