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.
5 #include "chrome/browser/speech/extension_api/tts_extension_api.h"
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"
19 namespace constants = tts_extension_api_constants;
22 const char kOnEvent[] = "tts.onEvent";
23 }; // namespace events
25 const char *TtsEventTypeToString(TtsEventType event_type) {
28 return constants::kEventTypeStart;
30 return constants::kEventTypeEnd;
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;
42 return constants::kEventTypeError;
44 return constants::kEventTypePause;
45 case TTS_EVENT_RESUME:
46 return constants::kEventTypeResume;
49 return constants::kEventTypeError;
53 TtsEventType TtsEventTypeFromString(const std::string& str) {
54 if (str == constants::kEventTypeStart)
55 return TTS_EVENT_START;
56 if (str == constants::kEventTypeEnd)
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;
76 return TTS_EVENT_ERROR;
79 namespace extensions {
81 // One of these is constructed for each utterance, and deleted
82 // when the utterance gets any final event.
83 class TtsExtensionEventHandler : public UtteranceEventDelegate {
85 virtual void OnTtsEvent(Utterance* utterance,
86 TtsEventType event_type,
88 const std::string& error_message) OVERRIDE;
91 void TtsExtensionEventHandler::OnTtsEvent(Utterance* utterance,
92 TtsEventType event_type,
94 const std::string& error_message) {
95 if (utterance->src_id() < 0) {
96 if (utterance->finished())
101 const std::set<TtsEventType>& desired_event_types =
102 utterance->desired_event_types();
103 if (desired_event_types.size() > 0 &&
104 desired_event_types.find(event_type) == desired_event_types.end()) {
105 if (utterance->finished())
110 const char *event_type_string = TtsEventTypeToString(event_type);
111 scoped_ptr<DictionaryValue> details(new DictionaryValue());
113 details->SetInteger(constants::kCharIndexKey, char_index);
114 details->SetString(constants::kEventTypeKey, event_type_string);
115 if (event_type == TTS_EVENT_ERROR) {
116 details->SetString(constants::kErrorMessageKey, error_message);
118 details->SetInteger(constants::kSrcIdKey, utterance->src_id());
119 details->SetBoolean(constants::kIsFinalEventKey, utterance->finished());
121 scoped_ptr<ListValue> arguments(new ListValue());
122 arguments->Set(0, details.release());
124 scoped_ptr<extensions::Event> event(
125 new extensions::Event(events::kOnEvent, arguments.Pass()));
126 event->restrict_to_profile = utterance->profile();
127 event->event_url = utterance->src_url();
128 extensions::ExtensionSystem::Get(utterance->profile())->event_router()->
129 DispatchEventToExtension(utterance->src_extension_id(), event.Pass());
131 if (utterance->finished())
136 bool TtsSpeakFunction::RunImpl() {
138 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &text));
139 if (text.size() > 32768) {
140 error_ = constants::kErrorUtteranceTooLong;
144 scoped_ptr<DictionaryValue> options(new DictionaryValue());
145 if (args_->GetSize() >= 2) {
146 DictionaryValue* temp_options = NULL;
147 if (args_->GetDictionary(1, &temp_options))
148 options.reset(temp_options->DeepCopy());
151 std::string voice_name;
152 if (options->HasKey(constants::kVoiceNameKey)) {
153 EXTENSION_FUNCTION_VALIDATE(
154 options->GetString(constants::kVoiceNameKey, &voice_name));
158 if (options->HasKey(constants::kLangKey))
159 EXTENSION_FUNCTION_VALIDATE(options->GetString(constants::kLangKey, &lang));
160 if (!lang.empty() && !l10n_util::IsValidLocaleSyntax(lang)) {
161 error_ = constants::kErrorInvalidLang;
165 std::string gender_str;
166 TtsGenderType gender;
167 if (options->HasKey(constants::kGenderKey))
168 EXTENSION_FUNCTION_VALIDATE(
169 options->GetString(constants::kGenderKey, &gender_str));
170 if (gender_str == constants::kGenderMale) {
171 gender = TTS_GENDER_MALE;
172 } else if (gender_str == constants::kGenderFemale) {
173 gender = TTS_GENDER_FEMALE;
174 } else if (gender_str.empty()) {
175 gender = TTS_GENDER_NONE;
177 error_ = constants::kErrorInvalidGender;
182 if (options->HasKey(constants::kRateKey)) {
183 EXTENSION_FUNCTION_VALIDATE(
184 options->GetDouble(constants::kRateKey, &rate));
185 if (rate < 0.1 || rate > 10.0) {
186 error_ = constants::kErrorInvalidRate;
192 if (options->HasKey(constants::kPitchKey)) {
193 EXTENSION_FUNCTION_VALIDATE(
194 options->GetDouble(constants::kPitchKey, &pitch));
195 if (pitch < 0.0 || pitch > 2.0) {
196 error_ = constants::kErrorInvalidPitch;
202 if (options->HasKey(constants::kVolumeKey)) {
203 EXTENSION_FUNCTION_VALIDATE(
204 options->GetDouble(constants::kVolumeKey, &volume));
205 if (volume < 0.0 || volume > 1.0) {
206 error_ = constants::kErrorInvalidVolume;
211 bool can_enqueue = false;
212 if (options->HasKey(constants::kEnqueueKey)) {
213 EXTENSION_FUNCTION_VALIDATE(
214 options->GetBoolean(constants::kEnqueueKey, &can_enqueue));
217 std::set<TtsEventType> required_event_types;
218 if (options->HasKey(constants::kRequiredEventTypesKey)) {
220 EXTENSION_FUNCTION_VALIDATE(
221 options->GetList(constants::kRequiredEventTypesKey, &list));
222 for (size_t i = 0; i < list->GetSize(); ++i) {
223 std::string event_type;
224 if (list->GetString(i, &event_type))
225 required_event_types.insert(TtsEventTypeFromString(event_type.c_str()));
229 std::set<TtsEventType> desired_event_types;
230 if (options->HasKey(constants::kDesiredEventTypesKey)) {
232 EXTENSION_FUNCTION_VALIDATE(
233 options->GetList(constants::kDesiredEventTypesKey, &list));
234 for (size_t i = 0; i < list->GetSize(); ++i) {
235 std::string event_type;
236 if (list->GetString(i, &event_type))
237 desired_event_types.insert(TtsEventTypeFromString(event_type.c_str()));
241 std::string voice_extension_id;
242 if (options->HasKey(constants::kExtensionIdKey)) {
243 EXTENSION_FUNCTION_VALIDATE(
244 options->GetString(constants::kExtensionIdKey, &voice_extension_id));
248 if (options->HasKey(constants::kSrcIdKey)) {
249 EXTENSION_FUNCTION_VALIDATE(
250 options->GetInteger(constants::kSrcIdKey, &src_id));
253 // If we got this far, the arguments were all in the valid format, so
254 // send the success response to the callback now - this ensures that
255 // the callback response always arrives before events, which makes
256 // the behavior more predictable and easier to write unit tests for too.
259 UtteranceContinuousParameters continuous_params;
260 continuous_params.rate = rate;
261 continuous_params.pitch = pitch;
262 continuous_params.volume = volume;
264 Utterance* utterance = new Utterance(GetProfile());
265 utterance->set_text(text);
266 utterance->set_voice_name(voice_name);
267 utterance->set_src_extension_id(extension_id());
268 utterance->set_src_id(src_id);
269 utterance->set_src_url(source_url());
270 utterance->set_lang(lang);
271 utterance->set_gender(gender);
272 utterance->set_continuous_parameters(continuous_params);
273 utterance->set_can_enqueue(can_enqueue);
274 utterance->set_required_event_types(required_event_types);
275 utterance->set_desired_event_types(desired_event_types);
276 utterance->set_extension_id(voice_extension_id);
277 utterance->set_options(options.get());
278 utterance->set_event_delegate(new TtsExtensionEventHandler());
280 TtsController* controller = TtsController::GetInstance();
281 controller->SpeakOrEnqueue(utterance);
285 bool TtsStopSpeakingFunction::RunImpl() {
286 TtsController::GetInstance()->Stop();
290 bool TtsPauseFunction::RunImpl() {
291 TtsController::GetInstance()->Pause();
295 bool TtsResumeFunction::RunImpl() {
296 TtsController::GetInstance()->Resume();
300 bool TtsIsSpeakingFunction::RunImpl() {
301 SetResult(Value::CreateBooleanValue(
302 TtsController::GetInstance()->IsSpeaking()));
306 bool TtsGetVoicesFunction::RunImpl() {
307 std::vector<VoiceData> voices;
308 TtsController::GetInstance()->GetVoices(GetProfile(), &voices);
310 scoped_ptr<ListValue> result_voices(new ListValue());
311 for (size_t i = 0; i < voices.size(); ++i) {
312 const VoiceData& voice = voices[i];
313 DictionaryValue* result_voice = new DictionaryValue();
314 result_voice->SetString(constants::kVoiceNameKey, voice.name);
315 result_voice->SetBoolean(constants::kRemoteKey, voice.remote);
316 if (!voice.lang.empty())
317 result_voice->SetString(constants::kLangKey, voice.lang);
318 if (voice.gender == TTS_GENDER_MALE)
319 result_voice->SetString(constants::kGenderKey, constants::kGenderMale);
320 else if (voice.gender == TTS_GENDER_FEMALE)
321 result_voice->SetString(constants::kGenderKey, constants::kGenderFemale);
322 if (!voice.extension_id.empty())
323 result_voice->SetString(constants::kExtensionIdKey, voice.extension_id);
325 ListValue* event_types = new ListValue();
326 for (std::set<TtsEventType>::iterator iter = voice.events.begin();
327 iter != voice.events.end(); ++iter) {
328 const char* event_name_constant = TtsEventTypeToString(*iter);
329 event_types->Append(Value::CreateStringValue(event_name_constant));
331 result_voice->Set(constants::kEventTypesKey, event_types);
333 result_voices->Append(result_voice);
336 SetResult(result_voices.release());
341 TtsAPI* TtsAPI::Get(Profile* profile) {
342 return ProfileKeyedAPIFactory<TtsAPI>::GetForProfile(profile);
345 TtsAPI::TtsAPI(Profile* profile) {
346 ExtensionFunctionRegistry* registry =
347 ExtensionFunctionRegistry::GetInstance();
348 registry->RegisterFunction<ExtensionTtsEngineSendTtsEventFunction>();
349 registry->RegisterFunction<TtsGetVoicesFunction>();
350 registry->RegisterFunction<TtsIsSpeakingFunction>();
351 registry->RegisterFunction<TtsSpeakFunction>();
352 registry->RegisterFunction<TtsStopSpeakingFunction>();
353 registry->RegisterFunction<TtsPauseFunction>();
354 registry->RegisterFunction<TtsResumeFunction>();
360 static base::LazyInstance<ProfileKeyedAPIFactory<TtsAPI> >
361 g_factory = LAZY_INSTANCE_INITIALIZER;
363 ProfileKeyedAPIFactory<TtsAPI>* TtsAPI::GetFactoryInstance() {
364 return &g_factory.Get();
367 } // namespace extensions