Home | History | Annotate | Download | only in speech
      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/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"
     20 
     21 namespace content {
     22 
     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),
     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) {
     47   bool handled = true;
     48   IPC_BEGIN_MESSAGE_MAP(SpeechRecognitionDispatcherHost, message)
     49     IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_StartRequest,
     50                         OnStartRequest)
     51     IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_AbortRequest,
     52                         OnAbortRequest)
     53     IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_StopCaptureRequest,
     54                         OnStopCaptureRequest)
     55     IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_AbortAllRequests,
     56                         OnAbortAllRequests)
     57     IPC_MESSAGE_UNHANDLED(handled = false)
     58   IPC_END_MESSAGE_MAP()
     59   return handled;
     60 }
     61 
     62 void SpeechRecognitionDispatcherHost::OverrideThreadForMessage(
     63     const IPC::Message& message,
     64     BrowserThread::ID* thread) {
     65   if (message.type() == SpeechRecognitionHostMsg_StartRequest::ID)
     66     *thread = BrowserThread::UI;
     67 }
     68 
     69 void SpeechRecognitionDispatcherHost::OnChannelClosing() {
     70   weak_factory_.InvalidateWeakPtrs();
     71 }
     72 
     73 void SpeechRecognitionDispatcherHost::OnStartRequest(
     74     const SpeechRecognitionHostMsg_StartRequest_Params& params) {
     75   SpeechRecognitionHostMsg_StartRequest_Params input_params(params);
     76 
     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: "
     83                << params.origin_url;
     84     return;
     85   }
     86 
     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   if (!render_view_host) {
     92     // RVH can be null if the tab was closed while continuous mode speech
     93     // recognition was running. This seems to happen on mac.
     94     LOG(WARNING) << "SRDH::OnStartRequest, RenderViewHost does not exist";
     95     return;
     96   }
     97   WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
     98       WebContents::FromRenderViewHost(render_view_host));
     99   BrowserPluginGuest* guest = web_contents->GetBrowserPluginGuest();
    100   if (guest) {
    101     // If the speech API request was from a guest, save the context of the
    102     // embedder since we will use it to decide permission.
    103     embedder_render_process_id =
    104         guest->embedder_web_contents()->GetRenderProcessHost()->GetID();
    105     DCHECK_NE(embedder_render_process_id, 0);
    106     embedder_render_view_id =
    107         guest->embedder_web_contents()->GetRenderViewHost()->GetRoutingID();
    108     DCHECK_NE(embedder_render_view_id, MSG_ROUTING_NONE);
    109   }
    110 
    111   // TODO(lazyboy): Check if filter_profanities should use |render_process_id|
    112   // instead of |render_process_id_|.
    113   bool filter_profanities =
    114       SpeechRecognitionManagerImpl::GetInstance() &&
    115       SpeechRecognitionManagerImpl::GetInstance()->delegate() &&
    116       SpeechRecognitionManagerImpl::GetInstance()->delegate()->
    117           FilterProfanities(render_process_id_);
    118 
    119   // TODO(miu): This is a hack to allow SpeechRecognition to operate with the
    120   // MediaStreamManager, which partitions requests per RenderFrame, not per
    121   // RenderView.  http://crbug.com/390749
    122   const int params_render_frame_id = render_view_host ?
    123       render_view_host->GetMainFrame()->GetRoutingID() : MSG_ROUTING_NONE;
    124 
    125   BrowserThread::PostTask(
    126       BrowserThread::IO,
    127       FROM_HERE,
    128       base::Bind(&SpeechRecognitionDispatcherHost::OnStartRequestOnIO,
    129                  this,
    130                  embedder_render_process_id,
    131                  embedder_render_view_id,
    132                  input_params,
    133                  params_render_frame_id,
    134                  filter_profanities));
    135 }
    136 
    137 void SpeechRecognitionDispatcherHost::OnStartRequestOnIO(
    138     int embedder_render_process_id,
    139     int embedder_render_view_id,
    140     const SpeechRecognitionHostMsg_StartRequest_Params& params,
    141     int params_render_frame_id,
    142     bool filter_profanities) {
    143   SpeechRecognitionSessionContext context;
    144   context.context_name = params.origin_url;
    145   context.render_process_id = render_process_id_;
    146   context.render_view_id = params.render_view_id;
    147   context.render_frame_id = params_render_frame_id;
    148   context.embedder_render_process_id = embedder_render_process_id;
    149   context.embedder_render_view_id = embedder_render_view_id;
    150   if (embedder_render_process_id)
    151     context.guest_render_view_id = params.render_view_id;
    152   context.request_id = params.request_id;
    153 
    154   SpeechRecognitionSessionConfig config;
    155   config.is_legacy_api = false;
    156   config.language = params.language;
    157   config.grammars = params.grammars;
    158   config.max_hypotheses = params.max_hypotheses;
    159   config.origin_url = params.origin_url;
    160   config.initial_context = context;
    161   config.url_request_context_getter = context_getter_.get();
    162   config.filter_profanities = filter_profanities;
    163   config.continuous = params.continuous;
    164   config.interim_results = params.interim_results;
    165   config.event_listener = AsWeakPtr();
    166 
    167   int session_id = SpeechRecognitionManager::GetInstance()->CreateSession(
    168       config);
    169   DCHECK_NE(session_id, SpeechRecognitionManager::kSessionIDInvalid);
    170   SpeechRecognitionManager::GetInstance()->StartSession(session_id);
    171 }
    172 
    173 void SpeechRecognitionDispatcherHost::OnAbortRequest(int render_view_id,
    174                                                      int request_id) {
    175   int session_id = SpeechRecognitionManager::GetInstance()->GetSession(
    176       render_process_id_, render_view_id, request_id);
    177 
    178   // The renderer might provide an invalid |request_id| if the session was not
    179   // started as expected, e.g., due to unsatisfied security requirements.
    180   if (session_id != SpeechRecognitionManager::kSessionIDInvalid)
    181     SpeechRecognitionManager::GetInstance()->AbortSession(session_id);
    182 }
    183 
    184 void SpeechRecognitionDispatcherHost::OnAbortAllRequests(int render_view_id) {
    185   SpeechRecognitionManager::GetInstance()->AbortAllSessionsForRenderView(
    186       render_process_id_, render_view_id);
    187 }
    188 
    189 void SpeechRecognitionDispatcherHost::OnStopCaptureRequest(
    190     int render_view_id, int request_id) {
    191   int session_id = SpeechRecognitionManager::GetInstance()->GetSession(
    192       render_process_id_, render_view_id, request_id);
    193 
    194   // The renderer might provide an invalid |request_id| if the session was not
    195   // started as expected, e.g., due to unsatisfied security requirements.
    196   if (session_id != SpeechRecognitionManager::kSessionIDInvalid) {
    197     SpeechRecognitionManager::GetInstance()->StopAudioCaptureForSession(
    198         session_id);
    199   }
    200 }
    201 
    202 // -------- SpeechRecognitionEventListener interface implementation -----------
    203 
    204 void SpeechRecognitionDispatcherHost::OnRecognitionStart(int session_id) {
    205   const SpeechRecognitionSessionContext& context =
    206       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
    207   Send(new SpeechRecognitionMsg_Started(context.render_view_id,
    208                                         context.request_id));
    209 }
    210 
    211 void SpeechRecognitionDispatcherHost::OnAudioStart(int session_id) {
    212   const SpeechRecognitionSessionContext& context =
    213       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
    214   Send(new SpeechRecognitionMsg_AudioStarted(context.render_view_id,
    215                                              context.request_id));
    216 }
    217 
    218 void SpeechRecognitionDispatcherHost::OnSoundStart(int session_id) {
    219   const SpeechRecognitionSessionContext& context =
    220       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
    221   Send(new SpeechRecognitionMsg_SoundStarted(context.render_view_id,
    222                                              context.request_id));
    223 }
    224 
    225 void SpeechRecognitionDispatcherHost::OnSoundEnd(int session_id) {
    226   const SpeechRecognitionSessionContext& context =
    227       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
    228   Send(new SpeechRecognitionMsg_SoundEnded(context.render_view_id,
    229                                            context.request_id));
    230 }
    231 
    232 void SpeechRecognitionDispatcherHost::OnAudioEnd(int session_id) {
    233   const SpeechRecognitionSessionContext& context =
    234       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
    235   Send(new SpeechRecognitionMsg_AudioEnded(context.render_view_id,
    236                                            context.request_id));
    237 }
    238 
    239 void SpeechRecognitionDispatcherHost::OnRecognitionEnd(int session_id) {
    240   const SpeechRecognitionSessionContext& context =
    241       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
    242   Send(new SpeechRecognitionMsg_Ended(context.render_view_id,
    243                                       context.request_id));
    244 }
    245 
    246 void SpeechRecognitionDispatcherHost::OnRecognitionResults(
    247     int session_id,
    248     const SpeechRecognitionResults& results) {
    249   const SpeechRecognitionSessionContext& context =
    250       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
    251   Send(new SpeechRecognitionMsg_ResultRetrieved(context.render_view_id,
    252                                                 context.request_id,
    253                                                 results));
    254 }
    255 
    256 void SpeechRecognitionDispatcherHost::OnRecognitionError(
    257     int session_id,
    258     const SpeechRecognitionError& error) {
    259   const SpeechRecognitionSessionContext& context =
    260       SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
    261   Send(new SpeechRecognitionMsg_ErrorOccurred(context.render_view_id,
    262                                               context.request_id,
    263                                               error));
    264 }
    265 
    266 // The events below are currently not used by speech JS APIs implementation.
    267 void SpeechRecognitionDispatcherHost::OnAudioLevelsChange(int session_id,
    268                                                           float volume,
    269                                                           float noise_volume) {
    270 }
    271 
    272 void SpeechRecognitionDispatcherHost::OnEnvironmentEstimationComplete(
    273     int session_id) {
    274 }
    275 
    276 }  // namespace content
    277