Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / speech / extension_api / tts_engine_extension_api.cc
blob9390ea2ecdef88edcd2ab3e89ea78e4405cbed3b
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_engine_extension_api.h"
7 #include <string>
9 #include "base/json/json_writer.h"
10 #include "base/values.h"
11 #include "chrome/browser/extensions/extension_host.h"
12 #include "chrome/browser/extensions/extension_service.h"
13 #include "chrome/browser/extensions/extension_system.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/speech/extension_api/tts_extension_api.h"
16 #include "chrome/browser/speech/extension_api/tts_extension_api_constants.h"
17 #include "chrome/browser/speech/tts_controller.h"
18 #include "chrome/common/extensions/api/speech/tts_engine_manifest_handler.h"
19 #include "chrome/common/extensions/extension_messages.h"
20 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "content/public/common/console_message_level.h"
23 #include "extensions/browser/event_router.h"
24 #include "extensions/browser/process_manager.h"
25 #include "extensions/common/extension.h"
26 #include "extensions/common/extension_set.h"
27 #include "net/base/network_change_notifier.h"
29 using extensions::EventRouter;
30 using extensions::Extension;
31 using extensions::ExtensionSystem;
33 namespace constants = tts_extension_api_constants;
35 namespace tts_engine_events {
36 const char kOnSpeak[] = "ttsEngine.onSpeak";
37 const char kOnStop[] = "ttsEngine.onStop";
38 const char kOnPause[] = "ttsEngine.onPause";
39 const char kOnResume[] = "ttsEngine.onResume";
40 }; // namespace tts_engine_events
42 namespace {
43 void WarnIfMissingPauseOrResumeListener(
44 Profile* profile, EventRouter* event_router, std::string extension_id) {
45 bool has_onpause = event_router->ExtensionHasEventListener(
46 extension_id, tts_engine_events::kOnPause);
47 bool has_onresume = event_router->ExtensionHasEventListener(
48 extension_id, tts_engine_events::kOnResume);
49 if (has_onpause == has_onresume)
50 return;
52 extensions::ProcessManager* process_manager =
53 ExtensionSystem::Get(profile)->process_manager();
54 extensions::ExtensionHost* host =
55 process_manager->GetBackgroundHostForExtension(extension_id);
56 host->render_process_host()->Send(new ExtensionMsg_AddMessageToConsole(
57 host->render_view_host()->GetRoutingID(),
58 content::CONSOLE_MESSAGE_LEVEL_WARNING,
59 constants::kErrorMissingPauseOrResume));
61 } // anonymous namespace
63 void GetExtensionVoices(Profile* profile, std::vector<VoiceData>* out_voices) {
64 ExtensionService* service = profile->GetExtensionService();
65 DCHECK(service);
66 EventRouter* event_router =
67 ExtensionSystem::Get(profile)->event_router();
68 DCHECK(event_router);
70 bool is_offline = (net::NetworkChangeNotifier::GetConnectionType() ==
71 net::NetworkChangeNotifier::CONNECTION_NONE);
73 const extensions::ExtensionSet* extensions = service->extensions();
74 extensions::ExtensionSet::const_iterator iter;
75 for (iter = extensions->begin(); iter != extensions->end(); ++iter) {
76 const Extension* extension = iter->get();
78 if (!event_router->ExtensionHasEventListener(
79 extension->id(), tts_engine_events::kOnSpeak) ||
80 !event_router->ExtensionHasEventListener(
81 extension->id(), tts_engine_events::kOnStop)) {
82 continue;
85 const std::vector<extensions::TtsVoice>* tts_voices =
86 extensions::TtsVoice::GetTtsVoices(extension);
87 if (!tts_voices)
88 continue;
90 for (size_t i = 0; i < tts_voices->size(); ++i) {
91 const extensions::TtsVoice& voice = tts_voices->at(i);
93 // Don't return remote voices when the system is offline.
94 if (voice.remote && is_offline)
95 continue;
97 out_voices->push_back(VoiceData());
98 VoiceData& result_voice = out_voices->back();
100 result_voice.native = false;
101 result_voice.name = voice.voice_name;
102 result_voice.lang = voice.lang;
103 result_voice.remote = voice.remote;
104 result_voice.extension_id = extension->id();
105 if (voice.gender == constants::kGenderMale)
106 result_voice.gender = TTS_GENDER_MALE;
107 else if (voice.gender == constants::kGenderFemale)
108 result_voice.gender = TTS_GENDER_FEMALE;
109 else
110 result_voice.gender = TTS_GENDER_NONE;
112 for (std::set<std::string>::const_iterator iter =
113 voice.event_types.begin();
114 iter != voice.event_types.end();
115 ++iter) {
116 result_voice.events.insert(TtsEventTypeFromString(*iter));
119 // If the extension sends end events, the controller will handle
120 // queueing and send interrupted and cancelled events.
121 if (voice.event_types.find(constants::kEventTypeEnd) !=
122 voice.event_types.end()) {
123 result_voice.events.insert(TTS_EVENT_CANCELLED);
124 result_voice.events.insert(TTS_EVENT_INTERRUPTED);
130 void ExtensionTtsEngineSpeak(Utterance* utterance, const VoiceData& voice) {
131 // See if the engine supports the "end" event; if so, we can keep the
132 // utterance around and track it. If not, we're finished with this
133 // utterance now.
134 bool sends_end_event = voice.events.find(TTS_EVENT_END) != voice.events.end();
136 scoped_ptr<base::ListValue> args(new base::ListValue());
137 args->Set(0, base::Value::CreateStringValue(utterance->text()));
139 // Pass through most options to the speech engine, but remove some
140 // that are handled internally.
141 scoped_ptr<base::DictionaryValue> options(static_cast<base::DictionaryValue*>(
142 utterance->options()->DeepCopy()));
143 if (options->HasKey(constants::kRequiredEventTypesKey))
144 options->Remove(constants::kRequiredEventTypesKey, NULL);
145 if (options->HasKey(constants::kDesiredEventTypesKey))
146 options->Remove(constants::kDesiredEventTypesKey, NULL);
147 if (sends_end_event && options->HasKey(constants::kEnqueueKey))
148 options->Remove(constants::kEnqueueKey, NULL);
149 if (options->HasKey(constants::kSrcIdKey))
150 options->Remove(constants::kSrcIdKey, NULL);
151 if (options->HasKey(constants::kIsFinalEventKey))
152 options->Remove(constants::kIsFinalEventKey, NULL);
153 if (options->HasKey(constants::kOnEventKey))
154 options->Remove(constants::kOnEventKey, NULL);
156 // Add the voice name and language to the options if they're not
157 // already there, since they might have been picked by the TTS controller
158 // rather than directly by the client that requested the speech.
159 if (!options->HasKey(constants::kVoiceNameKey))
160 options->SetString(constants::kVoiceNameKey, voice.name);
161 if (!options->HasKey(constants::kLangKey))
162 options->SetString(constants::kLangKey, voice.lang);
164 args->Set(1, options.release());
165 args->Set(2, base::Value::CreateIntegerValue(utterance->id()));
167 scoped_ptr<extensions::Event> event(new extensions::Event(
168 tts_engine_events::kOnSpeak, args.Pass()));
169 event->restrict_to_browser_context = utterance->profile();
170 ExtensionSystem::Get(utterance->profile())->event_router()->
171 DispatchEventToExtension(utterance->extension_id(), event.Pass());
174 void ExtensionTtsEngineStop(Utterance* utterance) {
175 scoped_ptr<base::ListValue> args(new base::ListValue());
176 scoped_ptr<extensions::Event> event(new extensions::Event(
177 tts_engine_events::kOnStop, args.Pass()));
178 event->restrict_to_browser_context = utterance->profile();
179 ExtensionSystem::Get(utterance->profile())->event_router()->
180 DispatchEventToExtension(utterance->extension_id(), event.Pass());
183 void ExtensionTtsEnginePause(Utterance* utterance) {
184 scoped_ptr<base::ListValue> args(new base::ListValue());
185 scoped_ptr<extensions::Event> event(new extensions::Event(
186 tts_engine_events::kOnPause, args.Pass()));
187 Profile* profile = utterance->profile();
188 event->restrict_to_browser_context = profile;
189 EventRouter* event_router = ExtensionSystem::Get(profile)->event_router();
190 std::string id = utterance->extension_id();
191 event_router->DispatchEventToExtension(id, event.Pass());
192 WarnIfMissingPauseOrResumeListener(profile, event_router, id);
195 void ExtensionTtsEngineResume(Utterance* utterance) {
196 scoped_ptr<base::ListValue> args(new base::ListValue());
197 scoped_ptr<extensions::Event> event(new extensions::Event(
198 tts_engine_events::kOnResume, args.Pass()));
199 Profile* profile = utterance->profile();
200 event->restrict_to_browser_context = profile;
201 EventRouter* event_router = ExtensionSystem::Get(profile)->event_router();
202 std::string id = utterance->extension_id();
203 event_router->DispatchEventToExtension(id, event.Pass());
204 WarnIfMissingPauseOrResumeListener(profile, event_router, id);
207 bool ExtensionTtsEngineSendTtsEventFunction::RunImpl() {
208 int utterance_id;
209 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &utterance_id));
211 base::DictionaryValue* event;
212 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &event));
214 std::string event_type;
215 EXTENSION_FUNCTION_VALIDATE(
216 event->GetString(constants::kEventTypeKey, &event_type));
218 int char_index = 0;
219 if (event->HasKey(constants::kCharIndexKey)) {
220 EXTENSION_FUNCTION_VALIDATE(
221 event->GetInteger(constants::kCharIndexKey, &char_index));
224 // Make sure the extension has included this event type in its manifest.
225 bool event_type_allowed = false;
226 const Extension* extension = GetExtension();
227 const std::vector<extensions::TtsVoice>* tts_voices =
228 extensions::TtsVoice::GetTtsVoices(extension);
229 if (!tts_voices) {
230 error_ = constants::kErrorUndeclaredEventType;
231 return false;
234 for (size_t i = 0; i < tts_voices->size(); i++) {
235 const extensions::TtsVoice& voice = tts_voices->at(i);
236 if (voice.event_types.find(event_type) != voice.event_types.end()) {
237 event_type_allowed = true;
238 break;
241 if (!event_type_allowed) {
242 error_ = constants::kErrorUndeclaredEventType;
243 return false;
246 TtsController* controller = TtsController::GetInstance();
247 if (event_type == constants::kEventTypeStart) {
248 controller->OnTtsEvent(
249 utterance_id, TTS_EVENT_START, char_index, std::string());
250 } else if (event_type == constants::kEventTypeEnd) {
251 controller->OnTtsEvent(
252 utterance_id, TTS_EVENT_END, char_index, std::string());
253 } else if (event_type == constants::kEventTypeWord) {
254 controller->OnTtsEvent(
255 utterance_id, TTS_EVENT_WORD, char_index, std::string());
256 } else if (event_type == constants::kEventTypeSentence) {
257 controller->OnTtsEvent(
258 utterance_id, TTS_EVENT_SENTENCE, char_index, std::string());
259 } else if (event_type == constants::kEventTypeMarker) {
260 controller->OnTtsEvent(
261 utterance_id, TTS_EVENT_MARKER, char_index, std::string());
262 } else if (event_type == constants::kEventTypeError) {
263 std::string error_message;
264 event->GetString(constants::kErrorMessageKey, &error_message);
265 controller->OnTtsEvent(
266 utterance_id, TTS_EVENT_ERROR, char_index, error_message);
267 } else if (event_type == constants::kEventTypePause) {
268 controller->OnTtsEvent(
269 utterance_id, TTS_EVENT_PAUSE, char_index, std::string());
270 } else if (event_type == constants::kEventTypeResume) {
271 controller->OnTtsEvent(
272 utterance_id, TTS_EVENT_RESUME, char_index, std::string());
273 } else {
274 EXTENSION_FUNCTION_VALIDATE(false);
277 return true;