diff options
author | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-11 18:51:43 +0000 |
---|---|---|
committer | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-11 18:51:43 +0000 |
commit | 56f6f9dc5522435534cebcf0a1a9a239dbda2bea (patch) | |
tree | ba37024edb6d2d6f06273f6fdfef976f00507719 /chrome/browser/speech/extension_api/tts_engine_extension_api.cc | |
parent | 71395b17a1da1100fe57e8ad141c2ea5da338416 (diff) | |
download | chromium_src-56f6f9dc5522435534cebcf0a1a9a239dbda2bea.zip chromium_src-56f6f9dc5522435534cebcf0a1a9a239dbda2bea.tar.gz chromium_src-56f6f9dc5522435534cebcf0a1a9a239dbda2bea.tar.bz2 |
Add support for native TTS to provide multiple voices.
This change refactors the text-to-speech system so that the
"platform native" text-to-speech implementation can provide
multiple voices, rather than just the system default voice.
This refactoring also further reduces the coupling between
the main TTS system in chrome/browser/speech and the
extension API in chrome/browser/speech/extension_api - the
goal is to later move all of the non-extension code to content.
This change also implements multiple voices on Mac OS X.
Windows support will be in a subsequent changelist.
BUG=88059
NOTRY=true
Review URL: https://chromiumcodereview.appspot.com/14657013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@199615 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/speech/extension_api/tts_engine_extension_api.cc')
-rw-r--r-- | chrome/browser/speech/extension_api/tts_engine_extension_api.cc | 135 |
1 files changed, 13 insertions, 122 deletions
diff --git a/chrome/browser/speech/extension_api/tts_engine_extension_api.cc b/chrome/browser/speech/extension_api/tts_engine_extension_api.cc index de8e24d..4c9b8d5 100644 --- a/chrome/browser/speech/extension_api/tts_engine_extension_api.cc +++ b/chrome/browser/speech/extension_api/tts_engine_extension_api.cc @@ -12,6 +12,7 @@ #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_system.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/speech/extension_api/tts_extension_api.h" #include "chrome/browser/speech/extension_api/tts_extension_api_constants.h" #include "chrome/browser/speech/tts_controller.h" #include "chrome/common/extensions/api/speech/tts_engine_manifest_handler.h" @@ -26,17 +27,6 @@ const char kOnSpeak[] = "ttsEngine.onSpeak"; const char kOnStop[] = "ttsEngine.onStop"; }; // namespace tts_engine_events -namespace { -// Given a language/region code of the form 'fr-FR', returns just the basic -// language portion, e.g. 'fr'. -std::string TrimLanguageCode(std::string lang) { - if (lang.size() >= 5 && lang[2] == '-') - return lang.substr(0, 2); - else - return lang; -} -} - void GetExtensionVoices(Profile* profile, std::vector<VoiceData>* out_voices) { ExtensionService* service = profile->GetExtensionService(); DCHECK(service); @@ -67,139 +57,40 @@ void GetExtensionVoices(Profile* profile, std::vector<VoiceData>* out_voices) { out_voices->push_back(VoiceData()); VoiceData& result_voice = out_voices->back(); + result_voice.native = false; result_voice.name = voice.voice_name; result_voice.lang = voice.lang; - result_voice.gender = voice.gender; result_voice.extension_id = extension->id(); + if (voice.gender == constants::kGenderMale) + result_voice.gender = TTS_GENDER_MALE; + else if (voice.gender == constants::kGenderFemale) + result_voice.gender = TTS_GENDER_FEMALE; + else + result_voice.gender = TTS_GENDER_NONE; for (std::set<std::string>::const_iterator iter = voice.event_types.begin(); iter != voice.event_types.end(); ++iter) { - result_voice.events.push_back(*iter); + result_voice.events.insert(TtsEventTypeFromString(*iter)); } // If the extension sends end events, the controller will handle // queueing and send interrupted and cancelled events. if (voice.event_types.find(constants::kEventTypeEnd) != voice.event_types.end()) { - result_voice.events.push_back(constants::kEventTypeCancelled); - result_voice.events.push_back(constants::kEventTypeInterrupted); - } - } - } -} - -bool GetMatchingExtensionVoice( - Utterance* utterance, - const Extension** matching_extension, - size_t* voice_index) { - // This will only happen during unit testing. Otherwise, an utterance - // will always have an associated profile. - if (!utterance->profile()) - return false; - - ExtensionService* service = utterance->profile()->GetExtensionService(); - - // If speech is generated when Chrome OS first starts up, it's possible - // the extension service isn't even available. - if (!service) - return false; - - extensions::EventRouter* event_router = - extensions::ExtensionSystem::Get(utterance->profile())->event_router(); - DCHECK(event_router); - - *matching_extension = NULL; - *voice_index = -1; - const ExtensionSet* extensions = service->extensions(); - ExtensionSet::const_iterator iter; - - // Make two passes: the first time, do strict language matching - // ('fr-FR' does not match 'fr-CA'). The second time, do prefix - // language matching ('fr-FR' matches 'fr' and 'fr-CA') - for (int pass = 0; pass < 2; ++pass) { - for (iter = extensions->begin(); iter != extensions->end(); ++iter) { - const Extension* extension = *iter; - - if (!event_router->ExtensionHasEventListener( - extension->id(), tts_engine_events::kOnSpeak) || - !event_router->ExtensionHasEventListener( - extension->id(), tts_engine_events::kOnStop)) { - continue; - } - - if (!utterance->extension_id().empty() && - utterance->extension_id() != extension->id()) { - continue; - } - - const std::vector<extensions::TtsVoice>* tts_voices = - extensions::TtsVoice::GetTtsVoices(extension); - if (!tts_voices) - continue; - - for (size_t i = 0; i < tts_voices->size(); ++i) { - const extensions::TtsVoice& voice = tts_voices->at(i); - if (!voice.voice_name.empty() && - !utterance->voice_name().empty() && - voice.voice_name != utterance->voice_name()) { - continue; - } - if (!voice.lang.empty() && !utterance->lang().empty()) { - std::string voice_lang = voice.lang; - std::string utterance_lang = utterance->lang(); - if (pass == 1) { - voice_lang = TrimLanguageCode(voice_lang); - utterance_lang = TrimLanguageCode(utterance_lang); - } - if (voice_lang != utterance_lang) - continue; - } - if (!voice.gender.empty() && - !utterance->gender().empty() && - voice.gender != utterance->gender()) { - continue; - } - if (utterance->required_event_types().size() > 0) { - bool has_all_required_event_types = true; - for (std::set<std::string>::const_iterator iter = - utterance->required_event_types().begin(); - iter != utterance->required_event_types().end(); - ++iter) { - if (voice.event_types.find(*iter) == voice.event_types.end()) { - has_all_required_event_types = false; - break; - } - } - if (!has_all_required_event_types) - continue; - } - - *matching_extension = extension; - *voice_index = i; - return true; + result_voice.events.insert(TTS_EVENT_CANCELLED); + result_voice.events.insert(TTS_EVENT_INTERRUPTED); } } } - - return false; } -void ExtensionTtsEngineSpeak(Utterance* utterance, - const Extension* extension, - size_t voice_index) { +void ExtensionTtsEngineSpeak(Utterance* utterance, const VoiceData& voice) { // See if the engine supports the "end" event; if so, we can keep the // utterance around and track it. If not, we're finished with this // utterance now. - const std::vector<extensions::TtsVoice>* tts_voices = - extensions::TtsVoice::GetTtsVoices(extension); - std::set<std::string> event_types; - if (tts_voices) - event_types = tts_voices->at(voice_index).event_types; - - bool sends_end_event = - (event_types.find(constants::kEventTypeEnd) != event_types.end()); + bool sends_end_event = voice.events.find(TTS_EVENT_END) != voice.events.end(); scoped_ptr<ListValue> args(new ListValue()); args->Set(0, Value::CreateStringValue(utterance->text())); |