Update To 11.40.268.0
[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/profiles/profile.h"
12 #include "chrome/browser/speech/extension_api/tts_engine_extension_api.h"
13 #include "chrome/browser/speech/extension_api/tts_engine_extension_observer.h"
14 #include "chrome/browser/speech/extension_api/tts_extension_api_constants.h"
15 #include "chrome/browser/speech/tts_controller.h"
16 #include "extensions/browser/event_router.h"
17 #include "extensions/browser/extension_function_registry.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:
87   explicit TtsExtensionEventHandler(const std::string& src_extension_id);
88
89   void OnTtsEvent(Utterance* utterance,
90                   TtsEventType event_type,
91                   int char_index,
92                   const std::string& error_message) override;
93
94  private:
95   // The extension ID of the extension that called speak() and should
96   // receive events.
97   std::string src_extension_id_;
98 };
99
100 TtsExtensionEventHandler::TtsExtensionEventHandler(
101     const std::string& src_extension_id)
102     : src_extension_id_(src_extension_id) {
103 }
104
105 void TtsExtensionEventHandler::OnTtsEvent(Utterance* utterance,
106                                           TtsEventType event_type,
107                                           int char_index,
108                                           const std::string& error_message) {
109   if (utterance->src_id() < 0) {
110     if (utterance->finished())
111       delete this;
112     return;
113   }
114
115   const std::set<TtsEventType>& desired_event_types =
116       utterance->desired_event_types();
117   if (desired_event_types.size() > 0 &&
118       desired_event_types.find(event_type) == desired_event_types.end()) {
119     if (utterance->finished())
120       delete this;
121     return;
122   }
123
124   const char *event_type_string = TtsEventTypeToString(event_type);
125   scoped_ptr<base::DictionaryValue> details(new base::DictionaryValue());
126   if (char_index >= 0)
127     details->SetInteger(constants::kCharIndexKey, char_index);
128   details->SetString(constants::kEventTypeKey, event_type_string);
129   if (event_type == TTS_EVENT_ERROR) {
130     details->SetString(constants::kErrorMessageKey, error_message);
131   }
132   details->SetInteger(constants::kSrcIdKey, utterance->src_id());
133   details->SetBoolean(constants::kIsFinalEventKey, utterance->finished());
134
135   scoped_ptr<base::ListValue> arguments(new base::ListValue());
136   arguments->Set(0, details.release());
137
138   scoped_ptr<extensions::Event> event(
139       new extensions::Event(events::kOnEvent, arguments.Pass()));
140   event->restrict_to_browser_context = utterance->browser_context();
141   event->event_url = utterance->src_url();
142   extensions::EventRouter::Get(utterance->browser_context())
143       ->DispatchEventToExtension(src_extension_id_, event.Pass());
144
145   if (utterance->finished())
146     delete this;
147 }
148
149 bool TtsSpeakFunction::RunAsync() {
150   std::string text;
151   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &text));
152   if (text.size() > 32768) {
153     error_ = constants::kErrorUtteranceTooLong;
154     return false;
155   }
156
157   scoped_ptr<base::DictionaryValue> options(new base::DictionaryValue());
158   if (args_->GetSize() >= 2) {
159     base::DictionaryValue* temp_options = NULL;
160     if (args_->GetDictionary(1, &temp_options))
161       options.reset(temp_options->DeepCopy());
162   }
163
164   std::string voice_name;
165   if (options->HasKey(constants::kVoiceNameKey)) {
166     EXTENSION_FUNCTION_VALIDATE(
167         options->GetString(constants::kVoiceNameKey, &voice_name));
168   }
169
170   std::string lang;
171   if (options->HasKey(constants::kLangKey))
172     EXTENSION_FUNCTION_VALIDATE(options->GetString(constants::kLangKey, &lang));
173   if (!lang.empty() && !l10n_util::IsValidLocaleSyntax(lang)) {
174     error_ = constants::kErrorInvalidLang;
175     return false;
176   }
177
178   std::string gender_str;
179   TtsGenderType gender;
180   if (options->HasKey(constants::kGenderKey))
181     EXTENSION_FUNCTION_VALIDATE(
182         options->GetString(constants::kGenderKey, &gender_str));
183   if (gender_str == constants::kGenderMale) {
184     gender = TTS_GENDER_MALE;
185   } else if (gender_str == constants::kGenderFemale) {
186     gender = TTS_GENDER_FEMALE;
187   } else if (gender_str.empty()) {
188     gender = TTS_GENDER_NONE;
189   } else {
190     error_ = constants::kErrorInvalidGender;
191     return false;
192   }
193
194   double rate = 1.0;
195   if (options->HasKey(constants::kRateKey)) {
196     EXTENSION_FUNCTION_VALIDATE(
197         options->GetDouble(constants::kRateKey, &rate));
198     if (rate < 0.1 || rate > 10.0) {
199       error_ = constants::kErrorInvalidRate;
200       return false;
201     }
202   }
203
204   double pitch = 1.0;
205   if (options->HasKey(constants::kPitchKey)) {
206     EXTENSION_FUNCTION_VALIDATE(
207         options->GetDouble(constants::kPitchKey, &pitch));
208     if (pitch < 0.0 || pitch > 2.0) {
209       error_ = constants::kErrorInvalidPitch;
210       return false;
211     }
212   }
213
214   double volume = 1.0;
215   if (options->HasKey(constants::kVolumeKey)) {
216     EXTENSION_FUNCTION_VALIDATE(
217         options->GetDouble(constants::kVolumeKey, &volume));
218     if (volume < 0.0 || volume > 1.0) {
219       error_ = constants::kErrorInvalidVolume;
220       return false;
221     }
222   }
223
224   bool can_enqueue = false;
225   if (options->HasKey(constants::kEnqueueKey)) {
226     EXTENSION_FUNCTION_VALIDATE(
227         options->GetBoolean(constants::kEnqueueKey, &can_enqueue));
228   }
229
230   std::set<TtsEventType> required_event_types;
231   if (options->HasKey(constants::kRequiredEventTypesKey)) {
232     base::ListValue* list;
233     EXTENSION_FUNCTION_VALIDATE(
234         options->GetList(constants::kRequiredEventTypesKey, &list));
235     for (size_t i = 0; i < list->GetSize(); ++i) {
236       std::string event_type;
237       if (list->GetString(i, &event_type))
238         required_event_types.insert(TtsEventTypeFromString(event_type.c_str()));
239     }
240   }
241
242   std::set<TtsEventType> desired_event_types;
243   if (options->HasKey(constants::kDesiredEventTypesKey)) {
244     base::ListValue* list;
245     EXTENSION_FUNCTION_VALIDATE(
246         options->GetList(constants::kDesiredEventTypesKey, &list));
247     for (size_t i = 0; i < list->GetSize(); ++i) {
248       std::string event_type;
249       if (list->GetString(i, &event_type))
250         desired_event_types.insert(TtsEventTypeFromString(event_type.c_str()));
251     }
252   }
253
254   std::string voice_extension_id;
255   if (options->HasKey(constants::kExtensionIdKey)) {
256     EXTENSION_FUNCTION_VALIDATE(
257         options->GetString(constants::kExtensionIdKey, &voice_extension_id));
258   }
259
260   int src_id = -1;
261   if (options->HasKey(constants::kSrcIdKey)) {
262     EXTENSION_FUNCTION_VALIDATE(
263         options->GetInteger(constants::kSrcIdKey, &src_id));
264   }
265
266   // If we got this far, the arguments were all in the valid format, so
267   // send the success response to the callback now - this ensures that
268   // the callback response always arrives before events, which makes
269   // the behavior more predictable and easier to write unit tests for too.
270   SendResponse(true);
271
272   UtteranceContinuousParameters continuous_params;
273   continuous_params.rate = rate;
274   continuous_params.pitch = pitch;
275   continuous_params.volume = volume;
276
277   Utterance* utterance = new Utterance(GetProfile());
278   utterance->set_text(text);
279   utterance->set_voice_name(voice_name);
280   utterance->set_src_id(src_id);
281   utterance->set_src_url(source_url());
282   utterance->set_lang(lang);
283   utterance->set_gender(gender);
284   utterance->set_continuous_parameters(continuous_params);
285   utterance->set_can_enqueue(can_enqueue);
286   utterance->set_required_event_types(required_event_types);
287   utterance->set_desired_event_types(desired_event_types);
288   utterance->set_extension_id(voice_extension_id);
289   utterance->set_options(options.get());
290   utterance->set_event_delegate(new TtsExtensionEventHandler(extension_id()));
291
292   TtsController* controller = TtsController::GetInstance();
293   controller->SpeakOrEnqueue(utterance);
294   return true;
295 }
296
297 bool TtsStopSpeakingFunction::RunSync() {
298   TtsController::GetInstance()->Stop();
299   return true;
300 }
301
302 bool TtsPauseFunction::RunSync() {
303   TtsController::GetInstance()->Pause();
304   return true;
305 }
306
307 bool TtsResumeFunction::RunSync() {
308   TtsController::GetInstance()->Resume();
309   return true;
310 }
311
312 bool TtsIsSpeakingFunction::RunSync() {
313   SetResult(
314       new base::FundamentalValue(TtsController::GetInstance()->IsSpeaking()));
315   return true;
316 }
317
318 bool TtsGetVoicesFunction::RunSync() {
319   std::vector<VoiceData> voices;
320   TtsController::GetInstance()->GetVoices(GetProfile(), &voices);
321
322   scoped_ptr<base::ListValue> result_voices(new base::ListValue());
323   for (size_t i = 0; i < voices.size(); ++i) {
324     const VoiceData& voice = voices[i];
325     base::DictionaryValue* result_voice = new base::DictionaryValue();
326     result_voice->SetString(constants::kVoiceNameKey, voice.name);
327     result_voice->SetBoolean(constants::kRemoteKey, voice.remote);
328     if (!voice.lang.empty())
329       result_voice->SetString(constants::kLangKey, voice.lang);
330     if (voice.gender == TTS_GENDER_MALE)
331       result_voice->SetString(constants::kGenderKey, constants::kGenderMale);
332     else if (voice.gender == TTS_GENDER_FEMALE)
333       result_voice->SetString(constants::kGenderKey, constants::kGenderFemale);
334     if (!voice.extension_id.empty())
335       result_voice->SetString(constants::kExtensionIdKey, voice.extension_id);
336
337     base::ListValue* event_types = new base::ListValue();
338     for (std::set<TtsEventType>::iterator iter = voice.events.begin();
339          iter != voice.events.end(); ++iter) {
340       const char* event_name_constant = TtsEventTypeToString(*iter);
341       event_types->Append(new base::StringValue(event_name_constant));
342     }
343     result_voice->Set(constants::kEventTypesKey, event_types);
344
345     result_voices->Append(result_voice);
346   }
347
348   SetResult(result_voices.release());
349   return true;
350 }
351
352 TtsAPI::TtsAPI(content::BrowserContext* context) {
353   ExtensionFunctionRegistry* registry =
354       ExtensionFunctionRegistry::GetInstance();
355   registry->RegisterFunction<ExtensionTtsEngineSendTtsEventFunction>();
356   registry->RegisterFunction<TtsGetVoicesFunction>();
357   registry->RegisterFunction<TtsIsSpeakingFunction>();
358   registry->RegisterFunction<TtsSpeakFunction>();
359   registry->RegisterFunction<TtsStopSpeakingFunction>();
360   registry->RegisterFunction<TtsPauseFunction>();
361   registry->RegisterFunction<TtsResumeFunction>();
362
363   // Ensure we're observing newly added engines for the given context.
364   TtsEngineExtensionObserver::GetInstance(Profile::FromBrowserContext(context));
365 }
366
367 TtsAPI::~TtsAPI() {
368 }
369
370 static base::LazyInstance<BrowserContextKeyedAPIFactory<TtsAPI> > g_factory =
371     LAZY_INSTANCE_INITIALIZER;
372
373 BrowserContextKeyedAPIFactory<TtsAPI>* TtsAPI::GetFactoryInstance() {
374   return g_factory.Pointer();
375 }
376
377 }  // namespace extensions