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/speech_recognition_dispatcher_host.h" 6 7 #include "base/bind.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/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 #include "content/public/common/content_switches.h" 19 20 namespace content { 21 22 SpeechRecognitionDispatcherHost::SpeechRecognitionDispatcherHost( 23 bool is_guest, 24 int render_process_id, 25 net::URLRequestContextGetter* context_getter) 26 : is_guest_(is_guest), 27 render_process_id_(render_process_id), 28 context_getter_(context_getter), 29 weak_factory_(this) { 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. 33 } 34 35 SpeechRecognitionDispatcherHost::~SpeechRecognitionDispatcherHost() { 36 SpeechRecognitionManager::GetInstance()->AbortAllSessionsForRenderProcess( 37 render_process_id_); 38 } 39 40 base::WeakPtr<SpeechRecognitionDispatcherHost> 41 SpeechRecognitionDispatcherHost::AsWeakPtr() { 42 return weak_factory_.GetWeakPtr(); 43 } 44 45 bool SpeechRecognitionDispatcherHost::OnMessageReceived( 46 const IPC::Message& message, bool* message_was_ok) { 47 bool handled = true; 48 IPC_BEGIN_MESSAGE_MAP_EX(SpeechRecognitionDispatcherHost, message, 49 *message_was_ok) 50 IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_StartRequest, 51 OnStartRequest) 52 IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_AbortRequest, 53 OnAbortRequest) 54 IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_StopCaptureRequest, 55 OnStopCaptureRequest) 56 IPC_MESSAGE_UNHANDLED(handled = false) 57 IPC_END_MESSAGE_MAP() 58 return handled; 59 } 60 61 void SpeechRecognitionDispatcherHost::OverrideThreadForMessage( 62 const IPC::Message& message, 63 BrowserThread::ID* thread) { 64 if (message.type() == SpeechRecognitionHostMsg_StartRequest::ID) 65 *thread = BrowserThread::UI; 66 } 67 68 void SpeechRecognitionDispatcherHost::OnChannelClosing() { 69 weak_factory_.InvalidateWeakPtrs(); 70 } 71 72 void SpeechRecognitionDispatcherHost::OnStartRequest( 73 const SpeechRecognitionHostMsg_StartRequest_Params& params) { 74 SpeechRecognitionHostMsg_StartRequest_Params input_params(params); 75 76 int embedder_render_process_id = 0; 77 int embedder_render_view_id = MSG_ROUTING_NONE; 78 if (is_guest_) { 79 // If the speech API request was from a guest, save the context of the 80 // embedder since we will use it to decide permission. 81 RenderViewHostImpl* render_view_host = 82 RenderViewHostImpl::FromID(render_process_id_, params.render_view_id); 83 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( 84 WebContents::FromRenderViewHost(render_view_host)); 85 BrowserPluginGuest* guest = web_contents->GetBrowserPluginGuest(); 86 87 embedder_render_process_id = 88 guest->embedder_web_contents()->GetRenderProcessHost()->GetID(); 89 DCHECK_NE(embedder_render_process_id, 0); 90 embedder_render_view_id = 91 guest->embedder_web_contents()->GetRenderViewHost()->GetRoutingID(); 92 DCHECK_NE(embedder_render_view_id, MSG_ROUTING_NONE); 93 } 94 95 // TODO(lazyboy): Check if filter_profanities should use |render_process_id| 96 // instead of |render_process_id_|. We are also using the same value in 97 // input_tag_dispatcher_host.cc 98 bool filter_profanities = 99 SpeechRecognitionManagerImpl::GetInstance() && 100 SpeechRecognitionManagerImpl::GetInstance()->delegate() && 101 SpeechRecognitionManagerImpl::GetInstance()->delegate()-> 102 FilterProfanities(render_process_id_); 103 104 BrowserThread::PostTask( 105 BrowserThread::IO, 106 FROM_HERE, 107 base::Bind(&SpeechRecognitionDispatcherHost::OnStartRequestOnIO, 108 this, 109 embedder_render_process_id, 110 embedder_render_view_id, 111 input_params, 112 filter_profanities)); 113 } 114 115 void SpeechRecognitionDispatcherHost::OnStartRequestOnIO( 116 int embedder_render_process_id, 117 int embedder_render_view_id, 118 const SpeechRecognitionHostMsg_StartRequest_Params& params, 119 bool filter_profanities) { 120 SpeechRecognitionSessionContext context; 121 context.context_name = params.origin_url; 122 context.render_process_id = render_process_id_; 123 context.render_view_id = params.render_view_id; 124 context.embedder_render_process_id = embedder_render_process_id; 125 context.embedder_render_view_id = embedder_render_view_id; 126 if (embedder_render_process_id) 127 context.guest_render_view_id = params.render_view_id; 128 context.request_id = params.request_id; 129 context.requested_by_page_element = false; 130 131 SpeechRecognitionSessionConfig config; 132 config.is_legacy_api = false; 133 config.language = params.language; 134 config.grammars = params.grammars; 135 config.max_hypotheses = params.max_hypotheses; 136 config.origin_url = params.origin_url; 137 config.initial_context = context; 138 config.url_request_context_getter = context_getter_.get(); 139 config.filter_profanities = filter_profanities; 140 config.continuous = params.continuous; 141 config.interim_results = params.interim_results; 142 config.event_listener = AsWeakPtr(); 143 144 int session_id = SpeechRecognitionManager::GetInstance()->CreateSession( 145 config); 146 DCHECK_NE(session_id, SpeechRecognitionManager::kSessionIDInvalid); 147 SpeechRecognitionManager::GetInstance()->StartSession(session_id); 148 } 149 150 void SpeechRecognitionDispatcherHost::OnAbortRequest(int render_view_id, 151 int request_id) { 152 int session_id = SpeechRecognitionManager::GetInstance()->GetSession( 153 render_process_id_, render_view_id, request_id); 154 155 // The renderer might provide an invalid |request_id| if the session was not 156 // started as expected, e.g., due to unsatisfied security requirements. 157 if (session_id != SpeechRecognitionManager::kSessionIDInvalid) 158 SpeechRecognitionManager::GetInstance()->AbortSession(session_id); 159 } 160 161 void SpeechRecognitionDispatcherHost::OnStopCaptureRequest( 162 int render_view_id, int request_id) { 163 int session_id = SpeechRecognitionManager::GetInstance()->GetSession( 164 render_process_id_, render_view_id, request_id); 165 166 // The renderer might provide an invalid |request_id| if the session was not 167 // started as expected, e.g., due to unsatisfied security requirements. 168 if (session_id != SpeechRecognitionManager::kSessionIDInvalid) { 169 SpeechRecognitionManager::GetInstance()->StopAudioCaptureForSession( 170 session_id); 171 } 172 } 173 174 // -------- SpeechRecognitionEventListener interface implementation ----------- 175 176 void SpeechRecognitionDispatcherHost::OnRecognitionStart(int session_id) { 177 const SpeechRecognitionSessionContext& context = 178 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 179 Send(new SpeechRecognitionMsg_Started(context.render_view_id, 180 context.request_id)); 181 } 182 183 void SpeechRecognitionDispatcherHost::OnAudioStart(int session_id) { 184 const SpeechRecognitionSessionContext& context = 185 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 186 Send(new SpeechRecognitionMsg_AudioStarted(context.render_view_id, 187 context.request_id)); 188 } 189 190 void SpeechRecognitionDispatcherHost::OnSoundStart(int session_id) { 191 const SpeechRecognitionSessionContext& context = 192 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 193 Send(new SpeechRecognitionMsg_SoundStarted(context.render_view_id, 194 context.request_id)); 195 } 196 197 void SpeechRecognitionDispatcherHost::OnSoundEnd(int session_id) { 198 const SpeechRecognitionSessionContext& context = 199 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 200 Send(new SpeechRecognitionMsg_SoundEnded(context.render_view_id, 201 context.request_id)); 202 } 203 204 void SpeechRecognitionDispatcherHost::OnAudioEnd(int session_id) { 205 const SpeechRecognitionSessionContext& context = 206 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 207 Send(new SpeechRecognitionMsg_AudioEnded(context.render_view_id, 208 context.request_id)); 209 } 210 211 void SpeechRecognitionDispatcherHost::OnRecognitionEnd(int session_id) { 212 const SpeechRecognitionSessionContext& context = 213 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 214 Send(new SpeechRecognitionMsg_Ended(context.render_view_id, 215 context.request_id)); 216 } 217 218 void SpeechRecognitionDispatcherHost::OnRecognitionResults( 219 int session_id, 220 const SpeechRecognitionResults& results) { 221 const SpeechRecognitionSessionContext& context = 222 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 223 Send(new SpeechRecognitionMsg_ResultRetrieved(context.render_view_id, 224 context.request_id, 225 results)); 226 } 227 228 void SpeechRecognitionDispatcherHost::OnRecognitionError( 229 int session_id, 230 const SpeechRecognitionError& error) { 231 const SpeechRecognitionSessionContext& context = 232 SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); 233 Send(new SpeechRecognitionMsg_ErrorOccurred(context.render_view_id, 234 context.request_id, 235 error)); 236 } 237 238 // The events below are currently not used by speech JS APIs implementation. 239 void SpeechRecognitionDispatcherHost::OnAudioLevelsChange(int session_id, 240 float volume, 241 float noise_volume) { 242 } 243 244 void SpeechRecognitionDispatcherHost::OnEnvironmentEstimationComplete( 245 int session_id) { 246 } 247 248 } // namespace content 249