diff options
-rw-r--r-- | chrome/browser/extensions/extension_tts_api.cc | 96 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tts_api.h | 40 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tts_api_chromeos.cc | 125 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tts_api_gtk.cc | 17 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tts_api_linux.cc | 58 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tts_api_mac.mm | 113 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tts_api_win.cc | 171 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tts_apitest.cc | 2 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 9 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/tts/chromeos/manifest.json (renamed from chrome/test/data/extensions/api_test/tts/manifest.json) | 0 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/tts/chromeos/test.html (renamed from chrome/test/data/extensions/api_test/tts/test.html) | 0 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/tts/chromeos/test.js (renamed from chrome/test/data/extensions/api_test/tts/test.js) | 17 |
12 files changed, 434 insertions, 214 deletions
diff --git a/chrome/browser/extensions/extension_tts_api.cc b/chrome/browser/extensions/extension_tts_api.cc index ba9c2f8..b022ec0 100644 --- a/chrome/browser/extensions/extension_tts_api.cc +++ b/chrome/browser/extensions/extension_tts_api.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,16 +6,11 @@ #include <string> +#include "base/float_util.h" #include "base/values.h" -#include "base/string_number_conversions.h" - -#include "chrome/browser/chromeos/cros/cros_library.h" -#include "chrome/browser/chromeos/cros/speech_synthesis_library.h" namespace util = extension_tts_api_util; -using base::DoubleToString; - namespace { const char kCrosLibraryNotLoadedError[] = "Cros shared library not loaded."; @@ -23,68 +18,57 @@ namespace { bool ExtensionTtsSpeakFunction::RunImpl() { std::string utterance; - std::string options = ""; + std::string language; + std::string gender; + double rate = -1.0; + double pitch = -1.0; + double volume = -1.0; + DictionaryValue* speak_options = NULL; EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &utterance)); + if (args_->GetDictionary(1, &speak_options)) { - std::string str_value; - double real_value; - if (speak_options->HasKey(util::kLanguageNameKey) && - speak_options->GetString(util::kLanguageNameKey, &str_value)) { - util::AppendSpeakOption( - std::string(util::kNameKey), str_value, &options); + if (speak_options->HasKey(util::kLanguageNameKey)) { + speak_options->GetString(util::kLanguageNameKey, &language); } - if (speak_options->HasKey(util::kGenderKey) && - speak_options->GetString(util::kGenderKey, &str_value)) { - util::AppendSpeakOption( - std::string(util::kGenderKey), str_value, &options); - } - if (util::ReadNumberByKey(speak_options, util::kRateKey, &real_value)) { - // The TTS service allows a range of 0 to 5 for speech rate. - util::AppendSpeakOption(std::string(util::kRateKey), - DoubleToString(real_value * 5), &options); + + if (speak_options->HasKey(util::kGenderKey)) { + speak_options->GetString(util::kGenderKey, &gender); } - if (util::ReadNumberByKey(speak_options, util::kPitchKey, &real_value)) { - // The TTS service allows a range of 0 to 2 for speech pitch. - util::AppendSpeakOption(std::string(util::kPitchKey), - DoubleToString(real_value * 2), &options); + + if (util::ReadNumberByKey(speak_options, util::kRateKey, &rate)) { + if (!base::IsFinite(rate) || rate < 0.0 || rate > 1.0) { + rate = -1.0; + } } - if (util::ReadNumberByKey(speak_options, util::kVolumeKey, &real_value)) { - // The TTS service allows a range of 0 to 5 for speech volume. - util::AppendSpeakOption(std::string(util::kVolumeKey), - DoubleToString(real_value * 5), &options); + + if (util::ReadNumberByKey(speak_options, util::kPitchKey, &pitch)) { + if (!base::IsFinite(pitch) || pitch < 0.0 || pitch > 1.0) { + pitch = -1.0; + } } - } - if (chromeos::CrosLibrary::Get()->EnsureLoaded()) { - if (!options.empty()) { - chromeos::CrosLibrary::Get()->GetSpeechSynthesisLibrary()-> - SetSpeakProperties(options.c_str()); + + if (util::ReadNumberByKey(speak_options, util::kVolumeKey, &volume)) { + if (!base::IsFinite(volume) || volume < 0.0 || volume > 1.0) { + volume = -1.0; + } } - bool ret = chromeos::CrosLibrary::Get()->GetSpeechSynthesisLibrary()-> - Speak(utterance.c_str()); - result_.reset(); - return ret; } - error_ = kCrosLibraryNotLoadedError; - return false; + + ExtensionTtsPlatformImpl* impl = ExtensionTtsPlatformImpl::GetInstance(); + impl->clear_error(); + return impl->Speak(utterance, language, gender, rate, pitch, volume); } bool ExtensionTtsStopSpeakingFunction::RunImpl() { - if (chromeos::CrosLibrary::Get()->EnsureLoaded()) { - return chromeos::CrosLibrary::Get()->GetSpeechSynthesisLibrary()-> - StopSpeaking(); - } - error_ = kCrosLibraryNotLoadedError; - return false; + ExtensionTtsPlatformImpl* impl = ExtensionTtsPlatformImpl::GetInstance(); + impl->clear_error(); + return impl->StopSpeaking(); } bool ExtensionTtsIsSpeakingFunction::RunImpl() { - if (chromeos::CrosLibrary::Get()->EnsureLoaded()) { - result_.reset(Value::CreateBooleanValue( - chromeos::CrosLibrary::Get()->GetSpeechSynthesisLibrary()-> - IsSpeaking())); - return true; - } - error_ = kCrosLibraryNotLoadedError; - return false; + ExtensionTtsPlatformImpl* impl = ExtensionTtsPlatformImpl::GetInstance(); + impl->clear_error(); + result_.reset(Value::CreateBooleanValue(impl->IsSpeaking())); + return true; } diff --git a/chrome/browser/extensions/extension_tts_api.h b/chrome/browser/extensions/extension_tts_api.h index 84fa384..73fc887 100644 --- a/chrome/browser/extensions/extension_tts_api.h +++ b/chrome/browser/extensions/extension_tts_api.h @@ -8,6 +8,46 @@ #include "chrome/browser/extensions/extension_function.h" #include "chrome/browser/extensions/extension_tts_api_util.h" +// Abstract class that defines the native platform TTS interface. +class ExtensionTtsPlatformImpl { + public: + static ExtensionTtsPlatformImpl* GetInstance(); + + // Speak the given utterance with the given parameters if possible, + // and return true on success. Utterance will always be nonempty. + // If the user does not specify the other values, language and gender + // will be empty strings, and rate, pitch, and volume will be -1.0. + virtual bool Speak( + const std::string& utterance, + const std::string& language, + const std::string& gender, + double rate, + double pitch, + double volume) = 0; + + // Stop speaking immediately and return true on success. + virtual bool StopSpeaking() = 0; + + // Return true if the synthesis engine is currently speaking. + virtual bool IsSpeaking() = 0; + + virtual std::string error() { return error_; } + virtual void clear_error() { error_ = std::string(); } + virtual void set_error(const std::string& error) { error_ = error; } + + protected: + ExtensionTtsPlatformImpl() {} + virtual ~ExtensionTtsPlatformImpl() {} + + std::string error_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImpl); +}; + +// +// Extension API function definitions +// + class ExtensionTtsSpeakFunction : public SyncExtensionFunction { ~ExtensionTtsSpeakFunction() {} virtual bool RunImpl(); diff --git a/chrome/browser/extensions/extension_tts_api_chromeos.cc b/chrome/browser/extensions/extension_tts_api_chromeos.cc new file mode 100644 index 0000000..a183612 --- /dev/null +++ b/chrome/browser/extensions/extension_tts_api_chromeos.cc @@ -0,0 +1,125 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/extension_tts_api.h" + +#include "base/singleton.h" +#include "base/string_number_conversions.h" +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros/speech_synthesis_library.h" + +namespace util = extension_tts_api_util; + +using base::DoubleToString; + +namespace { +const char kCrosLibraryNotLoadedError[] = "Cros shared library not loaded."; +}; + +class ExtensionTtsPlatformImplChromeOs : public ExtensionTtsPlatformImpl { + public: + virtual bool Speak( + const std::string& utterance, + const std::string& language, + const std::string& gender, + double rate, + double pitch, + double volume); + + virtual bool StopSpeaking(); + + virtual bool IsSpeaking(); + + // Get the single instance of this class. + static ExtensionTtsPlatformImplChromeOs* GetInstance(); + + private: + ExtensionTtsPlatformImplChromeOs() {} + virtual ~ExtensionTtsPlatformImplChromeOs() {} + + friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplChromeOs>; + + DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplChromeOs); +}; + +// static +ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() { + return ExtensionTtsPlatformImplChromeOs::GetInstance(); +} + +bool ExtensionTtsPlatformImplChromeOs::Speak( + const std::string& utterance, + const std::string& language, + const std::string& gender, + double rate, + double pitch, + double volume) { + chromeos::CrosLibrary* cros_library = chromeos::CrosLibrary::Get(); + if (!cros_library->EnsureLoaded()) { + set_error(kCrosLibraryNotLoadedError); + return false; + } + + std::string options; + + if (!language.empty()) { + util::AppendSpeakOption( + std::string(util::kNameKey), language, &options); + } + + if (!gender.empty()) { + util::AppendSpeakOption( + std::string(util::kGenderKey), gender, &options); + } + + if (rate >= 0.0) { + util::AppendSpeakOption( + std::string(util::kRateKey), DoubleToString(rate * 5), &options); + } + + if (pitch >= 0.0) { + // The TTS service allows a range of 0 to 2 for speech pitch. + util::AppendSpeakOption( + std::string(util::kPitchKey), DoubleToString(pitch * 2), &options); + } + + if (volume >= 0.0) { + // The TTS service allows a range of 0 to 5 for speech volume. + util::AppendSpeakOption( + std::string(util::kVolumeKey), DoubleToString(volume * 5), &options); + } + + if (!options.empty()) { + cros_library->GetSpeechSynthesisLibrary()->SetSpeakProperties( + options.c_str()); + } + + return cros_library->GetSpeechSynthesisLibrary()->Speak(utterance.c_str()); +} + +bool ExtensionTtsPlatformImplChromeOs::StopSpeaking() { + if (chromeos::CrosLibrary::Get()->EnsureLoaded()) { + return chromeos::CrosLibrary::Get()->GetSpeechSynthesisLibrary()-> + StopSpeaking(); + } + + set_error(kCrosLibraryNotLoadedError); + return false; +} + +bool ExtensionTtsPlatformImplChromeOs::IsSpeaking() { + if (chromeos::CrosLibrary::Get()->EnsureLoaded()) { + return chromeos::CrosLibrary::Get()->GetSpeechSynthesisLibrary()-> + IsSpeaking(); + } + + set_error(kCrosLibraryNotLoadedError); + return false; +} + +// static +ExtensionTtsPlatformImplChromeOs* +ExtensionTtsPlatformImplChromeOs::GetInstance() { + return Singleton<ExtensionTtsPlatformImplChromeOs>::get(); +} diff --git a/chrome/browser/extensions/extension_tts_api_gtk.cc b/chrome/browser/extensions/extension_tts_api_gtk.cc deleted file mode 100644 index 6804f92..0000000 --- a/chrome/browser/extensions/extension_tts_api_gtk.cc +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extension_tts_api.h"
-
-bool ExtensionTtsSpeakFunction::RunImpl() {
- return false;
-}
-
-bool ExtensionTtsStopSpeakingFunction::RunImpl() {
- return false;
-}
-
-bool ExtensionTtsIsSpeakingFunction::RunImpl() {
- return false;
-}
diff --git a/chrome/browser/extensions/extension_tts_api_linux.cc b/chrome/browser/extensions/extension_tts_api_linux.cc new file mode 100644 index 0000000..15f1af1 --- /dev/null +++ b/chrome/browser/extensions/extension_tts_api_linux.cc @@ -0,0 +1,58 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/extension_tts_api.h" + +#include "base/singleton.h" +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros/speech_synthesis_library.h" + +namespace util = extension_tts_api_util; + +namespace { +const char kNotSupportedError[] = + "Native speech synthesis not supported on this platform."; +}; + +class ExtensionTtsPlatformImplLinux : public ExtensionTtsPlatformImpl { + public: + virtual bool Speak( + const std::string& utterance, + const std::string& language, + const std::string& gender, + double rate, + double pitch, + double volume) { + error_ = kNotSupportedError; + return false; + } + + virtual bool StopSpeaking() { + error_ = kNotSupportedError; + return false; + } + + virtual bool IsSpeaking() { + error_ = kNotSupportedError; + return false; + } + + // Get the single instance of this class. + static ExtensionTtsPlatformImplLinux* GetInstance() { + return ExtensionTtsPlatformImplLinux::GetInstance(); + } + + private: + ExtensionTtsPlatformImplLinux() {} + virtual ~ExtensionTtsPlatformImplLinux() {} + + friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplLinux>; + + DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplLinux); +}; + +// static +ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() { + return ExtensionTtsPlatformImplLinux::GetInstance(); +} diff --git a/chrome/browser/extensions/extension_tts_api_mac.mm b/chrome/browser/extensions/extension_tts_api_mac.mm index 1b45380..2e97aca 100644 --- a/chrome/browser/extensions/extension_tts_api_mac.mm +++ b/chrome/browser/extensions/extension_tts_api_mac.mm @@ -6,6 +6,7 @@ #include <string> +#include "base/singleton.h" #include "base/values.h" #include "chrome/browser/extensions/extension_function.h" @@ -13,57 +14,87 @@ namespace util = extension_tts_api_util; -static NSSpeechSynthesizer* speech_synthesizer_; +class ExtensionTtsPlatformImplMac : public ExtensionTtsPlatformImpl { + public: + virtual bool Speak( + const std::string& utterance, + const std::string& language, + const std::string& gender, + double rate, + double pitch, + double volume); -void InitializeSpeechSynthesizer() { - if (!speech_synthesizer_) - speech_synthesizer_ = [[NSSpeechSynthesizer alloc] init]; + virtual bool StopSpeaking(); + + virtual bool IsSpeaking(); + + // Get the single instance of this class. + static ExtensionTtsPlatformImplMac* GetInstance(); + + private: + ExtensionTtsPlatformImplMac(); + virtual ~ExtensionTtsPlatformImplMac() {} + + NSSpeechSynthesizer* speech_synthesizer_; + + friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplMac>; + + DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplMac); +}; + +// static +ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() { + return ExtensionTtsPlatformImplMac::GetInstance(); } -bool ExtensionTtsSpeakFunction::RunImpl() { - InitializeSpeechSynthesizer(); - std::string utterance; - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &utterance)); - DictionaryValue* speak_options = NULL; - - // Parse speech properties. - if (args_->GetDictionary(1, &speak_options)) { - std::string str_value; - double real_value; - // NSSpeechSynthesizer equivalents for kGenderKey and kLanguageNameKey do - // not exist and thus are not supported. - if (util::ReadNumberByKey(speak_options, util::kRateKey, &real_value)) { - // The TTS api defines rate via words per minute. - [speech_synthesizer_ - setObject:[NSNumber numberWithInt:real_value*400] - forProperty:NSSpeechRateProperty error:nil]; - } - if (util::ReadNumberByKey(speak_options, util::kPitchKey, &real_value)) { - // The TTS api allows an approximate range of 30 to 65 for speech pitch. - [speech_synthesizer_ - setObject: [NSNumber numberWithInt:(real_value*35 + 30)] - forProperty:NSSpeechPitchBaseProperty error:nil]; - } - if (util::ReadNumberByKey(speak_options, util::kVolumeKey, &real_value)) { - // The TTS api allows a range of 0.0 to 1.0 for speech volume. - [speech_synthesizer_ - setObject: [NSNumber numberWithFloat:real_value] - forProperty:NSSpeechVolumeProperty error:nil]; - } +bool ExtensionTtsPlatformImplMac::Speak( + const std::string& utterance, + const std::string& language, + const std::string& gender, + double rate, + double pitch, + double volume) { + // NSSpeechSynthesizer equivalents for kGenderKey and kLanguageNameKey do + // not exist and thus are not supported. + + if (rate >= 0.0) { + // The TTS api defines rate via words per minute. + [speech_synthesizer_ + setObject:[NSNumber numberWithInt:rate * 400] + forProperty:NSSpeechRateProperty error:nil]; } - return - [speech_synthesizer_ startSpeakingString: - [NSString stringWithUTF8String: utterance.c_str()]]; + if (pitch >= 0.0) { + // The TTS api allows an approximate range of 30 to 65 for speech pitch. + [speech_synthesizer_ + setObject: [NSNumber numberWithInt:(pitch * 35 + 30)] + forProperty:NSSpeechPitchBaseProperty error:nil]; + } + + if (volume >= 0.0) { + [speech_synthesizer_ + setObject: [NSNumber numberWithFloat:volume] + forProperty:NSSpeechVolumeProperty error:nil]; + } + + return [speech_synthesizer_ startSpeakingString: + [NSString stringWithUTF8String: utterance.c_str()]]; } -bool ExtensionTtsStopSpeakingFunction::RunImpl() { - InitializeSpeechSynthesizer(); +bool ExtensionTtsPlatformImplMac::StopSpeaking() { [speech_synthesizer_ stopSpeaking]; return true; } -bool ExtensionTtsIsSpeakingFunction::RunImpl() { - InitializeSpeechSynthesizer(); +bool ExtensionTtsPlatformImplMac::IsSpeaking() { return [speech_synthesizer_ isSpeaking]; } + +ExtensionTtsPlatformImplMac::ExtensionTtsPlatformImplMac() { + speech_synthesizer_ = [[NSSpeechSynthesizer alloc] init]; +} + +// static +ExtensionTtsPlatformImplMac* ExtensionTtsPlatformImplMac::GetInstance() { + return Singleton<ExtensionTtsPlatformImplMac>::get(); +} diff --git a/chrome/browser/extensions/extension_tts_api_win.cc b/chrome/browser/extensions/extension_tts_api_win.cc index 480880b..a9a6062 100644 --- a/chrome/browser/extensions/extension_tts_api_win.cc +++ b/chrome/browser/extensions/extension_tts_api_win.cc @@ -11,113 +11,112 @@ #include "base/scoped_comptr_win.h" #include "base/singleton.h" #include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" #include "base/values.h" namespace util = extension_tts_api_util; -class SpeechSynthesizerWrapper { +class ExtensionTtsPlatformImplWin : public ExtensionTtsPlatformImpl { public: - SpeechSynthesizerWrapper() : speech_synthesizer_(NULL), - paused_(false), - permanent_failure_(false) { - InitializeSpeechSynthesizer(); - } + virtual bool Speak( + const std::string& utterance, + const std::string& language, + const std::string& gender, + double rate, + double pitch, + double volume); - bool InitializeSpeechSynthesizer() { - if (!SUCCEEDED(CoCreateInstance(CLSID_SpVoice, - NULL, - CLSCTX_SERVER, - IID_ISpVoice, - reinterpret_cast<void**>( - &speech_synthesizer_)))) { - permanent_failure_ = true; - return false; - } - - if (paused_) - speech_synthesizer_->Resume(); - return true; - } + virtual bool StopSpeaking(); - ScopedComPtr<ISpVoice> speech_synthesizer() { - return speech_synthesizer_; - } + virtual bool IsSpeaking(); - bool paused() { - return paused_; - } - - void paused(bool state) { - paused_ = state; - } + // Get the single instance of this class. + static ExtensionTtsPlatformImplWin* GetInstance(); private: + ExtensionTtsPlatformImplWin(); + virtual ~ExtensionTtsPlatformImplWin() {} + ScopedComPtr<ISpVoice> speech_synthesizer_; bool paused_; - // Indicates an error retrieving the SAPI COM interface. - bool permanent_failure_; + + friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplWin>; + + DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplWin); }; -typedef Singleton<SpeechSynthesizerWrapper> SpeechSynthesizerSingleton; - -bool ExtensionTtsSpeakFunction::RunImpl() { - ScopedComPtr<ISpVoice> speech_synthesizer = - SpeechSynthesizerSingleton::get()->speech_synthesizer(); - if (speech_synthesizer) { - std::wstring utterance; - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &utterance)); - - std::string options = ""; - DictionaryValue* speak_options = NULL; - - // Parse speech properties. - if (args_->GetDictionary(1, &speak_options)) { - std::string str_value; - double real_value; - // Speech API equivalents for kGenderKey and kLanguageNameKey do not - // exist and thus are not supported. - if (util::ReadNumberByKey(speak_options, util::kRateKey, &real_value)) { - // The TTS api allows a range of -10 to 10 for speech rate. - speech_synthesizer->SetRate(static_cast<int32>(real_value*20 - 10)); - } - if (util::ReadNumberByKey(speak_options, util::kPitchKey, &real_value)) { - // The TTS api allows a range of -10 to 10 for speech pitch. - // TODO(dtseng): cleanup if we ever - // use any other properties that require xml. - std::wstring pitch_value = - base::IntToString16(static_cast<int>(real_value*20 - 10)); - utterance = L"<pitch absmiddle=\"" + pitch_value + L"\">" + - utterance + L"</pitch>"; - } - if (util::ReadNumberByKey( - speak_options, util::kVolumeKey, &real_value)) { - // The TTS api allows a range of 0 to 100 for speech volume. - speech_synthesizer->SetVolume(static_cast<uint16>(real_value * 100)); - } - } - - if (SpeechSynthesizerSingleton::get()->paused()) - speech_synthesizer->Resume(); - speech_synthesizer->Speak( - utterance.c_str(), SPF_ASYNC | SPF_PURGEBEFORESPEAK, NULL); - return true; +// static +ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() { + return ExtensionTtsPlatformImplWin::GetInstance(); +} + +bool ExtensionTtsPlatformImplWin::Speak( + const std::string& src_utterance, + const std::string& language, + const std::string& gender, + double rate, + double pitch, + double volume) { + std::wstring utterance = UTF8ToUTF16(src_utterance); + + if (!speech_synthesizer_) + return false; + + // Speech API equivalents for kGenderKey and kLanguageNameKey do not + // exist and thus are not supported. + + if (rate >= 0.0) { + // The TTS api allows a range of -10 to 10 for speech rate. + speech_synthesizer_->SetRate(static_cast<int32>(rate * 20 - 10)); } - return false; + if (pitch >= 0.0) { + // The TTS api allows a range of -10 to 10 for speech pitch. + // TODO(dtseng): cleanup if we ever use any other properties that + // require xml. + std::wstring pitch_value = + base::IntToString16(static_cast<int>(pitch * 20 - 10)); + utterance = L"<pitch absmiddle=\"" + pitch_value + L"\">" + + utterance + L"</pitch>"; + } + + if (volume >= 0.0) { + // The TTS api allows a range of 0 to 100 for speech volume. + speech_synthesizer_->SetVolume(static_cast<uint16>(volume * 100)); + } + + if (paused_) + speech_synthesizer_->Resume(); + speech_synthesizer_->Speak( + utterance.c_str(), SPF_ASYNC | SPF_PURGEBEFORESPEAK, NULL); + + return true; } -bool ExtensionTtsStopSpeakingFunction::RunImpl() { - // We need to keep track of the paused state since SAPI doesn't have a stop - // method. - ScopedComPtr<ISpVoice> speech_synthesizer = - SpeechSynthesizerSingleton::get()->speech_synthesizer(); - if (speech_synthesizer && !SpeechSynthesizerSingleton::get()->paused()) { - speech_synthesizer->Pause(); - SpeechSynthesizerSingleton::get()->paused(true); +bool ExtensionTtsPlatformImplWin::StopSpeaking() { + if (!speech_synthesizer_ && !paused_) { + speech_synthesizer_->Pause(); + paused_ = true; } return true; } -bool ExtensionTtsIsSpeakingFunction::RunImpl() { +bool ExtensionTtsPlatformImplWin::IsSpeaking() { return false; } + +ExtensionTtsPlatformImplWin::ExtensionTtsPlatformImplWin() + : speech_synthesizer_(NULL), + paused_(false) { + CoCreateInstance( + CLSID_SpVoice, + NULL, + CLSCTX_SERVER, + IID_ISpVoice, + reinterpret_cast<void**>(&speech_synthesizer_)); +} + +// static +ExtensionTtsPlatformImplWin* ExtensionTtsPlatformImplWin::GetInstance() { + return Singleton<ExtensionTtsPlatformImplWin>::get(); +} diff --git a/chrome/browser/extensions/extension_tts_apitest.cc b/chrome/browser/extensions/extension_tts_apitest.cc index 5acda10..dcdfb9d5 100644 --- a/chrome/browser/extensions/extension_tts_apitest.cc +++ b/chrome/browser/extensions/extension_tts_apitest.cc @@ -22,5 +22,5 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_Tts) { crosMock.InitMockSpeechSynthesisLibrary(); crosMock.SetSpeechSynthesisLibraryExpectations(); - ASSERT_TRUE(RunExtensionTest("tts")) << message_; + ASSERT_TRUE(RunExtensionTest("tts/chromeos")) << message_; } diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 59f2055..6ee4855 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1543,7 +1543,8 @@ 'browser/extensions/extension_test_api.h', 'browser/extensions/extension_tts_api.cc', 'browser/extensions/extension_tts_api.h', - 'browser/extensions/extension_tts_api_gtk.cc', + 'browser/extensions/extension_tts_api_chromeos.cc', + 'browser/extensions/extension_tts_api_linux.cc', 'browser/extensions/extension_tts_api_mac.mm', 'browser/extensions/extension_tts_api_util.cc', 'browser/extensions/extension_tts_api_util.h', @@ -3294,7 +3295,7 @@ ['exclude', 'browser/dom_ui/filebrowse_ui.cc'], ['exclude', 'browser/dom_ui/mediaplayer_ui.cc'], ['exclude', 'browser/dom_ui/slideshow_ui.cc'], - ['exclude', 'browser/extensions/extension_tts_api.cc'], + ['exclude', 'browser/extensions/extension_tts_api_chromeos.cc'], ['exclude', 'browser/renderer_host/offline_resource_handler.cc'], ['exclude', 'browser/renderer_host/offline_resource_handler.h'], ], @@ -3960,13 +3961,11 @@ # non-ChromeOS views Linux builds. ['OS=="linux" and toolkit_views==1 and chromeos==0', { 'sources/': [ - ['exclude', '^browser/extensions/extension_tts_api.cc'], ['include', '^browser/gtk/dialogs_gtk.cc'], ['include', '^browser/gtk/external_protocol_dialog_gtk.cc'], ['include', '^browser/gtk/external_protocol_dialog_gtk.h'], ['include', '^browser/views/notifications/balloon_view.cc'], ['include', '^browser/views/notifications/balloon_view.h'], - ['exclude', '^browser/views/select_file_dialog.cc'], ], }], @@ -3983,7 +3982,7 @@ }], ['OS=="linux" and chromeos==1',{ 'sources/': [ - ['exclude', '^browser/extensions/extension_tts_api_gtk.cc'], + ['exclude', '^browser/extensions/extension_tts_api_linux.cc'], ['exclude', '^browser/notifications/balloon_collection.cc'], ['exclude', '^browser/notifications/balloon_collection_impl.h'], ['exclude', '^browser/notifications/balloon_collection_linux.cc'], diff --git a/chrome/test/data/extensions/api_test/tts/manifest.json b/chrome/test/data/extensions/api_test/tts/chromeos/manifest.json index a43bc3d..a43bc3d 100644 --- a/chrome/test/data/extensions/api_test/tts/manifest.json +++ b/chrome/test/data/extensions/api_test/tts/chromeos/manifest.json diff --git a/chrome/test/data/extensions/api_test/tts/test.html b/chrome/test/data/extensions/api_test/tts/chromeos/test.html index 46f4d74..46f4d74 100644 --- a/chrome/test/data/extensions/api_test/tts/test.html +++ b/chrome/test/data/extensions/api_test/tts/chromeos/test.html diff --git a/chrome/test/data/extensions/api_test/tts/test.js b/chrome/test/data/extensions/api_test/tts/chromeos/test.js index df5837b..0cf73bc0 100644 --- a/chrome/test/data/extensions/api_test/tts/test.js +++ b/chrome/test/data/extensions/api_test/tts/chromeos/test.js @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TTS api test for Chrome. This is currently limited to ChromeOS. -// browser_tests.exe --gtest_filter=ExtensionApiTest.Tts +// TTS api test for Chrome on ChromeOS. +// browser_tests.exe --gtest_filter=ExtensionApiTest.TtsOnChromeOs chrome.test.runTests([ function testSpeak() { @@ -20,12 +20,13 @@ chrome.test.runTests([ function testIsSpeaking() { for (var i = 0; i < 3; i++) { chrome.experimental.tts.isSpeaking(function(speaking) { - chrome.test.assertTrue(speaking); - }); + chrome.test.assertTrue(speaking); + }); } chrome.experimental.tts.isSpeaking(function(speaking) { - chrome.test.assertFalse(speaking); - chrome.test.succeed(); - }); + chrome.test.assertFalse(speaking); + chrome.test.succeed(); + }); } -]);
\ No newline at end of file + +]); |