1 // Copyright (c) 2011 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.h"
6
7 #include <atlbase.h>
8 #include <atlcom.h>
9 #include <sapi.h>
10
11 #include "base/memory/singleton.h"
12 #include "base/string_number_conversions.h"
13 #include "base/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "base/win/scoped_comptr.h"
16
17 namespace util = extension_tts_api_util;
18
19 class ExtensionTtsPlatformImplWin : public ExtensionTtsPlatformImpl {
20 public:
21 virtual bool Speak(
22 const std::string& utterance,
23 const std::string& language,
24 const std::string& gender,
25 double rate,
26 double pitch,
27 double volume);
28
29 virtual bool StopSpeaking();
30
31 virtual bool IsSpeaking();
32
33 // Get the single instance of this class.
34 static ExtensionTtsPlatformImplWin* GetInstance();
35
36 private:
37 ExtensionTtsPlatformImplWin();
~ExtensionTtsPlatformImplWin()38 virtual ~ExtensionTtsPlatformImplWin() {}
39
40 base::win::ScopedComPtr<ISpVoice> speech_synthesizer_;
41 bool paused_;
42
43 friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplWin>;
44
45 DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplWin);
46 };
47
48 // static
GetInstance()49 ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() {
50 return ExtensionTtsPlatformImplWin::GetInstance();
51 }
52
Speak(const std::string & src_utterance,const std::string & language,const std::string & gender,double rate,double pitch,double volume)53 bool ExtensionTtsPlatformImplWin::Speak(
54 const std::string& src_utterance,
55 const std::string& language,
56 const std::string& gender,
57 double rate,
58 double pitch,
59 double volume) {
60 std::wstring utterance = UTF8ToUTF16(src_utterance);
61
62 if (!speech_synthesizer_)
63 return false;
64
65 // Speech API equivalents for kGenderKey and kLanguageNameKey do not
66 // exist and thus are not supported.
67
68 if (rate >= 0.0) {
69 // The TTS api allows a range of -10 to 10 for speech rate.
70 speech_synthesizer_->SetRate(static_cast<int32>(rate * 20 - 10));
71 }
72
73 if (pitch >= 0.0) {
74 // The TTS api allows a range of -10 to 10 for speech pitch.
75 // TODO(dtseng): cleanup if we ever use any other properties that
76 // require xml.
77 std::wstring pitch_value =
78 base::IntToString16(static_cast<int>(pitch * 20 - 10));
79 utterance = L"<pitch absmiddle=\"" + pitch_value + L"\">" +
80 utterance + L"</pitch>";
81 }
82
83 if (volume >= 0.0) {
84 // The TTS api allows a range of 0 to 100 for speech volume.
85 speech_synthesizer_->SetVolume(static_cast<uint16>(volume * 100));
86 }
87
88 if (paused_) {
89 speech_synthesizer_->Resume();
90 paused_ = false;
91 }
92 speech_synthesizer_->Speak(
93 utterance.c_str(), SPF_ASYNC | SPF_PURGEBEFORESPEAK, NULL);
94
95 return true;
96 }
97
StopSpeaking()98 bool ExtensionTtsPlatformImplWin::StopSpeaking() {
99 if (speech_synthesizer_ && !paused_) {
100 speech_synthesizer_->Pause();
101 paused_ = true;
102 }
103 return true;
104 }
105
IsSpeaking()106 bool ExtensionTtsPlatformImplWin::IsSpeaking() {
107 if (speech_synthesizer_ && !paused_) {
108 SPVOICESTATUS status;
109 HRESULT result = speech_synthesizer_->GetStatus(&status, NULL);
110 if (result == S_OK) {
111 if (status.dwRunningState == 0 || // 0 == waiting to speak
112 status.dwRunningState == SPRS_IS_SPEAKING) {
113 return true;
114 }
115 }
116 }
117 return false;
118 }
119
ExtensionTtsPlatformImplWin()120 ExtensionTtsPlatformImplWin::ExtensionTtsPlatformImplWin()
121 : speech_synthesizer_(NULL),
122 paused_(false) {
123 CoCreateInstance(
124 CLSID_SpVoice,
125 NULL,
126 CLSCTX_SERVER,
127 IID_ISpVoice,
128 reinterpret_cast<void**>(&speech_synthesizer_));
129 }
130
131 // static
GetInstance()132 ExtensionTtsPlatformImplWin* ExtensionTtsPlatformImplWin::GetInstance() {
133 return Singleton<ExtensionTtsPlatformImplWin>::get();
134 }
135