Home | History | Annotate | Download | only in renderer
      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/renderer/speech_recognition_dispatcher.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "content/common/speech_recognition_messages.h"
     10 #include "content/renderer/render_view_impl.h"
     11 #include "third_party/WebKit/public/platform/WebString.h"
     12 #include "third_party/WebKit/public/platform/WebVector.h"
     13 #include "third_party/WebKit/public/web/WebSpeechGrammar.h"
     14 #include "third_party/WebKit/public/web/WebSpeechRecognitionParams.h"
     15 #include "third_party/WebKit/public/web/WebSpeechRecognitionResult.h"
     16 #include "third_party/WebKit/public/web/WebSpeechRecognizerClient.h"
     17 
     18 using WebKit::WebVector;
     19 using WebKit::WebString;
     20 using WebKit::WebSpeechGrammar;
     21 using WebKit::WebSpeechRecognitionHandle;
     22 using WebKit::WebSpeechRecognitionResult;
     23 using WebKit::WebSpeechRecognitionParams;
     24 using WebKit::WebSpeechRecognizerClient;
     25 
     26 namespace content {
     27 
     28 SpeechRecognitionDispatcher::SpeechRecognitionDispatcher(
     29     RenderViewImpl* render_view)
     30     : RenderViewObserver(render_view),
     31       recognizer_client_(NULL),
     32       next_id_(1) {
     33 }
     34 
     35 SpeechRecognitionDispatcher::~SpeechRecognitionDispatcher() {
     36 }
     37 
     38 bool SpeechRecognitionDispatcher::OnMessageReceived(
     39     const IPC::Message& message) {
     40   bool handled = true;
     41   IPC_BEGIN_MESSAGE_MAP(SpeechRecognitionDispatcher, message)
     42     IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_Started, OnRecognitionStarted)
     43     IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_AudioStarted, OnAudioStarted)
     44     IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_SoundStarted, OnSoundStarted)
     45     IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_SoundEnded, OnSoundEnded)
     46     IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_AudioEnded, OnAudioEnded)
     47     IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_ErrorOccurred, OnErrorOccurred)
     48     IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_Ended, OnRecognitionEnded)
     49     IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_ResultRetrieved,
     50                         OnResultsRetrieved)
     51     IPC_MESSAGE_UNHANDLED(handled = false)
     52   IPC_END_MESSAGE_MAP()
     53   return handled;
     54 }
     55 
     56 void SpeechRecognitionDispatcher::start(
     57     const WebSpeechRecognitionHandle& handle,
     58     const WebSpeechRecognitionParams& params,
     59     WebSpeechRecognizerClient* recognizer_client) {
     60   DCHECK(!recognizer_client_ || recognizer_client_ == recognizer_client);
     61   recognizer_client_ = recognizer_client;
     62 
     63   SpeechRecognitionHostMsg_StartRequest_Params msg_params;
     64   for (size_t i = 0; i < params.grammars().size(); ++i) {
     65     const WebSpeechGrammar& grammar = params.grammars()[i];
     66     msg_params.grammars.push_back(
     67         SpeechRecognitionGrammar(grammar.src().spec(), grammar.weight()));
     68   }
     69   msg_params.language = UTF16ToUTF8(params.language());
     70   msg_params.max_hypotheses = static_cast<uint32>(params.maxAlternatives());
     71   msg_params.continuous = params.continuous();
     72   msg_params.interim_results = params.interimResults();
     73   msg_params.origin_url = params.origin().toString().utf8();
     74   msg_params.render_view_id = routing_id();
     75   msg_params.request_id = GetOrCreateIDForHandle(handle);
     76   // The handle mapping will be removed in |OnRecognitionEnd|.
     77   Send(new SpeechRecognitionHostMsg_StartRequest(msg_params));
     78 }
     79 
     80 void SpeechRecognitionDispatcher::stop(
     81     const WebSpeechRecognitionHandle& handle,
     82     WebSpeechRecognizerClient* recognizer_client) {
     83   // Ignore a |stop| issued without a matching |start|.
     84   if (recognizer_client_ != recognizer_client || !HandleExists(handle))
     85     return;
     86   Send(new SpeechRecognitionHostMsg_StopCaptureRequest(
     87       routing_id(), GetOrCreateIDForHandle(handle)));
     88 }
     89 
     90 void SpeechRecognitionDispatcher::abort(
     91     const WebSpeechRecognitionHandle& handle,
     92     WebSpeechRecognizerClient* recognizer_client) {
     93   // Ignore an |abort| issued without a matching |start|.
     94   if (recognizer_client_ != recognizer_client || !HandleExists(handle))
     95     return;
     96   Send(new SpeechRecognitionHostMsg_AbortRequest(
     97       routing_id(), GetOrCreateIDForHandle(handle)));
     98 }
     99 
    100 void SpeechRecognitionDispatcher::OnRecognitionStarted(int request_id) {
    101   recognizer_client_->didStart(GetHandleFromID(request_id));
    102 }
    103 
    104 void SpeechRecognitionDispatcher::OnAudioStarted(int request_id) {
    105   recognizer_client_->didStartAudio(GetHandleFromID(request_id));
    106 }
    107 
    108 void SpeechRecognitionDispatcher::OnSoundStarted(int request_id) {
    109   recognizer_client_->didStartSound(GetHandleFromID(request_id));
    110 }
    111 
    112 void SpeechRecognitionDispatcher::OnSoundEnded(int request_id) {
    113   recognizer_client_->didEndSound(GetHandleFromID(request_id));
    114 }
    115 
    116 void SpeechRecognitionDispatcher::OnAudioEnded(int request_id) {
    117   recognizer_client_->didEndAudio(GetHandleFromID(request_id));
    118 }
    119 
    120 static WebSpeechRecognizerClient::ErrorCode WebKitErrorCode(
    121     SpeechRecognitionErrorCode e) {
    122   switch (e) {
    123     case SPEECH_RECOGNITION_ERROR_NONE:
    124       NOTREACHED();
    125       return WebSpeechRecognizerClient::OtherError;
    126     case SPEECH_RECOGNITION_ERROR_ABORTED:
    127       return WebSpeechRecognizerClient::AbortedError;
    128     case SPEECH_RECOGNITION_ERROR_AUDIO:
    129       return WebSpeechRecognizerClient::AudioCaptureError;
    130     case SPEECH_RECOGNITION_ERROR_NETWORK:
    131       return WebSpeechRecognizerClient::NetworkError;
    132     case SPEECH_RECOGNITION_ERROR_NOT_ALLOWED:
    133       return WebSpeechRecognizerClient::NotAllowedError;
    134     case SPEECH_RECOGNITION_ERROR_NO_SPEECH:
    135       return WebSpeechRecognizerClient::NoSpeechError;
    136     case SPEECH_RECOGNITION_ERROR_NO_MATCH:
    137       NOTREACHED();
    138       return WebSpeechRecognizerClient::OtherError;
    139     case SPEECH_RECOGNITION_ERROR_BAD_GRAMMAR:
    140       return WebSpeechRecognizerClient::BadGrammarError;
    141   }
    142   NOTREACHED();
    143   return WebSpeechRecognizerClient::OtherError;
    144 }
    145 
    146 void SpeechRecognitionDispatcher::OnErrorOccurred(
    147     int request_id, const SpeechRecognitionError& error) {
    148   if (error.code == SPEECH_RECOGNITION_ERROR_NO_MATCH) {
    149     recognizer_client_->didReceiveNoMatch(GetHandleFromID(request_id),
    150                                           WebSpeechRecognitionResult());
    151   } else {
    152     recognizer_client_->didReceiveError(
    153         GetHandleFromID(request_id),
    154         WebString(),  // TODO(primiano): message?
    155         WebKitErrorCode(error.code));
    156   }
    157 }
    158 
    159 void SpeechRecognitionDispatcher::OnRecognitionEnded(int request_id) {
    160   // TODO(tommi): It is possible that the handle isn't found in the array if
    161   // the user just refreshed the page. It seems that we then get a notification
    162   // for the previously loaded instance of the page.
    163   HandleMap::iterator iter = handle_map_.find(request_id);
    164   if (iter == handle_map_.end()) {
    165     DLOG(ERROR) << "OnRecognitionEnded called for a handle that doesn't exist";
    166   } else {
    167     WebSpeechRecognitionHandle handle = iter->second;
    168     // Note: we need to erase the handle from the map *before* calling didEnd.
    169     // didEnd may call back synchronously to start a new recognition session,
    170     // and we don't want to delete the handle from the map after that happens.
    171     handle_map_.erase(request_id);
    172     recognizer_client_->didEnd(handle);
    173   }
    174 }
    175 
    176 void SpeechRecognitionDispatcher::OnResultsRetrieved(
    177     int request_id, const SpeechRecognitionResults& results) {
    178   size_t provisional_count = 0;
    179   SpeechRecognitionResults::const_iterator it = results.begin();
    180   for (; it != results.end(); ++it) {
    181     if (it->is_provisional)
    182       ++provisional_count;
    183   }
    184 
    185   WebVector<WebSpeechRecognitionResult> provisional(provisional_count);
    186   WebVector<WebSpeechRecognitionResult> final(
    187       results.size() - provisional_count);
    188 
    189   int provisional_index = 0, final_index = 0;
    190   for (it = results.begin(); it != results.end(); ++it) {
    191     const SpeechRecognitionResult& result = (*it);
    192     WebSpeechRecognitionResult* webkit_result = result.is_provisional ?
    193         &provisional[provisional_index++] : &final[final_index++];
    194 
    195     const size_t num_hypotheses = result.hypotheses.size();
    196     WebVector<WebString> transcripts(num_hypotheses);
    197     WebVector<float> confidences(num_hypotheses);
    198     for (size_t i = 0; i < num_hypotheses; ++i) {
    199       transcripts[i] = result.hypotheses[i].utterance;
    200       confidences[i] = static_cast<float>(result.hypotheses[i].confidence);
    201     }
    202     webkit_result->assign(transcripts, confidences, !result.is_provisional);
    203   }
    204 
    205   recognizer_client_->didReceiveResults(
    206       GetHandleFromID(request_id), final, provisional);
    207 }
    208 
    209 
    210 int SpeechRecognitionDispatcher::GetOrCreateIDForHandle(
    211     const WebSpeechRecognitionHandle& handle) {
    212   // Search first for an existing mapping.
    213   for (HandleMap::iterator iter = handle_map_.begin();
    214       iter != handle_map_.end();
    215       ++iter) {
    216     if (iter->second.equals(handle))
    217       return iter->first;
    218   }
    219   // If no existing mapping found, create a new one.
    220   const int new_id = next_id_;
    221   handle_map_[new_id] = handle;
    222   ++next_id_;
    223   return new_id;
    224 }
    225 
    226 bool SpeechRecognitionDispatcher::HandleExists(
    227     const WebSpeechRecognitionHandle& handle) {
    228   for (HandleMap::iterator iter = handle_map_.begin();
    229       iter != handle_map_.end();
    230       ++iter) {
    231     if (iter->second.equals(handle))
    232       return true;
    233   }
    234   return false;
    235 }
    236 
    237 const WebSpeechRecognitionHandle& SpeechRecognitionDispatcher::GetHandleFromID(
    238     int request_id) {
    239   HandleMap::iterator iter = handle_map_.find(request_id);
    240   DCHECK(iter != handle_map_.end());
    241   return iter->second;
    242 }
    243 
    244 }  // namespace content
    245