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(); 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 49 ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() { 50 return ExtensionTtsPlatformImplWin::GetInstance(); 51 } 52 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 98 bool ExtensionTtsPlatformImplWin::StopSpeaking() { 99 if (speech_synthesizer_ && !paused_) { 100 speech_synthesizer_->Pause(); 101 paused_ = true; 102 } 103 return true; 104 } 105 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 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 132 ExtensionTtsPlatformImplWin* ExtensionTtsPlatformImplWin::GetInstance() { 133 return Singleton<ExtensionTtsPlatformImplWin>::get(); 134 } 135