Home | History | Annotate | Download | only in extension_api
      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 "chrome/browser/speech/extension_api/tts_engine_extension_api.h"
      6 
      7 #include <string>
      8 
      9 #include "base/json/json_writer.h"
     10 #include "base/values.h"
     11 #include "chrome/browser/extensions/extension_service.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/browser/speech/extension_api/tts_extension_api.h"
     14 #include "chrome/browser/speech/extension_api/tts_extension_api_constants.h"
     15 #include "chrome/browser/speech/tts_controller.h"
     16 #include "chrome/common/extensions/api/speech/tts_engine_manifest_handler.h"
     17 #include "content/public/browser/render_process_host.h"
     18 #include "content/public/browser/render_view_host.h"
     19 #include "content/public/common/console_message_level.h"
     20 #include "extensions/browser/event_router.h"
     21 #include "extensions/browser/extension_host.h"
     22 #include "extensions/browser/extension_system.h"
     23 #include "extensions/browser/process_manager.h"
     24 #include "extensions/common/extension.h"
     25 #include "extensions/common/extension_messages.h"
     26 #include "extensions/common/extension_set.h"
     27 #include "net/base/network_change_notifier.h"
     28 
     29 using extensions::EventRouter;
     30 using extensions::Extension;
     31 using extensions::ExtensionSystem;
     32 
     33 namespace constants = tts_extension_api_constants;
     34 
     35 namespace tts_engine_events {
     36 const char kOnSpeak[] = "ttsEngine.onSpeak";
     37 const char kOnStop[] = "ttsEngine.onStop";
     38 const char kOnPause[] = "ttsEngine.onPause";
     39 const char kOnResume[] = "ttsEngine.onResume";
     40 };  // namespace tts_engine_events
     41 
     42 namespace {
     43 void WarnIfMissingPauseOrResumeListener(
     44     Profile* profile, EventRouter* event_router, std::string extension_id) {
     45   bool has_onpause = event_router->ExtensionHasEventListener(
     46       extension_id, tts_engine_events::kOnPause);
     47   bool has_onresume = event_router->ExtensionHasEventListener(
     48       extension_id, tts_engine_events::kOnResume);
     49   if (has_onpause == has_onresume)
     50     return;
     51 
     52   extensions::ProcessManager* process_manager =
     53       ExtensionSystem::Get(profile)->process_manager();
     54   extensions::ExtensionHost* host =
     55       process_manager->GetBackgroundHostForExtension(extension_id);
     56   host->render_process_host()->Send(new ExtensionMsg_AddMessageToConsole(
     57       host->render_view_host()->GetRoutingID(),
     58       content::CONSOLE_MESSAGE_LEVEL_WARNING,
     59       constants::kErrorMissingPauseOrResume));
     60 };
     61 }  // anonymous namespace
     62 
     63 void GetExtensionVoices(Profile* profile, std::vector<VoiceData>* out_voices) {
     64   ExtensionService* service = profile->GetExtensionService();
     65   DCHECK(service);
     66   EventRouter* event_router = EventRouter::Get(profile);
     67   DCHECK(event_router);
     68 
     69   bool is_offline = (net::NetworkChangeNotifier::GetConnectionType() ==
     70                      net::NetworkChangeNotifier::CONNECTION_NONE);
     71 
     72   const extensions::ExtensionSet* extensions = service->extensions();
     73   extensions::ExtensionSet::const_iterator iter;
     74   for (iter = extensions->begin(); iter != extensions->end(); ++iter) {
     75     const Extension* extension = iter->get();
     76 
     77     if (!event_router->ExtensionHasEventListener(
     78             extension->id(), tts_engine_events::kOnSpeak) ||
     79         !event_router->ExtensionHasEventListener(
     80             extension->id(), tts_engine_events::kOnStop)) {
     81       continue;
     82     }
     83 
     84     const std::vector<extensions::TtsVoice>* tts_voices =
     85         extensions::TtsVoice::GetTtsVoices(extension);
     86     if (!tts_voices)
     87       continue;
     88 
     89     for (size_t i = 0; i < tts_voices->size(); ++i) {
     90       const extensions::TtsVoice& voice = tts_voices->at(i);
     91 
     92       // Don't return remote voices when the system is offline.
     93       if (voice.remote && is_offline)
     94         continue;
     95 
     96       out_voices->push_back(VoiceData());
     97       VoiceData& result_voice = out_voices->back();
     98 
     99       result_voice.native = false;
    100       result_voice.name = voice.voice_name;
    101       result_voice.lang = voice.lang;
    102       result_voice.remote = voice.remote;
    103       result_voice.extension_id = extension->id();
    104       if (voice.gender == constants::kGenderMale)
    105         result_voice.gender = TTS_GENDER_MALE;
    106       else if (voice.gender == constants::kGenderFemale)
    107         result_voice.gender = TTS_GENDER_FEMALE;
    108       else
    109         result_voice.gender = TTS_GENDER_NONE;
    110 
    111       for (std::set<std::string>::const_iterator iter =
    112                voice.event_types.begin();
    113            iter != voice.event_types.end();
    114            ++iter) {
    115         result_voice.events.insert(TtsEventTypeFromString(*iter));
    116       }
    117 
    118       // If the extension sends end events, the controller will handle
    119       // queueing and send interrupted and cancelled events.
    120       if (voice.event_types.find(constants::kEventTypeEnd) !=
    121           voice.event_types.end()) {
    122         result_voice.events.insert(TTS_EVENT_CANCELLED);
    123         result_voice.events.insert(TTS_EVENT_INTERRUPTED);
    124       }
    125     }
    126   }
    127 }
    128 
    129 void ExtensionTtsEngineSpeak(Utterance* utterance, const VoiceData& voice) {
    130   // See if the engine supports the "end" event; if so, we can keep the
    131   // utterance around and track it. If not, we're finished with this
    132   // utterance now.
    133   bool sends_end_event = voice.events.find(TTS_EVENT_END) != voice.events.end();
    134 
    135   scoped_ptr<base::ListValue> args(new base::ListValue());
    136   args->Set(0, base::Value::CreateStringValue(utterance->text()));
    137 
    138   // Pass through most options to the speech engine, but remove some
    139   // that are handled internally.
    140   scoped_ptr<base::DictionaryValue> options(static_cast<base::DictionaryValue*>(
    141       utterance->options()->DeepCopy()));
    142   if (options->HasKey(constants::kRequiredEventTypesKey))
    143     options->Remove(constants::kRequiredEventTypesKey, NULL);
    144   if (options->HasKey(constants::kDesiredEventTypesKey))
    145     options->Remove(constants::kDesiredEventTypesKey, NULL);
    146   if (sends_end_event && options->HasKey(constants::kEnqueueKey))
    147     options->Remove(constants::kEnqueueKey, NULL);
    148   if (options->HasKey(constants::kSrcIdKey))
    149     options->Remove(constants::kSrcIdKey, NULL);
    150   if (options->HasKey(constants::kIsFinalEventKey))
    151     options->Remove(constants::kIsFinalEventKey, NULL);
    152   if (options->HasKey(constants::kOnEventKey))
    153     options->Remove(constants::kOnEventKey, NULL);
    154 
    155   // Add the voice name and language to the options if they're not
    156   // already there, since they might have been picked by the TTS controller
    157   // rather than directly by the client that requested the speech.
    158   if (!options->HasKey(constants::kVoiceNameKey))
    159     options->SetString(constants::kVoiceNameKey, voice.name);
    160   if (!options->HasKey(constants::kLangKey))
    161     options->SetString(constants::kLangKey, voice.lang);
    162 
    163   args->Set(1, options.release());
    164   args->Set(2, base::Value::CreateIntegerValue(utterance->id()));
    165 
    166   scoped_ptr<extensions::Event> event(new extensions::Event(
    167       tts_engine_events::kOnSpeak, args.Pass()));
    168   event->restrict_to_browser_context = utterance->profile();
    169   EventRouter::Get(utterance->profile())
    170       ->DispatchEventToExtension(utterance->extension_id(), event.Pass());
    171 }
    172 
    173 void ExtensionTtsEngineStop(Utterance* utterance) {
    174   scoped_ptr<base::ListValue> args(new base::ListValue());
    175   scoped_ptr<extensions::Event> event(new extensions::Event(
    176       tts_engine_events::kOnStop, args.Pass()));
    177   event->restrict_to_browser_context = utterance->profile();
    178   EventRouter::Get(utterance->profile())
    179       ->DispatchEventToExtension(utterance->extension_id(), event.Pass());
    180 }
    181 
    182 void ExtensionTtsEnginePause(Utterance* utterance) {
    183   scoped_ptr<base::ListValue> args(new base::ListValue());
    184   scoped_ptr<extensions::Event> event(new extensions::Event(
    185       tts_engine_events::kOnPause, args.Pass()));
    186   Profile* profile = utterance->profile();
    187   event->restrict_to_browser_context = profile;
    188   EventRouter* event_router = EventRouter::Get(profile);
    189   std::string id = utterance->extension_id();
    190   event_router->DispatchEventToExtension(id, event.Pass());
    191   WarnIfMissingPauseOrResumeListener(profile, event_router, id);
    192 }
    193 
    194 void ExtensionTtsEngineResume(Utterance* utterance) {
    195   scoped_ptr<base::ListValue> args(new base::ListValue());
    196   scoped_ptr<extensions::Event> event(new extensions::Event(
    197       tts_engine_events::kOnResume, args.Pass()));
    198   Profile* profile = utterance->profile();
    199   event->restrict_to_browser_context = profile;
    200   EventRouter* event_router = EventRouter::Get(profile);
    201   std::string id = utterance->extension_id();
    202   event_router->DispatchEventToExtension(id, event.Pass());
    203   WarnIfMissingPauseOrResumeListener(profile, event_router, id);
    204 }
    205 
    206 bool ExtensionTtsEngineSendTtsEventFunction::RunSync() {
    207   int utterance_id;
    208   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &utterance_id));
    209 
    210   base::DictionaryValue* event;
    211   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &event));
    212 
    213   std::string event_type;
    214   EXTENSION_FUNCTION_VALIDATE(
    215       event->GetString(constants::kEventTypeKey, &event_type));
    216 
    217   int char_index = 0;
    218   if (event->HasKey(constants::kCharIndexKey)) {
    219     EXTENSION_FUNCTION_VALIDATE(
    220         event->GetInteger(constants::kCharIndexKey, &char_index));
    221   }
    222 
    223   // Make sure the extension has included this event type in its manifest.
    224   bool event_type_allowed = false;
    225   const Extension* extension = GetExtension();
    226   const std::vector<extensions::TtsVoice>* tts_voices =
    227       extensions::TtsVoice::GetTtsVoices(extension);
    228   if (!tts_voices) {
    229     error_ = constants::kErrorUndeclaredEventType;
    230     return false;
    231   }
    232 
    233   for (size_t i = 0; i < tts_voices->size(); i++) {
    234     const extensions::TtsVoice& voice = tts_voices->at(i);
    235     if (voice.event_types.find(event_type) != voice.event_types.end()) {
    236       event_type_allowed = true;
    237       break;
    238     }
    239   }
    240   if (!event_type_allowed) {
    241     error_ = constants::kErrorUndeclaredEventType;
    242     return false;
    243   }
    244 
    245   TtsController* controller = TtsController::GetInstance();
    246   if (event_type == constants::kEventTypeStart) {
    247     controller->OnTtsEvent(
    248         utterance_id, TTS_EVENT_START, char_index, std::string());
    249   } else if (event_type == constants::kEventTypeEnd) {
    250     controller->OnTtsEvent(
    251         utterance_id, TTS_EVENT_END, char_index, std::string());
    252   } else if (event_type == constants::kEventTypeWord) {
    253     controller->OnTtsEvent(
    254         utterance_id, TTS_EVENT_WORD, char_index, std::string());
    255   } else if (event_type == constants::kEventTypeSentence) {
    256     controller->OnTtsEvent(
    257         utterance_id, TTS_EVENT_SENTENCE, char_index, std::string());
    258   } else if (event_type == constants::kEventTypeMarker) {
    259     controller->OnTtsEvent(
    260         utterance_id, TTS_EVENT_MARKER, char_index, std::string());
    261   } else if (event_type == constants::kEventTypeError) {
    262     std::string error_message;
    263     event->GetString(constants::kErrorMessageKey, &error_message);
    264     controller->OnTtsEvent(
    265         utterance_id, TTS_EVENT_ERROR, char_index, error_message);
    266   } else if (event_type == constants::kEventTypePause) {
    267     controller->OnTtsEvent(
    268         utterance_id, TTS_EVENT_PAUSE, char_index, std::string());
    269   } else if (event_type == constants::kEventTypeResume) {
    270     controller->OnTtsEvent(
    271         utterance_id, TTS_EVENT_RESUME, char_index, std::string());
    272   } else {
    273     EXTENSION_FUNCTION_VALIDATE(false);
    274   }
    275 
    276   return true;
    277 }
    278