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