- add sources.
[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/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"
17
18 namespace {
19 const uint32 kMaxHypothesesForSpeechInputTag = 6;
20 }
21
22 namespace content {
23
24 InputTagSpeechDispatcherHost::InputTagSpeechDispatcherHost(
25     bool is_guest,
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.
34 }
35
36 InputTagSpeechDispatcherHost::~InputTagSpeechDispatcherHost() {
37   SpeechRecognitionManager::GetInstance()->AbortAllSessionsForListener(this);
38 }
39
40 bool InputTagSpeechDispatcherHost::OnMessageReceived(
41     const IPC::Message& message, bool* message_was_ok) {
42   bool handled = true;
43   IPC_BEGIN_MESSAGE_MAP_EX(InputTagSpeechDispatcherHost, message,
44                            *message_was_ok)
45     IPC_MESSAGE_HANDLER(InputTagSpeechHostMsg_StartRecognition,
46                         OnStartRecognition)
47     IPC_MESSAGE_HANDLER(InputTagSpeechHostMsg_CancelRecognition,
48                         OnCancelRecognition)
49     IPC_MESSAGE_HANDLER(InputTagSpeechHostMsg_StopRecording,
50                         OnStopRecording)
51     IPC_MESSAGE_UNHANDLED(handled = false)
52   IPC_END_MESSAGE_MAP()
53   return handled;
54 }
55
56 void InputTagSpeechDispatcherHost::OverrideThreadForMessage(
57     const IPC::Message& message,
58     BrowserThread::ID* thread) {
59   if (message.type() == InputTagSpeechHostMsg_StartRecognition::ID)
60     *thread = BrowserThread::UI;
61 }
62
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;
71   if (is_guest_) {
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;
80     render_process_id =
81         guest->embedder_web_contents()->GetRenderProcessHost()->GetID();
82     input_params.render_view_id =
83         guest->embedder_web_contents()->GetRoutingID();
84   }
85   bool filter_profanities =
86       SpeechRecognitionManagerImpl::GetInstance() &&
87       SpeechRecognitionManagerImpl::GetInstance()->delegate() &&
88       SpeechRecognitionManagerImpl::GetInstance()->delegate()->
89           FilterProfanities(render_process_id_);
90
91  BrowserThread::PostTask(
92       BrowserThread::IO, FROM_HERE,
93       base::Bind(
94           &InputTagSpeechDispatcherHost::StartRecognitionOnIO,
95           this,
96           render_process_id,
97           guest_render_view_id,
98           input_params,
99           filter_profanities));
100 }
101
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
112   // unset.
113   context.request_id = params.request_id;
114   context.element_rect = params.element_rect;
115
116   SpeechRecognitionSessionConfig config;
117   config.language = params.language;
118   if (!params.grammar.empty()) {
119     config.grammars.push_back(SpeechRecognitionGrammar(params.grammar));
120   }
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;
127
128   int session_id = SpeechRecognitionManager::GetInstance()->CreateSession(
129       config);
130   DCHECK_NE(session_id, SpeechRecognitionManager::kSessionIDInvalid);
131   SpeechRecognitionManager::GetInstance()->StartSession(session_id);
132 }
133
134 void InputTagSpeechDispatcherHost::OnCancelRecognition(int render_view_id,
135                                                        int request_id) {
136   int session_id = SpeechRecognitionManager::GetInstance()->GetSession(
137       render_process_id_, render_view_id, request_id);
138
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);
143 }
144
145 void InputTagSpeechDispatcherHost::OnStopRecording(int render_view_id,
146                                                    int request_id) {
147   int session_id = SpeechRecognitionManager::GetInstance()->GetSession(
148       render_process_id_, render_view_id, request_id);
149
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(
154         session_id);
155   }
156 }
157
158 // -------- SpeechRecognitionEventListener interface implementation -----------
159 void InputTagSpeechDispatcherHost::OnRecognitionResults(
160     int session_id,
161     const SpeechRecognitionResults& results) {
162   DVLOG(1) << "InputTagSpeechDispatcherHost::OnRecognitionResults enter";
163
164   const SpeechRecognitionSessionContext& context =
165       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
166
167   int render_view_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(
171       render_view_id,
172       context.request_id,
173       results));
174   DVLOG(1) << "InputTagSpeechDispatcherHost::OnRecognitionResults exit";
175 }
176
177 void InputTagSpeechDispatcherHost::OnAudioEnd(int session_id) {
178   DVLOG(1) << "InputTagSpeechDispatcherHost::OnAudioEnd enter";
179
180   const SpeechRecognitionSessionContext& context =
181       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
182   int render_view_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";
188 }
189
190 void InputTagSpeechDispatcherHost::OnRecognitionEnd(int session_id) {
191   DVLOG(1) << "InputTagSpeechDispatcherHost::OnRecognitionEnd enter";
192   const SpeechRecognitionSessionContext& context =
193       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
194   int render_view_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";
200 }
201
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(
208     int session_id,
209     const SpeechRecognitionError& error) {}
210 void InputTagSpeechDispatcherHost::OnAudioLevelsChange(
211     int session_id, float volume, float noise_volume) {}
212 void InputTagSpeechDispatcherHost::OnEnvironmentEstimationComplete(
213     int session_id) {}
214
215 }  // namespace content