diff options
author | dtseng@chromium.org <dtseng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-15 22:33:38 +0000 |
---|---|---|
committer | dtseng@chromium.org <dtseng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-15 22:33:38 +0000 |
commit | 5686e18f9855098f6b0993549e3243e4d4f7f947 (patch) | |
tree | 9c29fc0a7b16778095d0fbf716c6506a0e5356f8 | |
parent | 6827bceba32719b03a6cf49faf0b2cde17685f2f (diff) | |
download | chromium_src-5686e18f9855098f6b0993549e3243e4d4f7f947.zip chromium_src-5686e18f9855098f6b0993549e3243e4d4f7f947.tar.gz chromium_src-5686e18f9855098f6b0993549e3243e4d4f7f947.tar.bz2 |
Add support for speak properties such as rate to platform specific TTS.
BUG=none.
TEST=Use extension to drive the tts engines on Windows and Mac. Had key bindings so that verification of:
decrease rate, increase rate, decrease pitch, increase pitch, decrease volume, and increase volume worked. Verified that the limits, when reached, did not have any adverse effects.
Review URL: http://codereview.chromium.org/3325021
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@59572 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/extensions/extension_tts_api.cc | 69 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tts_api.h | 2 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tts_api_mac.mm | 108 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tts_api_util.cc | 38 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tts_api_util.h | 32 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tts_api_win.cc | 209 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 |
7 files changed, 287 insertions, 173 deletions
diff --git a/chrome/browser/extensions/extension_tts_api.cc b/chrome/browser/extensions/extension_tts_api.cc index 47168af..ba9c2f8 100644 --- a/chrome/browser/extensions/extension_tts_api.cc +++ b/chrome/browser/extensions/extension_tts_api.cc @@ -12,43 +12,13 @@ #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/cros/speech_synthesis_library.h" -using base::DoubleToString; +namespace util = extension_tts_api_util; -const char kNameKey[] = "name"; -const char kLanguageNameKey[] = "languageName"; -const char kGenderKey[] = "gender"; -const char kRateKey[] = "rate"; -const char kPitchKey[] = "pitch"; -const char kVolumeKey[] = "volume"; -const char kEqualStr[] = "="; -const char kDelimiter[] = ";"; +using base::DoubleToString; namespace { const char kCrosLibraryNotLoadedError[] = "Cros shared library not loaded."; - - bool ReadNumberByKey(DictionaryValue* dict, const char* key, - double* ret_value) { - Value* value; - dict->Get(key, &value); - if (value->IsType(Value::TYPE_INTEGER)) { - int int_value; - if (!dict->GetInteger(key, &int_value)) - return false; - *ret_value = int_value; - } else if (value->IsType(Value::TYPE_REAL)) { - if (!dict->GetReal(key, ret_value)) - return false; - } else { - return false; - } - return true; - } - - void AppendSpeakOption(std::string key, std::string value, - std::string* options) { - *options += key + kEqualStr + value + kDelimiter; - } }; bool ExtensionTtsSpeakFunction::RunImpl() { @@ -59,26 +29,31 @@ bool ExtensionTtsSpeakFunction::RunImpl() { if (args_->GetDictionary(1, &speak_options)) { std::string str_value; double real_value; - if (speak_options->HasKey(kLanguageNameKey) && - speak_options->GetString(kLanguageNameKey, &str_value)) { - AppendSpeakOption(std::string(kNameKey), str_value, &options); + 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(kGenderKey) && - speak_options->GetString(kGenderKey, &str_value)) { - AppendSpeakOption(std::string(kGenderKey), str_value, &options); + if (speak_options->HasKey(util::kGenderKey) && + speak_options->GetString(util::kGenderKey, &str_value)) { + util::AppendSpeakOption( + std::string(util::kGenderKey), str_value, &options); } - if (ReadNumberByKey(speak_options, kRateKey, &real_value)) + if (util::ReadNumberByKey(speak_options, util::kRateKey, &real_value)) { // The TTS service allows a range of 0 to 5 for speech rate. - AppendSpeakOption(std::string(kRateKey), - DoubleToString(real_value * 5), &options); - if (ReadNumberByKey(speak_options, kPitchKey, &real_value)) + util::AppendSpeakOption(std::string(util::kRateKey), + DoubleToString(real_value * 5), &options); + } + if (util::ReadNumberByKey(speak_options, util::kPitchKey, &real_value)) { // The TTS service allows a range of 0 to 2 for speech pitch. - AppendSpeakOption(std::string(kPitchKey), - DoubleToString(real_value * 2), &options); - if (ReadNumberByKey(speak_options, kVolumeKey, &real_value)) + util::AppendSpeakOption(std::string(util::kPitchKey), + DoubleToString(real_value * 2), &options); + } + if (util::ReadNumberByKey(speak_options, util::kVolumeKey, &real_value)) { // The TTS service allows a range of 0 to 5 for speech volume. - AppendSpeakOption(std::string(kVolumeKey), - DoubleToString(real_value * 5), &options); + util::AppendSpeakOption(std::string(util::kVolumeKey), + DoubleToString(real_value * 5), &options); + } } if (chromeos::CrosLibrary::Get()->EnsureLoaded()) { if (!options.empty()) { diff --git a/chrome/browser/extensions/extension_tts_api.h b/chrome/browser/extensions/extension_tts_api.h index d5f578d..84fa384 100644 --- a/chrome/browser/extensions/extension_tts_api.h +++ b/chrome/browser/extensions/extension_tts_api.h @@ -5,8 +5,8 @@ #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_H_ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_H_ -#include "base/singleton.h" #include "chrome/browser/extensions/extension_function.h" +#include "chrome/browser/extensions/extension_tts_api_util.h" class ExtensionTtsSpeakFunction : public SyncExtensionFunction { ~ExtensionTtsSpeakFunction() {} diff --git a/chrome/browser/extensions/extension_tts_api_mac.mm b/chrome/browser/extensions/extension_tts_api_mac.mm index 98e49e3..1b45380 100644 --- a/chrome/browser/extensions/extension_tts_api_mac.mm +++ b/chrome/browser/extensions/extension_tts_api_mac.mm @@ -1,39 +1,69 @@ -// 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"
-
-#include <string>
-
-#include "base/values.h"
-#include "chrome/browser/extensions/extension_function.h"
-
-#import <cocoa/cocoa.h>
-
-static NSSpeechSynthesizer* speech_synthesizer_;
-
-void InitializeSpeechSynthesizer() {
- if (!speech_synthesizer_)
- speech_synthesizer_ = [[NSSpeechSynthesizer alloc] init];
-}
-
-bool ExtensionTtsSpeakFunction::RunImpl() {
- InitializeSpeechSynthesizer();
- std::string utterance;
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &utterance));
- return
- [speech_synthesizer_ startSpeakingString:
- [NSString stringWithUTF8String: utterance.c_str()]];
-}
-
-bool ExtensionTtsStopSpeakingFunction::RunImpl() {
- InitializeSpeechSynthesizer();
- [speech_synthesizer_ stopSpeaking];
- return true;
-}
-
-bool ExtensionTtsIsSpeakingFunction::RunImpl() {
- InitializeSpeechSynthesizer();
- return [speech_synthesizer_ isSpeaking];
-}
+// 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" + +#include <string> + +#include "base/values.h" +#include "chrome/browser/extensions/extension_function.h" + +#import <Cocoa/Cocoa.h> + +namespace util = extension_tts_api_util; + +static NSSpeechSynthesizer* speech_synthesizer_; + +void InitializeSpeechSynthesizer() { + if (!speech_synthesizer_) + speech_synthesizer_ = [[NSSpeechSynthesizer alloc] init]; +} + +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]; + } + } + + return + [speech_synthesizer_ startSpeakingString: + [NSString stringWithUTF8String: utterance.c_str()]]; +} + +bool ExtensionTtsStopSpeakingFunction::RunImpl() { + InitializeSpeechSynthesizer(); + [speech_synthesizer_ stopSpeaking]; + return true; +} + +bool ExtensionTtsIsSpeakingFunction::RunImpl() { + InitializeSpeechSynthesizer(); + return [speech_synthesizer_ isSpeaking]; +} diff --git a/chrome/browser/extensions/extension_tts_api_util.cc b/chrome/browser/extensions/extension_tts_api_util.cc new file mode 100644 index 0000000..ac5d53b --- /dev/null +++ b/chrome/browser/extensions/extension_tts_api_util.cc @@ -0,0 +1,38 @@ +// 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_util.h" + +namespace extension_tts_api_util { + +// Static. +bool ReadNumberByKey(DictionaryValue* dict, + const char* key, + double* ret_value) { + Value* value; + if (!dict->Get(key, &value)) + return false; + + if (value->IsType(Value::TYPE_INTEGER)) { + int int_value; + if (!dict->GetInteger(key, &int_value)) + return false; + *ret_value = int_value; + } else if (value->IsType(Value::TYPE_REAL)) { + if (!dict->GetReal(key, ret_value)) + return false; + } else { + return false; + } + return true; +} + +// Static. +void AppendSpeakOption(std::string key, + std::string value, + std::string* options) { + *options += key + kEqualStr + value + kDelimiter; +} + +} // namespace extension_tts_api_util. diff --git a/chrome/browser/extensions/extension_tts_api_util.h b/chrome/browser/extensions/extension_tts_api_util.h new file mode 100644 index 0000000..4b41871 --- /dev/null +++ b/chrome/browser/extensions/extension_tts_api_util.h @@ -0,0 +1,32 @@ +// 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. + +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_UTIL_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_UTIL_H_ + +#include <string> + +#include "base/values.h" + +namespace extension_tts_api_util { + +const char kNameKey[] = "name"; +const char kLanguageNameKey[] = "languageName"; +const char kGenderKey[] = "gender"; +const char kRateKey[] = "rate"; +const char kPitchKey[] = "pitch"; +const char kVolumeKey[] = "volume"; +const char kEqualStr[] = "="; +const char kDelimiter[] = ";"; + +bool ReadNumberByKey(DictionaryValue* dict, + const char* key, + double* ret_value); + +void AppendSpeakOption(std::string key, + std::string value, + std::string* options); + +} // namespace extension_tts_api_util. +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_UTIL_H_ diff --git a/chrome/browser/extensions/extension_tts_api_win.cc b/chrome/browser/extensions/extension_tts_api_win.cc index 260d047..480880b 100644 --- a/chrome/browser/extensions/extension_tts_api_win.cc +++ b/chrome/browser/extensions/extension_tts_api_win.cc @@ -1,86 +1,123 @@ -// 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"
-
-#include <atlbase.h>
-#include <atlcom.h>
-#include <sapi.h>
-
-#include "base/scoped_comptr_win.h"
-#include "base/singleton.h"
-#include "base/values.h"
-
-class SpeechSynthesizerWrapper {
- public:
- SpeechSynthesizerWrapper() : speech_synthesizer_(NULL),
- paused_(false),
- permanent_failure_(false) {
- InitializeSpeechSynthesizer();
- }
-
- 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;
- }
-
- ScopedComPtr<ISpVoice> speech_synthesizer() {
- return speech_synthesizer_;
- }
-
- bool paused() {
- return paused_;
- }
-
- void paused(bool state) {
- paused_ = state;
- }
-
- private:
- ScopedComPtr<ISpVoice> speech_synthesizer_;
- bool paused_;
- // Indicates an error retrieving the SAPI COM interface.
- bool permanent_failure_;
-};
-
-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));
- if (SpeechSynthesizerSingleton::get()->paused())
- speech_synthesizer->Resume();
- speech_synthesizer->Speak(
- utterance.c_str(), SPF_ASYNC | SPF_PURGEBEFORESPEAK, NULL);
- return true;
- }
-
- return false;
-}
-
-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);
- }
- return true;
-}
-
-bool ExtensionTtsIsSpeakingFunction::RunImpl() {
- return false;
-}
+// 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 <atlbase.h> +#include <atlcom.h> +#include <sapi.h> + +#include "base/scoped_comptr_win.h" +#include "base/singleton.h" +#include "base/string_number_conversions.h" +#include "base/values.h" + +namespace util = extension_tts_api_util; + +class SpeechSynthesizerWrapper { + public: + SpeechSynthesizerWrapper() : speech_synthesizer_(NULL), + paused_(false), + permanent_failure_(false) { + InitializeSpeechSynthesizer(); + } + + 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; + } + + ScopedComPtr<ISpVoice> speech_synthesizer() { + return speech_synthesizer_; + } + + bool paused() { + return paused_; + } + + void paused(bool state) { + paused_ = state; + } + + private: + ScopedComPtr<ISpVoice> speech_synthesizer_; + bool paused_; + // Indicates an error retrieving the SAPI COM interface. + bool permanent_failure_; +}; + +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; + } + + return false; +} + +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); + } + return true; +} + +bool ExtensionTtsIsSpeakingFunction::RunImpl() { + return false; +} diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index e7f007b..5032f92 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1468,6 +1468,8 @@ 'browser/extensions/extension_tts_api.h', 'browser/extensions/extension_tts_api_gtk.cc', 'browser/extensions/extension_tts_api_mac.mm', + 'browser/extensions/extension_tts_api_util.cc', + 'browser/extensions/extension_tts_api_util.h', 'browser/extensions/extension_tts_api_win.cc', 'browser/extensions/extension_toolbar_model.cc', 'browser/extensions/extension_toolbar_model.h', |