summaryrefslogtreecommitdiffstats
path: root/chrome/browser/speech
diff options
context:
space:
mode:
authordmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-14 00:04:25 +0000
committerdmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-14 00:04:25 +0000
commit28db40c7faa4c0fa772b4467e4afc0a0c3e618c8 (patch)
tree4b211ac000b3fd616d5561dd8127ce8945accc11 /chrome/browser/speech
parentae3d357e37bcafa1544a624a0929ea90ef8bd1b2 (diff)
downloadchromium_src-28db40c7faa4c0fa772b4467e4afc0a0c3e618c8.zip
chromium_src-28db40c7faa4c0fa772b4467e4afc0a0c3e618c8.tar.gz
chromium_src-28db40c7faa4c0fa772b4467e4afc0a0c3e618c8.tar.bz2
Support multiple TTS voices on Windows.
BUG=88059 Review URL: https://codereview.chromium.org/97793002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@240810 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/speech')
-rw-r--r--chrome/browser/speech/tts_win.cc109
1 files changed, 95 insertions, 14 deletions
diff --git a/chrome/browser/speech/tts_win.cc b/chrome/browser/speech/tts_win.cc
index 1602fc2..5df7f82 100644
--- a/chrome/browser/speech/tts_win.cc
+++ b/chrome/browser/speech/tts_win.cc
@@ -4,15 +4,27 @@
#include <math.h>
#include <sapi.h>
+#include <sphelper.h>
#include "base/memory/singleton.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
+#include "base/win/scoped_co_mem.h"
#include "base/win/scoped_comptr.h"
#include "chrome/browser/speech/tts_controller.h"
#include "chrome/browser/speech/tts_platform.h"
+namespace {
+
+// ISpObjectToken key and value names.
+const wchar_t kAttributesKey[] = L"Attributes";
+const wchar_t kGenderValue[] = L"Gender";
+const wchar_t kLanguageValue[] = L"Language";
+
+} // anonymous namespace.
+
class TtsPlatformImplWin : public TtsPlatformImpl {
public:
virtual bool PlatformImplAvailable() {
@@ -47,6 +59,8 @@ class TtsPlatformImplWin : public TtsPlatformImpl {
void OnSpeechEvent();
+ void SetVoiceFromName(const std::string& name);
+
base::win::ScopedComPtr<ISpVoice> speech_synthesizer_;
// These apply to the current utterance only.
@@ -56,6 +70,7 @@ class TtsPlatformImplWin : public TtsPlatformImpl {
ULONG stream_number_;
int char_position_;
bool paused_;
+ std::string last_voice_name_;
friend struct DefaultSingletonTraits<TtsPlatformImplWin>;
@@ -79,7 +94,7 @@ bool TtsPlatformImplWin::Speak(
if (!speech_synthesizer_.get())
return false;
- // TODO(dmazzoni): support languages other than the default: crbug.com/88059
+ SetVoiceFromName(voice.name);
if (params.rate >= 0.0) {
// Map our multiplicative range of 0.1x to 10.0x onto Microsoft's
@@ -172,19 +187,57 @@ bool TtsPlatformImplWin::IsSpeaking() {
void TtsPlatformImplWin::GetVoices(
std::vector<VoiceData>* out_voices) {
- // TODO: get all voices, not just default voice.
- // http://crbug.com/88059
- out_voices->push_back(VoiceData());
- VoiceData& voice = out_voices->back();
- voice.native = true;
- voice.name = "native";
- voice.events.insert(TTS_EVENT_START);
- voice.events.insert(TTS_EVENT_END);
- voice.events.insert(TTS_EVENT_MARKER);
- voice.events.insert(TTS_EVENT_WORD);
- voice.events.insert(TTS_EVENT_SENTENCE);
- voice.events.insert(TTS_EVENT_PAUSE);
- voice.events.insert(TTS_EVENT_RESUME);
+ base::win::ScopedComPtr<IEnumSpObjectTokens> voice_tokens;
+ unsigned long voice_count;
+ if (S_OK != SpEnumTokens(SPCAT_VOICES, NULL, NULL, voice_tokens.Receive()))
+ return;
+ if (S_OK != voice_tokens->GetCount(&voice_count))
+ return;
+
+ for (unsigned i = 0; i < voice_count; i++) {
+ VoiceData voice;
+
+ base::win::ScopedComPtr<ISpObjectToken> voice_token;
+ if (S_OK != voice_tokens->Next(1, voice_token.Receive(), NULL))
+ return;
+
+ base::win::ScopedCoMem<WCHAR> description;
+ if (S_OK != SpGetDescription(voice_token, &description))
+ continue;
+ voice.name = WideToUTF8(description.get());
+
+ base::win::ScopedComPtr<ISpDataKey> attributes;
+ if (S_OK != voice_token->OpenKey(kAttributesKey, attributes.Receive()))
+ continue;
+
+ base::win::ScopedCoMem<WCHAR> gender;
+ if (S_OK == attributes->GetStringValue(kGenderValue, &gender)) {
+ if (0 == _wcsicmp(gender.get(), L"male"))
+ voice.gender = TTS_GENDER_MALE;
+ else if (0 == _wcsicmp(gender.get(), L"female"))
+ voice.gender = TTS_GENDER_FEMALE;
+ }
+
+ base::win::ScopedCoMem<WCHAR> language;
+ if (S_OK == attributes->GetStringValue(kLanguageValue, &language)) {
+ int lcid_value;
+ base::HexStringToInt(WideToUTF8(language.get()), &lcid_value);
+ LCID lcid = MAKELCID(lcid_value, SORT_DEFAULT);
+ WCHAR locale_name[LOCALE_NAME_MAX_LENGTH] = {0};
+ LCIDToLocaleName(lcid, locale_name, LOCALE_NAME_MAX_LENGTH, 0);
+ voice.lang = WideToUTF8(locale_name);
+ }
+
+ voice.native = true;
+ voice.events.insert(TTS_EVENT_START);
+ voice.events.insert(TTS_EVENT_END);
+ voice.events.insert(TTS_EVENT_MARKER);
+ voice.events.insert(TTS_EVENT_WORD);
+ voice.events.insert(TTS_EVENT_SENTENCE);
+ voice.events.insert(TTS_EVENT_PAUSE);
+ voice.events.insert(TTS_EVENT_RESUME);
+ out_voices->push_back(voice);
+ }
}
void TtsPlatformImplWin::OnSpeechEvent() {
@@ -224,6 +277,34 @@ void TtsPlatformImplWin::OnSpeechEvent() {
}
}
+void TtsPlatformImplWin::SetVoiceFromName(const std::string& name) {
+ if (name.empty() || name == last_voice_name_)
+ return;
+
+ last_voice_name_ = name;
+
+ base::win::ScopedComPtr<IEnumSpObjectTokens> voice_tokens;
+ unsigned long voice_count;
+ if (S_OK != SpEnumTokens(SPCAT_VOICES, NULL, NULL, voice_tokens.Receive()))
+ return;
+ if (S_OK != voice_tokens->GetCount(&voice_count))
+ return;
+
+ for (unsigned i = 0; i < voice_count; i++) {
+ base::win::ScopedComPtr<ISpObjectToken> voice_token;
+ if (S_OK != voice_tokens->Next(1, voice_token.Receive(), NULL))
+ return;
+
+ base::win::ScopedCoMem<WCHAR> description;
+ if (S_OK != SpGetDescription(voice_token, &description))
+ continue;
+ if (name == WideToUTF8(description.get())) {
+ speech_synthesizer_->SetVoice(voice_token);
+ break;
+ }
+ }
+}
+
TtsPlatformImplWin::TtsPlatformImplWin()
: utterance_id_(0),
prefix_len_(0),