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_extension_api.h"
      6 
      7 #include <string>
      8 
      9 #include "base/lazy_instance.h"
     10 #include "base/values.h"
     11 #include "chrome/browser/extensions/event_router.h"
     12 #include "chrome/browser/extensions/extension_function_registry.h"
     13 #include "chrome/browser/profiles/profile.h"
     14 #include "chrome/browser/speech/extension_api/tts_engine_extension_api.h"
     15 #include "chrome/browser/speech/extension_api/tts_extension_api_constants.h"
     16 #include "chrome/browser/speech/tts_controller.h"
     17 #include "ui/base/l10n/l10n_util.h"
     18 
     19 namespace constants = tts_extension_api_constants;
     20 
     21 namespace events {
     22 const char kOnEvent[] = "tts.onEvent";
     23 };  // namespace events
     24 
     25 const char *TtsEventTypeToString(TtsEventType event_type) {
     26   switch (event_type) {
     27     case TTS_EVENT_START:
     28       return constants::kEventTypeStart;
     29     case TTS_EVENT_END:
     30       return constants::kEventTypeEnd;
     31     case TTS_EVENT_WORD:
     32       return constants::kEventTypeWord;
     33     case TTS_EVENT_SENTENCE:
     34       return constants::kEventTypeSentence;
     35     case TTS_EVENT_MARKER:
     36       return constants::kEventTypeMarker;
     37     case TTS_EVENT_INTERRUPTED:
     38       return constants::kEventTypeInterrupted;
     39     case TTS_EVENT_CANCELLED:
     40       return constants::kEventTypeCancelled;
     41     case TTS_EVENT_ERROR:
     42       return constants::kEventTypeError;
     43     case TTS_EVENT_PAUSE:
     44       return constants::kEventTypePause;
     45     case TTS_EVENT_RESUME:
     46       return constants::kEventTypeResume;
     47     default:
     48       NOTREACHED();
     49       return constants::kEventTypeError;
     50   }
     51 }
     52 
     53 TtsEventType TtsEventTypeFromString(const std::string& str) {
     54   if (str == constants::kEventTypeStart)
     55     return TTS_EVENT_START;
     56   if (str == constants::kEventTypeEnd)
     57     return TTS_EVENT_END;
     58   if (str == constants::kEventTypeWord)
     59     return TTS_EVENT_WORD;
     60   if (str == constants::kEventTypeSentence)
     61     return TTS_EVENT_SENTENCE;
     62   if (str == constants::kEventTypeMarker)
     63     return TTS_EVENT_MARKER;
     64   if (str == constants::kEventTypeInterrupted)
     65     return TTS_EVENT_INTERRUPTED;
     66   if (str == constants::kEventTypeCancelled)
     67     return TTS_EVENT_CANCELLED;
     68   if (str == constants::kEventTypeError)
     69     return TTS_EVENT_ERROR;
     70   if (str == constants::kEventTypePause)
     71     return TTS_EVENT_PAUSE;
     72   if (str == constants::kEventTypeResume)
     73     return TTS_EVENT_RESUME;
     74 
     75   NOTREACHED();
     76   return TTS_EVENT_ERROR;
     77 }
     78 
     79 namespace extensions {
     80 
     81 // One of these is constructed for each utterance, and deleted
     82 // when the utterance gets any final event.
     83 class TtsExtensionEventHandler : public UtteranceEventDelegate {
     84  public:
     85   virtual void OnTtsEvent(Utterance* utterance,
     86                           TtsEventType event_type,
     87                           int char_index,
     88                           const std::string& error_message) OVERRIDE;
     89 };
     90 
     91 void TtsExtensionEventHandler::OnTtsEvent(Utterance* utterance,
     92                                           TtsEventType event_type,
     93                                           int char_index,
     94                                           const std::string& error_message) {
     95   if (utterance->src_id() < 0)
     96     return;
     97 
     98   const std::set<TtsEventType>& desired_event_types =
     99       utterance->desired_event_types();
    100   if (desired_event_types.size() > 0 &&
    101       desired_event_types.find(event_type) == desired_event_types.end()) {
    102     return;
    103   }
    104 
    105   const char *event_type_string = TtsEventTypeToString(event_type);
    106   scoped_ptr<DictionaryValue> details(new DictionaryValue());
    107   if (char_index >= 0)
    108     details->SetInteger(constants::kCharIndexKey, char_index);
    109   details->SetString(constants::kEventTypeKey, event_type_string);
    110   if (event_type == TTS_EVENT_ERROR) {
    111     details->SetString(constants::kErrorMessageKey, error_message);
    112   }
    113   details->SetInteger(constants::kSrcIdKey, utterance->src_id());
    114   details->SetBoolean(constants::kIsFinalEventKey, utterance->finished());
    115 
    116   scoped_ptr<ListValue> arguments(new ListValue());
    117   arguments->Set(0, details.release());
    118 
    119   scoped_ptr<extensions::Event> event(
    120       new extensions::Event(events::kOnEvent, arguments.Pass()));
    121   event->restrict_to_profile = utterance->profile();
    122   event->event_url = utterance->src_url();
    123   extensions::ExtensionSystem::Get(utterance->profile())->event_router()->
    124       DispatchEventToExtension(utterance->src_extension_id(), event.Pass());
    125 
    126   if (utterance->finished())
    127     delete this;
    128 }
    129 
    130 
    131 bool TtsSpeakFunction::RunImpl() {
    132   std::string text;
    133   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &text));
    134   if (text.size() > 32768) {
    135     error_ = constants::kErrorUtteranceTooLong;
    136     return false;
    137   }
    138 
    139   scoped_ptr<DictionaryValue> options(new DictionaryValue());
    140   if (args_->GetSize() >= 2) {
    141     DictionaryValue* temp_options = NULL;
    142     if (args_->GetDictionary(1, &temp_options))
    143       options.reset(temp_options->DeepCopy());
    144   }
    145 
    146   std::string voice_name;
    147   if (options->HasKey(constants::kVoiceNameKey)) {
    148     EXTENSION_FUNCTION_VALIDATE(
    149         options->GetString(constants::kVoiceNameKey, &voice_name));
    150   }
    151 
    152   std::string lang;
    153   if (options->HasKey(constants::kLangKey))
    154     EXTENSION_FUNCTION_VALIDATE(options->GetString(constants::kLangKey, &lang));
    155   if (!lang.empty() && !l10n_util::IsValidLocaleSyntax(lang)) {
    156     error_ = constants::kErrorInvalidLang;
    157     return false;
    158   }
    159 
    160   std::string gender_str;
    161   TtsGenderType gender;
    162   if (options->HasKey(constants::kGenderKey))
    163     EXTENSION_FUNCTION_VALIDATE(
    164         options->GetString(constants::kGenderKey, &gender_str));
    165   if (gender_str == constants::kGenderMale) {
    166     gender = TTS_GENDER_MALE;
    167   } else if (gender_str == constants::kGenderFemale) {
    168     gender = TTS_GENDER_FEMALE;
    169   } else if (gender_str.empty()) {
    170     gender = TTS_GENDER_NONE;
    171   } else {
    172     error_ = constants::kErrorInvalidGender;
    173     return false;
    174   }
    175 
    176   double rate = 1.0;
    177   if (options->HasKey(constants::kRateKey)) {
    178     EXTENSION_FUNCTION_VALIDATE(
    179         options->GetDouble(constants::kRateKey, &rate));
    180     if (rate < 0.1 || rate > 10.0) {
    181       error_ = constants::kErrorInvalidRate;
    182       return false;
    183     }
    184   }
    185 
    186   double pitch = 1.0;
    187   if (options->HasKey(constants::kPitchKey)) {
    188     EXTENSION_FUNCTION_VALIDATE(
    189         options->GetDouble(constants::kPitchKey, &pitch));
    190     if (pitch < 0.0 || pitch > 2.0) {
    191       error_ = constants::kErrorInvalidPitch;
    192       return false;
    193     }
    194   }
    195 
    196   double volume = 1.0;
    197   if (options->HasKey(constants::kVolumeKey)) {
    198     EXTENSION_FUNCTION_VALIDATE(
    199         options->GetDouble(constants::kVolumeKey, &volume));
    200     if (volume < 0.0 || volume > 1.0) {
    201       error_ = constants::kErrorInvalidVolume;
    202       return false;
    203     }
    204   }
    205 
    206   bool can_enqueue = false;
    207   if (options->HasKey(constants::kEnqueueKey)) {
    208     EXTENSION_FUNCTION_VALIDATE(
    209         options->GetBoolean(constants::kEnqueueKey, &can_enqueue));
    210   }
    211 
    212   std::set<TtsEventType> required_event_types;
    213   if (options->HasKey(constants::kRequiredEventTypesKey)) {
    214     ListValue* list;
    215     EXTENSION_FUNCTION_VALIDATE(
    216         options->GetList(constants::kRequiredEventTypesKey, &list));
    217     for (size_t i = 0; i < list->GetSize(); ++i) {
    218       std::string event_type;
    219       if (list->GetString(i, &event_type))
    220         required_event_types.insert(TtsEventTypeFromString(event_type.c_str()));
    221     }
    222   }
    223 
    224   std::set<TtsEventType> desired_event_types;
    225   if (options->HasKey(constants::kDesiredEventTypesKey)) {
    226     ListValue* list;
    227     EXTENSION_FUNCTION_VALIDATE(
    228         options->GetList(constants::kDesiredEventTypesKey, &list));
    229     for (size_t i = 0; i < list->GetSize(); ++i) {
    230       std::string event_type;
    231       if (list->GetString(i, &event_type))
    232         desired_event_types.insert(TtsEventTypeFromString(event_type.c_str()));
    233     }
    234   }
    235 
    236   std::string voice_extension_id;
    237   if (options->HasKey(constants::kExtensionIdKey)) {
    238     EXTENSION_FUNCTION_VALIDATE(
    239         options->GetString(constants::kExtensionIdKey, &voice_extension_id));
    240   }
    241 
    242   int src_id = -1;
    243   if (options->HasKey(constants::kSrcIdKey)) {
    244     EXTENSION_FUNCTION_VALIDATE(
    245         options->GetInteger(constants::kSrcIdKey, &src_id));
    246   }
    247 
    248   // If we got this far, the arguments were all in the valid format, so
    249   // send the success response to the callback now - this ensures that
    250   // the callback response always arrives before events, which makes
    251   // the behavior more predictable and easier to write unit tests for too.
    252   SendResponse(true);
    253 
    254   UtteranceContinuousParameters continuous_params;
    255   continuous_params.rate = rate;
    256   continuous_params.pitch = pitch;
    257   continuous_params.volume = volume;
    258 
    259   Utterance* utterance = new Utterance(profile());
    260   utterance->set_text(text);
    261   utterance->set_voice_name(voice_name);
    262   utterance->set_src_extension_id(extension_id());
    263   utterance->set_src_id(src_id);
    264   utterance->set_src_url(source_url());
    265   utterance->set_lang(lang);
    266   utterance->set_gender(gender);
    267   utterance->set_continuous_parameters(continuous_params);
    268   utterance->set_can_enqueue(can_enqueue);
    269   utterance->set_required_event_types(required_event_types);
    270   utterance->set_desired_event_types(desired_event_types);
    271   utterance->set_extension_id(voice_extension_id);
    272   utterance->set_options(options.get());
    273   utterance->set_event_delegate(new TtsExtensionEventHandler());
    274 
    275   TtsController* controller = TtsController::GetInstance();
    276   controller->SpeakOrEnqueue(utterance);
    277   return true;
    278 }
    279 
    280 bool TtsStopSpeakingFunction::RunImpl() {
    281   TtsController::GetInstance()->Stop();
    282   return true;
    283 }
    284 
    285 bool TtsPauseFunction::RunImpl() {
    286   TtsController::GetInstance()->Pause();
    287   return true;
    288 }
    289 
    290 bool TtsResumeFunction::RunImpl() {
    291   TtsController::GetInstance()->Resume();
    292   return true;
    293 }
    294 
    295 bool TtsIsSpeakingFunction::RunImpl() {
    296   SetResult(Value::CreateBooleanValue(
    297       TtsController::GetInstance()->IsSpeaking()));
    298   return true;
    299 }
    300 
    301 bool TtsGetVoicesFunction::RunImpl() {
    302   std::vector<VoiceData> voices;
    303   TtsController::GetInstance()->GetVoices(profile(), &voices);
    304 
    305   scoped_ptr<ListValue> result_voices(new ListValue());
    306   for (size_t i = 0; i < voices.size(); ++i) {
    307     const VoiceData& voice = voices[i];
    308     DictionaryValue* result_voice = new DictionaryValue();
    309     result_voice->SetString(constants::kVoiceNameKey, voice.name);
    310     if (!voice.lang.empty())
    311       result_voice->SetString(constants::kLangKey, voice.lang);
    312     if (voice.gender == TTS_GENDER_MALE)
    313       result_voice->SetString(constants::kGenderKey, constants::kGenderMale);
    314     else if (voice.gender == TTS_GENDER_FEMALE)
    315       result_voice->SetString(constants::kGenderKey, constants::kGenderFemale);
    316     if (!voice.extension_id.empty())
    317       result_voice->SetString(constants::kExtensionIdKey, voice.extension_id);
    318 
    319     ListValue* event_types = new ListValue();
    320     for (std::set<TtsEventType>::iterator iter = voice.events.begin();
    321          iter != voice.events.end(); ++iter) {
    322       const char* event_name_constant = TtsEventTypeToString(*iter);
    323       event_types->Append(Value::CreateStringValue(event_name_constant));
    324     }
    325     result_voice->Set(constants::kEventTypesKey, event_types);
    326 
    327     result_voices->Append(result_voice);
    328   }
    329 
    330   SetResult(result_voices.release());
    331   return true;
    332 }
    333 
    334 // static
    335 TtsAPI* TtsAPI::Get(Profile* profile) {
    336   return ProfileKeyedAPIFactory<TtsAPI>::GetForProfile(profile);
    337 }
    338 
    339 TtsAPI::TtsAPI(Profile* profile) {
    340   ExtensionFunctionRegistry* registry =
    341       ExtensionFunctionRegistry::GetInstance();
    342   registry->RegisterFunction<ExtensionTtsEngineSendTtsEventFunction>();
    343   registry->RegisterFunction<TtsGetVoicesFunction>();
    344   registry->RegisterFunction<TtsIsSpeakingFunction>();
    345   registry->RegisterFunction<TtsSpeakFunction>();
    346   registry->RegisterFunction<TtsStopSpeakingFunction>();
    347   registry->RegisterFunction<TtsPauseFunction>();
    348   registry->RegisterFunction<TtsResumeFunction>();
    349 }
    350 
    351 TtsAPI::~TtsAPI() {
    352 }
    353 
    354 static base::LazyInstance<ProfileKeyedAPIFactory<TtsAPI> >
    355 g_factory = LAZY_INSTANCE_INITIALIZER;
    356 
    357 ProfileKeyedAPIFactory<TtsAPI>* TtsAPI::GetFactoryInstance() {
    358   return &g_factory.Get();
    359 }
    360 
    361 }  // namespace extensions
    362