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/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