Chromium Code Reviews| Index: chrome/browser/speech/extension_api/tts_extension_api.cc |
| diff --git a/chrome/browser/speech/extension_api/tts_extension_api.cc b/chrome/browser/speech/extension_api/tts_extension_api.cc |
| index 96ca3e17770c9bf889532dc03b5513b151bbf7d5..f3a6e08a5e93dbb0e2a6c67642e019bc42968166 100644 |
| --- a/chrome/browser/speech/extension_api/tts_extension_api.cc |
| +++ b/chrome/browser/speech/extension_api/tts_extension_api.cc |
| @@ -8,6 +8,7 @@ |
| #include "base/lazy_instance.h" |
| #include "base/values.h" |
| +#include "chrome/browser/extensions/event_router.h" |
| #include "chrome/browser/extensions/extension_function_registry.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/speech/extension_api/tts_engine_extension_api.h" |
| @@ -18,8 +19,91 @@ |
| namespace constants = tts_extension_api_constants; |
| +namespace events { |
| + const char kOnEvent[] = "tts.onEvent"; |
| +}; // namespace events |
| + |
| +namespace { |
| + |
| +std::string TtsEventTypeToString(TtsEventType event_type) { |
|
tommi (sloooow) - chröme
2013/03/07 13:04:46
nit: is there a reason for returning a string obje
dmazzoni
2013/03/19 17:30:22
Changed to const char *, that way no string copyin
|
| + switch (event_type) { |
| + case TTS_EVENT_START: |
| + return constants::kEventTypeStart; |
| + case TTS_EVENT_END: |
| + return constants::kEventTypeEnd; |
| + case TTS_EVENT_WORD: |
| + return constants::kEventTypeWord; |
| + case TTS_EVENT_SENTENCE: |
| + return constants::kEventTypeSentence; |
| + case TTS_EVENT_MARKER: |
| + return constants::kEventTypeMarker; |
| + case TTS_EVENT_INTERRUPTED: |
| + return constants::kEventTypeInterrupted; |
| + case TTS_EVENT_CANCELLED: |
| + return constants::kEventTypeCancelled; |
| + case TTS_EVENT_ERROR: |
| + return constants::kEventTypeError; |
| + default: |
| + NOTREACHED(); |
| + return std::string(); |
| + } |
| +} |
| + |
| +} // anonymous namespace |
| + |
| namespace extensions { |
| +// One of these is constructed for each utterance, and deleted |
| +// when the utterance gets any final event. |
| +class TtsExtensionEventHandler : public UtteranceEventDelegate { |
| + public: |
| + virtual void OnTtsEvent(Utterance* utterance, |
| + TtsEventType event_type, |
| + int char_index, |
| + const std::string& error_message) OVERRIDE; |
| +}; |
| + |
| +void TtsExtensionEventHandler::OnTtsEvent(Utterance* utterance, |
| + TtsEventType event_type, |
| + int char_index, |
| + const std::string& error_message) { |
| + if (utterance->src_id() < 0) |
| + return; |
| + |
| + std::string event_type_string = TtsEventTypeToString(event_type); |
| + const std::set<std::string>& desired_event_types = |
| + utterance->desired_event_types(); |
| + if (desired_event_types.size() > 0 && |
| + desired_event_types.find(event_type_string) == |
| + desired_event_types.end()) { |
| + return; |
| + } |
| + |
| + DictionaryValue* details = new DictionaryValue(); |
|
hans
2013/03/09 14:19:52
maybe make this a scoped_ptr?
dmazzoni
2013/03/19 17:30:22
Done.
|
| + if (char_index >= 0) |
| + details->SetInteger(constants::kCharIndexKey, char_index); |
| + details->SetString(constants::kEventTypeKey, event_type_string); |
| + if (event_type == TTS_EVENT_ERROR) { |
| + details->SetString(constants::kErrorMessageKey, error_message); |
| + } |
| + details->SetInteger(constants::kSrcIdKey, utterance->src_id()); |
| + details->SetBoolean(constants::kIsFinalEventKey, utterance->finished()); |
| + |
| + scoped_ptr<ListValue> arguments(new ListValue()); |
| + arguments->Set(0, details); |
| + |
| + scoped_ptr<extensions::Event> event( |
| + new extensions::Event(events::kOnEvent, arguments.Pass())); |
| + event->restrict_to_profile = utterance->profile(); |
| + event->event_url = utterance->src_url(); |
| + extensions::ExtensionSystem::Get(utterance->profile())->event_router()-> |
| + DispatchEventToExtension(utterance->src_extension_id(), event.Pass()); |
| + |
| + if (utterance->finished()) |
| + delete this; |
|
tommi (sloooow) - chröme
2013/03/07 13:04:46
thinking out loud here - is there some way for us
dmazzoni
2013/03/19 17:30:22
Since TTS spans processes, we use a simple convent
|
| +} |
| + |
| + |
| bool TtsSpeakFunction::RunImpl() { |
| std::string text; |
| EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &text)); |
| @@ -157,6 +241,7 @@ bool TtsSpeakFunction::RunImpl() { |
| utterance->set_desired_event_types(desired_event_types); |
| utterance->set_extension_id(voice_extension_id); |
| utterance->set_options(options.get()); |
| + utterance->set_event_delegate(new TtsExtensionEventHandler()); |
| TtsController* controller = TtsController::GetInstance(); |
| controller->SpeakOrEnqueue(utterance); |
| @@ -175,7 +260,30 @@ bool TtsIsSpeakingFunction::RunImpl() { |
| } |
| bool TtsGetVoicesFunction::RunImpl() { |
| - SetResult(TtsController::GetInstance()->GetVoices(profile())); |
| + std::vector<VoiceData> voices; |
| + TtsController::GetInstance()->GetVoices(profile(), &voices); |
| + |
| + ListValue* result_voices = new ListValue(); |
| + for (size_t i = 0; i < voices.size(); i++) { |
|
tommi (sloooow) - chröme
2013/03/07 13:04:46
++i
dmazzoni
2013/03/19 17:30:22
Done throughout
|
| + const VoiceData& voice = voices[i]; |
| + DictionaryValue* result_voice = new DictionaryValue(); |
|
hans
2013/03/09 14:19:52
scoped_ptr?
dmazzoni
2013/03/19 17:30:22
Same - this gets owned by the ListValue.
|
| + result_voice->SetString(constants::kVoiceNameKey, voice.name); |
| + if (!voice.lang.empty()) |
|
tommi (sloooow) - chröme
2013/03/07 13:04:46
I'm guessing that if all of these are empty, then
dmazzoni
2013/03/19 17:30:22
Well, it still has a name...
Currently support fo
tommi (sloooow) - chröme
2013/03/21 14:34:02
OK
|
| + result_voice->SetString(constants::kLangKey, voice.lang); |
| + if (!voice.gender.empty()) |
| + result_voice->SetString(constants::kGenderKey, voice.gender); |
| + if (!voice.extension_id.empty()) |
| + result_voice->SetString(constants::kExtensionIdKey, voice.extension_id); |
| + |
| + ListValue* event_types = new ListValue(); |
|
hans
2013/03/09 14:19:52
scoped_ptr?
|
| + for (size_t j = 0; j < voice.events.size(); j++) |
|
tommi (sloooow) - chröme
2013/03/07 13:04:46
++j
|
| + event_types->Append(Value::CreateStringValue(voice.events[j])); |
| + result_voice->Set(constants::kEventTypesKey, event_types); |
|
hans
2013/03/09 14:19:52
naive question because I don't have the whole pict
dmazzoni
2013/03/19 17:30:22
It's done this way because it's a JavaScript API.
|
| + |
| + result_voices->Append(result_voice); |
| + } |
| + |
| + SetResult(result_voices); |
| return true; |
| } |