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