| OLD | NEW |
| (Empty) |
| 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/extensions/extension_tts_engine_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_event_router.h" | |
| 12 #include "chrome/browser/extensions/extension_service.h" | |
| 13 #include "chrome/browser/extensions/extension_tts_api_constants.h" | |
| 14 #include "chrome/browser/extensions/extension_tts_api_controller.h" | |
| 15 #include "chrome/browser/profiles/profile.h" | |
| 16 #include "chrome/common/extensions/extension.h" | |
| 17 | |
| 18 namespace constants = extension_tts_api_constants; | |
| 19 | |
| 20 namespace events { | |
| 21 const char kOnSpeak[] = "ttsEngine.onSpeak"; | |
| 22 const char kOnStop[] = "ttsEngine.onStop"; | |
| 23 }; // namespace events | |
| 24 | |
| 25 void GetExtensionVoices(Profile* profile, ListValue* result_voices) { | |
| 26 ExtensionService* service = profile->GetExtensionService(); | |
| 27 DCHECK(service); | |
| 28 ExtensionEventRouter* event_router = profile->GetExtensionEventRouter(); | |
| 29 DCHECK(event_router); | |
| 30 | |
| 31 const ExtensionSet* extensions = service->extensions(); | |
| 32 ExtensionSet::const_iterator iter; | |
| 33 for (iter = extensions->begin(); iter != extensions->end(); ++iter) { | |
| 34 const Extension* extension = *iter; | |
| 35 | |
| 36 if (!event_router->ExtensionHasEventListener( | |
| 37 extension->id(), events::kOnSpeak) || | |
| 38 !event_router->ExtensionHasEventListener( | |
| 39 extension->id(), events::kOnStop)) { | |
| 40 continue; | |
| 41 } | |
| 42 | |
| 43 const std::vector<Extension::TtsVoice>& tts_voices = | |
| 44 extension->tts_voices(); | |
| 45 for (size_t i = 0; i < tts_voices.size(); ++i) { | |
| 46 const Extension::TtsVoice& voice = tts_voices[i]; | |
| 47 DictionaryValue* result_voice = new DictionaryValue(); | |
| 48 if (!voice.voice_name.empty()) | |
| 49 result_voice->SetString(constants::kVoiceNameKey, voice.voice_name); | |
| 50 if (!voice.lang.empty()) | |
| 51 result_voice->SetString(constants::kLangKey, voice.lang); | |
| 52 if (!voice.gender.empty()) | |
| 53 result_voice->SetString(constants::kGenderKey, voice.gender); | |
| 54 result_voice->SetString(constants::kExtensionIdKey, extension->id()); | |
| 55 | |
| 56 ListValue* event_types = new ListValue(); | |
| 57 for (std::set<std::string>::const_iterator iter = | |
| 58 voice.event_types.begin(); | |
| 59 iter != voice.event_types.end(); | |
| 60 ++iter) { | |
| 61 event_types->Append(Value::CreateStringValue(*iter)); | |
| 62 } | |
| 63 // If the extension sends end events, the controller will handle | |
| 64 // queueing and send interrupted and cancelled events. | |
| 65 if (voice.event_types.find(constants::kEventTypeEnd) != | |
| 66 voice.event_types.end()) { | |
| 67 event_types->Append( | |
| 68 Value::CreateStringValue(constants::kEventTypeCancelled)); | |
| 69 event_types->Append(Value::CreateStringValue( | |
| 70 constants::kEventTypeInterrupted)); | |
| 71 } | |
| 72 | |
| 73 result_voice->Set(constants::kEventTypesKey, event_types); | |
| 74 result_voices->Append(result_voice); | |
| 75 } | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 bool GetMatchingExtensionVoice( | |
| 80 Utterance* utterance, | |
| 81 const Extension** matching_extension, | |
| 82 size_t* voice_index) { | |
| 83 // This will only happen during unit testing. Otherwise, an utterance | |
| 84 // will always have an associated profile. | |
| 85 if (!utterance->profile()) | |
| 86 return false; | |
| 87 | |
| 88 ExtensionService* service = utterance->profile()->GetExtensionService(); | |
| 89 DCHECK(service); | |
| 90 ExtensionEventRouter* event_router = | |
| 91 utterance->profile()->GetExtensionEventRouter(); | |
| 92 DCHECK(event_router); | |
| 93 | |
| 94 *matching_extension = NULL; | |
| 95 *voice_index = -1; | |
| 96 const ExtensionSet* extensions = service->extensions(); | |
| 97 ExtensionSet::const_iterator iter; | |
| 98 for (iter = extensions->begin(); iter != extensions->end(); ++iter) { | |
| 99 const Extension* extension = *iter; | |
| 100 | |
| 101 if (!event_router->ExtensionHasEventListener( | |
| 102 extension->id(), events::kOnSpeak) || | |
| 103 !event_router->ExtensionHasEventListener( | |
| 104 extension->id(), events::kOnStop)) { | |
| 105 continue; | |
| 106 } | |
| 107 | |
| 108 if (!utterance->extension_id().empty() && | |
| 109 utterance->extension_id() != extension->id()) { | |
| 110 continue; | |
| 111 } | |
| 112 | |
| 113 const std::vector<Extension::TtsVoice>& tts_voices = | |
| 114 extension->tts_voices(); | |
| 115 for (size_t i = 0; i < tts_voices.size(); ++i) { | |
| 116 const Extension::TtsVoice& voice = tts_voices[i]; | |
| 117 if (!voice.voice_name.empty() && | |
| 118 !utterance->voice_name().empty() && | |
| 119 voice.voice_name != utterance->voice_name()) { | |
| 120 continue; | |
| 121 } | |
| 122 if (!voice.lang.empty() && | |
| 123 !utterance->lang().empty() && | |
| 124 voice.lang != utterance->lang()) { | |
| 125 continue; | |
| 126 } | |
| 127 if (!voice.gender.empty() && | |
| 128 !utterance->gender().empty() && | |
| 129 voice.gender != utterance->gender()) { | |
| 130 continue; | |
| 131 } | |
| 132 if (utterance->required_event_types().size() > 0) { | |
| 133 bool has_all_required_event_types = true; | |
| 134 for (std::set<std::string>::const_iterator iter = | |
| 135 utterance->required_event_types().begin(); | |
| 136 iter != utterance->required_event_types().end(); | |
| 137 ++iter) { | |
| 138 if (voice.event_types.find(*iter) == voice.event_types.end()) { | |
| 139 has_all_required_event_types = false; | |
| 140 break; | |
| 141 } | |
| 142 } | |
| 143 if (!has_all_required_event_types) | |
| 144 continue; | |
| 145 } | |
| 146 | |
| 147 *matching_extension = extension; | |
| 148 *voice_index = i; | |
| 149 return true; | |
| 150 } | |
| 151 } | |
| 152 | |
| 153 return false; | |
| 154 } | |
| 155 | |
| 156 void ExtensionTtsEngineSpeak(Utterance* utterance, | |
| 157 const Extension* extension, | |
| 158 size_t voice_index) { | |
| 159 // See if the engine supports the "end" event; if so, we can keep the | |
| 160 // utterance around and track it. If not, we're finished with this | |
| 161 // utterance now. | |
| 162 const std::set<std::string> event_types = | |
| 163 extension->tts_voices()[voice_index].event_types; | |
| 164 bool sends_end_event = | |
| 165 (event_types.find(constants::kEventTypeEnd) != event_types.end()); | |
| 166 | |
| 167 ListValue args; | |
| 168 args.Set(0, Value::CreateStringValue(utterance->text())); | |
| 169 | |
| 170 // Pass through most options to the speech engine, but remove some | |
| 171 // that are handled internally. | |
| 172 DictionaryValue* options = static_cast<DictionaryValue*>( | |
| 173 utterance->options()->DeepCopy()); | |
| 174 if (options->HasKey(constants::kRequiredEventTypesKey)) | |
| 175 options->Remove(constants::kRequiredEventTypesKey, NULL); | |
| 176 if (options->HasKey(constants::kDesiredEventTypesKey)) | |
| 177 options->Remove(constants::kDesiredEventTypesKey, NULL); | |
| 178 if (sends_end_event && options->HasKey(constants::kEnqueueKey)) | |
| 179 options->Remove(constants::kEnqueueKey, NULL); | |
| 180 if (options->HasKey(constants::kSrcIdKey)) | |
| 181 options->Remove(constants::kSrcIdKey, NULL); | |
| 182 if (options->HasKey(constants::kIsFinalEventKey)) | |
| 183 options->Remove(constants::kIsFinalEventKey, NULL); | |
| 184 | |
| 185 args.Set(1, options); | |
| 186 args.Set(2, Value::CreateIntegerValue(utterance->id())); | |
| 187 std::string json_args; | |
| 188 base::JSONWriter::Write(&args, &json_args); | |
| 189 | |
| 190 utterance->profile()->GetExtensionEventRouter()->DispatchEventToExtension( | |
| 191 extension->id(), | |
| 192 events::kOnSpeak, | |
| 193 json_args, | |
| 194 utterance->profile(), | |
| 195 GURL()); | |
| 196 } | |
| 197 | |
| 198 void ExtensionTtsEngineStop(Utterance* utterance) { | |
| 199 utterance->profile()->GetExtensionEventRouter()->DispatchEventToExtension( | |
| 200 utterance->extension_id(), | |
| 201 events::kOnStop, | |
| 202 "[]", | |
| 203 utterance->profile(), | |
| 204 GURL()); | |
| 205 } | |
| 206 | |
| 207 bool ExtensionTtsEngineSendTtsEventFunction::RunImpl() { | |
| 208 int utterance_id; | |
| 209 std::string error_message; | |
| 210 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &utterance_id)); | |
| 211 | |
| 212 DictionaryValue* event; | |
| 213 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &event)); | |
| 214 | |
| 215 std::string event_type; | |
| 216 EXTENSION_FUNCTION_VALIDATE( | |
| 217 event->GetString(constants::kEventTypeKey, &event_type)); | |
| 218 | |
| 219 int char_index = 0; | |
| 220 if (event->HasKey(constants::kCharIndexKey)) { | |
| 221 EXTENSION_FUNCTION_VALIDATE( | |
| 222 event->GetInteger(constants::kCharIndexKey, &char_index)); | |
| 223 } | |
| 224 | |
| 225 // Make sure the extension has included this event type in its manifest. | |
| 226 bool event_type_allowed = false; | |
| 227 const Extension* extension = GetExtension(); | |
| 228 for (size_t i = 0; i < extension->tts_voices().size(); i++) { | |
| 229 const Extension::TtsVoice& voice = extension->tts_voices()[i]; | |
| 230 if (voice.event_types.find(event_type) != voice.event_types.end()) { | |
| 231 event_type_allowed = true; | |
| 232 break; | |
| 233 } | |
| 234 } | |
| 235 if (!event_type_allowed) { | |
| 236 error_ = constants::kErrorUndeclaredEventType; | |
| 237 return false; | |
| 238 } | |
| 239 | |
| 240 ExtensionTtsController* controller = ExtensionTtsController::GetInstance(); | |
| 241 if (event_type == constants::kEventTypeStart) { | |
| 242 controller->OnTtsEvent( | |
| 243 utterance_id, TTS_EVENT_START, char_index, std::string()); | |
| 244 } else if (event_type == constants::kEventTypeEnd) { | |
| 245 controller->OnTtsEvent( | |
| 246 utterance_id, TTS_EVENT_END, char_index, std::string()); | |
| 247 } else if (event_type == constants::kEventTypeWord) { | |
| 248 controller->OnTtsEvent( | |
| 249 utterance_id, TTS_EVENT_WORD, char_index, std::string()); | |
| 250 } else if (event_type == constants::kEventTypeSentence) { | |
| 251 controller->OnTtsEvent( | |
| 252 utterance_id, TTS_EVENT_SENTENCE, char_index, std::string()); | |
| 253 } else if (event_type == constants::kEventTypeMarker) { | |
| 254 controller->OnTtsEvent( | |
| 255 utterance_id, TTS_EVENT_MARKER, char_index, std::string()); | |
| 256 } else if (event_type == constants::kEventTypeError) { | |
| 257 std::string error_message; | |
| 258 event->GetString(constants::kErrorMessageKey, &error_message); | |
| 259 controller->OnTtsEvent( | |
| 260 utterance_id, TTS_EVENT_ERROR, char_index, error_message); | |
| 261 } else { | |
| 262 EXTENSION_FUNCTION_VALIDATE(false); | |
| 263 } | |
| 264 | |
| 265 return true; | |
| 266 } | |
| OLD | NEW |