- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / speech / extension_api / tts_extension_api.cc
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     if (utterance->finished())
97       delete this;
98     return;
99   }
100
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())
106       delete this;
107     return;
108   }
109
110   const char *event_type_string = TtsEventTypeToString(event_type);
111   scoped_ptr<DictionaryValue> details(new DictionaryValue());
112   if (char_index >= 0)
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);
117   }
118   details->SetInteger(constants::kSrcIdKey, utterance->src_id());
119   details->SetBoolean(constants::kIsFinalEventKey, utterance->finished());
120
121   scoped_ptr<ListValue> arguments(new ListValue());
122   arguments->Set(0, details.release());
123
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());
130
131   if (utterance->finished())
132     delete this;
133 }
134
135
136 bool TtsSpeakFunction::RunImpl() {
137   std::string text;
138   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &text));
139   if (text.size() > 32768) {
140     error_ = constants::kErrorUtteranceTooLong;
141     return false;
142   }
143
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());
149   }
150
151   std::string voice_name;
152   if (options->HasKey(constants::kVoiceNameKey)) {
153     EXTENSION_FUNCTION_VALIDATE(
154         options->GetString(constants::kVoiceNameKey, &voice_name));
155   }
156
157   std::string lang;
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;
162     return false;
163   }
164
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;
176   } else {
177     error_ = constants::kErrorInvalidGender;
178     return false;
179   }
180
181   double rate = 1.0;
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;
187       return false;
188     }
189   }
190
191   double pitch = 1.0;
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;
197       return false;
198     }
199   }
200
201   double volume = 1.0;
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;
207       return false;
208     }
209   }
210
211   bool can_enqueue = false;
212   if (options->HasKey(constants::kEnqueueKey)) {
213     EXTENSION_FUNCTION_VALIDATE(
214         options->GetBoolean(constants::kEnqueueKey, &can_enqueue));
215   }
216
217   std::set<TtsEventType> required_event_types;
218   if (options->HasKey(constants::kRequiredEventTypesKey)) {
219     ListValue* list;
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()));
226     }
227   }
228
229   std::set<TtsEventType> desired_event_types;
230   if (options->HasKey(constants::kDesiredEventTypesKey)) {
231     ListValue* list;
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()));
238     }
239   }
240
241   std::string voice_extension_id;
242   if (options->HasKey(constants::kExtensionIdKey)) {
243     EXTENSION_FUNCTION_VALIDATE(
244         options->GetString(constants::kExtensionIdKey, &voice_extension_id));
245   }
246
247   int src_id = -1;
248   if (options->HasKey(constants::kSrcIdKey)) {
249     EXTENSION_FUNCTION_VALIDATE(
250         options->GetInteger(constants::kSrcIdKey, &src_id));
251   }
252
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.
257   SendResponse(true);
258
259   UtteranceContinuousParameters continuous_params;
260   continuous_params.rate = rate;
261   continuous_params.pitch = pitch;
262   continuous_params.volume = volume;
263
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());
279
280   TtsController* controller = TtsController::GetInstance();
281   controller->SpeakOrEnqueue(utterance);
282   return true;
283 }
284
285 bool TtsStopSpeakingFunction::RunImpl() {
286   TtsController::GetInstance()->Stop();
287   return true;
288 }
289
290 bool TtsPauseFunction::RunImpl() {
291   TtsController::GetInstance()->Pause();
292   return true;
293 }
294
295 bool TtsResumeFunction::RunImpl() {
296   TtsController::GetInstance()->Resume();
297   return true;
298 }
299
300 bool TtsIsSpeakingFunction::RunImpl() {
301   SetResult(Value::CreateBooleanValue(
302       TtsController::GetInstance()->IsSpeaking()));
303   return true;
304 }
305
306 bool TtsGetVoicesFunction::RunImpl() {
307   std::vector<VoiceData> voices;
308   TtsController::GetInstance()->GetVoices(GetProfile(), &voices);
309
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);
324
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));
330     }
331     result_voice->Set(constants::kEventTypesKey, event_types);
332
333     result_voices->Append(result_voice);
334   }
335
336   SetResult(result_voices.release());
337   return true;
338 }
339
340 // static
341 TtsAPI* TtsAPI::Get(Profile* profile) {
342   return ProfileKeyedAPIFactory<TtsAPI>::GetForProfile(profile);
343 }
344
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>();
355 }
356
357 TtsAPI::~TtsAPI() {
358 }
359
360 static base::LazyInstance<ProfileKeyedAPIFactory<TtsAPI> >
361 g_factory = LAZY_INSTANCE_INITIALIZER;
362
363 ProfileKeyedAPIFactory<TtsAPI>* TtsAPI::GetFactoryInstance() {
364   return &g_factory.Get();
365 }
366
367 }  // namespace extensions