Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(312)

Side by Side Diff: chrome/browser/extensions/extension_tts_api_controller.cc

Issue 9808024: Move TTS extension API to chrome/browser/speech/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix chromeos compile error, rebase Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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_api_controller.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/float_util.h"
11 #include "base/json/json_writer.h"
12 #include "base/values.h"
13 #include "chrome/browser/extensions/extension_event_router.h"
14 #include "chrome/browser/extensions/extension_tts_api.h"
15 #include "chrome/browser/extensions/extension_tts_api_constants.h"
16 #include "chrome/browser/extensions/extension_tts_api_platform.h"
17 #include "chrome/browser/extensions/extension_tts_engine_api.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/common/extensions/extension.h"
20
21 namespace constants = extension_tts_api_constants;
22
23 namespace {
24
25 // A value to be used to indicate that there is no char index available.
26 const int kInvalidCharIndex = -1;
27
28 namespace events {
29 const char kOnEvent[] = "tts.onEvent";
30 }; // namespace events
31
32 std::string TtsEventTypeToString(TtsEventType event_type) {
33 switch (event_type) {
34 case TTS_EVENT_START:
35 return constants::kEventTypeStart;
36 case TTS_EVENT_END:
37 return constants::kEventTypeEnd;
38 case TTS_EVENT_WORD:
39 return constants::kEventTypeWord;
40 case TTS_EVENT_SENTENCE:
41 return constants::kEventTypeSentence;
42 case TTS_EVENT_MARKER:
43 return constants::kEventTypeMarker;
44 case TTS_EVENT_INTERRUPTED:
45 return constants::kEventTypeInterrupted;
46 case TTS_EVENT_CANCELLED:
47 return constants::kEventTypeCancelled;
48 case TTS_EVENT_ERROR:
49 return constants::kEventTypeError;
50 default:
51 NOTREACHED();
52 return std::string();
53 }
54 }
55
56 } // namespace
57
58 //
59 // UtteranceContinuousParameters
60 //
61
62
63 UtteranceContinuousParameters::UtteranceContinuousParameters()
64 : rate(-1),
65 pitch(-1),
66 volume(-1) {}
67
68
69 //
70 // Utterance
71 //
72
73 // static
74 int Utterance::next_utterance_id_ = 0;
75
76 Utterance::Utterance(Profile* profile)
77 : profile_(profile),
78 id_(next_utterance_id_++),
79 src_id_(-1),
80 can_enqueue_(false),
81 char_index_(0),
82 finished_(false) {
83 options_.reset(new DictionaryValue());
84 }
85
86 Utterance::~Utterance() {
87 DCHECK(finished_);
88 }
89
90 void Utterance::OnTtsEvent(TtsEventType event_type,
91 int char_index,
92 const std::string& error_message) {
93 std::string event_type_string = TtsEventTypeToString(event_type);
94 if (char_index >= 0)
95 char_index_ = char_index;
96 if (event_type == TTS_EVENT_END ||
97 event_type == TTS_EVENT_INTERRUPTED ||
98 event_type == TTS_EVENT_CANCELLED ||
99 event_type == TTS_EVENT_ERROR) {
100 finished_ = true;
101 }
102 if (desired_event_types_.size() > 0 &&
103 desired_event_types_.find(event_type_string) ==
104 desired_event_types_.end()) {
105 return;
106 }
107
108 if (src_id_ < 0)
109 return;
110
111 ListValue args;
112 DictionaryValue* event = new DictionaryValue();
113 if (char_index != kInvalidCharIndex)
114 event->SetInteger(constants::kCharIndexKey, char_index);
115 event->SetString(constants::kEventTypeKey, event_type_string);
116 if (event_type == TTS_EVENT_ERROR) {
117 event->SetString(constants::kErrorMessageKey, error_message);
118 }
119 event->SetInteger(constants::kSrcIdKey, src_id_);
120 event->SetBoolean(constants::kIsFinalEventKey, finished_);
121 args.Set(0, event);
122 std::string json_args;
123 base::JSONWriter::Write(&args, &json_args);
124
125 profile_->GetExtensionEventRouter()->DispatchEventToExtension(
126 src_extension_id_,
127 events::kOnEvent,
128 json_args,
129 profile_,
130 src_url_);
131 }
132
133 void Utterance::Finish() {
134 finished_ = true;
135 }
136
137 void Utterance::set_options(const Value* options) {
138 options_.reset(options->DeepCopy());
139 }
140
141 //
142 // ExtensionTtsController
143 //
144
145 // static
146 ExtensionTtsController* ExtensionTtsController::GetInstance() {
147 return Singleton<ExtensionTtsController>::get();
148 }
149
150 ExtensionTtsController::ExtensionTtsController()
151 : current_utterance_(NULL),
152 platform_impl_(NULL) {
153 }
154
155 ExtensionTtsController::~ExtensionTtsController() {
156 if (current_utterance_) {
157 current_utterance_->Finish();
158 delete current_utterance_;
159 }
160
161 // Clear any queued utterances too.
162 ClearUtteranceQueue(false); // Don't sent events.
163 }
164
165 void ExtensionTtsController::SpeakOrEnqueue(Utterance* utterance) {
166 if (IsSpeaking() && utterance->can_enqueue()) {
167 utterance_queue_.push(utterance);
168 } else {
169 Stop();
170 SpeakNow(utterance);
171 }
172 }
173
174 void ExtensionTtsController::SpeakNow(Utterance* utterance) {
175 const Extension* extension;
176 size_t voice_index;
177 if (GetMatchingExtensionVoice(utterance, &extension, &voice_index)) {
178 current_utterance_ = utterance;
179 utterance->set_extension_id(extension->id());
180
181 ExtensionTtsEngineSpeak(utterance, extension, voice_index);
182
183 const std::set<std::string> event_types =
184 extension->tts_voices()[voice_index].event_types;
185 bool sends_end_event =
186 (event_types.find(constants::kEventTypeEnd) != event_types.end());
187 if (!sends_end_event) {
188 utterance->Finish();
189 delete utterance;
190 current_utterance_ = NULL;
191 SpeakNextUtterance();
192 }
193 return;
194 }
195
196 GetPlatformImpl()->clear_error();
197 bool success = GetPlatformImpl()->Speak(
198 utterance->id(),
199 utterance->text(),
200 utterance->lang(),
201 utterance->continuous_parameters());
202 if (!success) {
203 utterance->OnTtsEvent(TTS_EVENT_ERROR, kInvalidCharIndex,
204 GetPlatformImpl()->error());
205 delete utterance;
206 return;
207 }
208 current_utterance_ = utterance;
209 }
210
211 void ExtensionTtsController::Stop() {
212 if (current_utterance_ && !current_utterance_->extension_id().empty()) {
213 ExtensionTtsEngineStop(current_utterance_);
214 } else {
215 GetPlatformImpl()->clear_error();
216 GetPlatformImpl()->StopSpeaking();
217 }
218
219 if (current_utterance_)
220 current_utterance_->OnTtsEvent(TTS_EVENT_INTERRUPTED, kInvalidCharIndex,
221 std::string());
222 FinishCurrentUtterance();
223 ClearUtteranceQueue(true); // Send events.
224 }
225
226 void ExtensionTtsController::OnTtsEvent(int utterance_id,
227 TtsEventType event_type,
228 int char_index,
229 const std::string& error_message) {
230 // We may sometimes receive completion callbacks "late", after we've
231 // already finished the utterance (for example because another utterance
232 // interrupted or we got a call to Stop). This is normal and we can
233 // safely just ignore these events.
234 if (!current_utterance_ || utterance_id != current_utterance_->id())
235 return;
236
237 current_utterance_->OnTtsEvent(event_type, char_index, error_message);
238 if (current_utterance_->finished()) {
239 FinishCurrentUtterance();
240 SpeakNextUtterance();
241 }
242 }
243
244 ListValue* ExtensionTtsController::GetVoices(Profile* profile) {
245 ListValue* result_voices = new ListValue();
246 ExtensionTtsPlatformImpl* platform_impl = GetPlatformImpl();
247 if (platform_impl && platform_impl->PlatformImplAvailable()) {
248 DictionaryValue* result_voice = new DictionaryValue();
249 result_voice->SetString(
250 constants::kVoiceNameKey, constants::kNativeVoiceName);
251 if (!platform_impl->gender().empty())
252 result_voice->SetString(constants::kGenderKey, platform_impl->gender());
253 ListValue* event_types = new ListValue();
254
255 // All platforms must send end events, and cancelled and interrupted
256 // events are generated from the controller.
257 DCHECK(platform_impl->SendsEvent(TTS_EVENT_END));
258 event_types->Append(Value::CreateStringValue(constants::kEventTypeEnd));
259 event_types->Append(Value::CreateStringValue(
260 constants::kEventTypeCancelled));
261 event_types->Append(Value::CreateStringValue(
262 constants::kEventTypeInterrupted));
263
264 if (platform_impl->SendsEvent(TTS_EVENT_START))
265 event_types->Append(Value::CreateStringValue(constants::kEventTypeStart));
266 if (platform_impl->SendsEvent(TTS_EVENT_WORD))
267 event_types->Append(Value::CreateStringValue(constants::kEventTypeWord));
268 if (platform_impl->SendsEvent(TTS_EVENT_SENTENCE))
269 event_types->Append(Value::CreateStringValue(
270 constants::kEventTypeSentence));
271 if (platform_impl->SendsEvent(TTS_EVENT_MARKER))
272 event_types->Append(Value::CreateStringValue(
273 constants::kEventTypeMarker));
274 if (platform_impl->SendsEvent(TTS_EVENT_ERROR))
275 event_types->Append(Value::CreateStringValue(
276 constants::kEventTypeError));
277 result_voice->Set(constants::kEventTypesKey, event_types);
278 result_voices->Append(result_voice);
279 }
280
281 GetExtensionVoices(profile, result_voices);
282
283 return result_voices;
284 }
285
286 bool ExtensionTtsController::IsSpeaking() const {
287 return current_utterance_ != NULL;
288 }
289
290 void ExtensionTtsController::FinishCurrentUtterance() {
291 if (current_utterance_) {
292 if (!current_utterance_->finished())
293 current_utterance_->OnTtsEvent(TTS_EVENT_INTERRUPTED, kInvalidCharIndex,
294 std::string());
295 delete current_utterance_;
296 current_utterance_ = NULL;
297 }
298 }
299
300 void ExtensionTtsController::SpeakNextUtterance() {
301 // Start speaking the next utterance in the queue. Keep trying in case
302 // one fails but there are still more in the queue to try.
303 while (!utterance_queue_.empty() && !current_utterance_) {
304 Utterance* utterance = utterance_queue_.front();
305 utterance_queue_.pop();
306 SpeakNow(utterance);
307 }
308 }
309
310 void ExtensionTtsController::ClearUtteranceQueue(bool send_events) {
311 while (!utterance_queue_.empty()) {
312 Utterance* utterance = utterance_queue_.front();
313 utterance_queue_.pop();
314 if (send_events)
315 utterance->OnTtsEvent(TTS_EVENT_CANCELLED, kInvalidCharIndex,
316 std::string());
317 else
318 utterance->Finish();
319 delete utterance;
320 }
321 }
322
323 void ExtensionTtsController::SetPlatformImpl(
324 ExtensionTtsPlatformImpl* platform_impl) {
325 platform_impl_ = platform_impl;
326 }
327
328 int ExtensionTtsController::QueueSize() {
329 return static_cast<int>(utterance_queue_.size());
330 }
331
332 ExtensionTtsPlatformImpl* ExtensionTtsController::GetPlatformImpl() {
333 if (!platform_impl_)
334 platform_impl_ = ExtensionTtsPlatformImpl::GetInstance();
335 return platform_impl_;
336 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698