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