summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordtseng@chromium.org <dtseng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-15 22:33:38 +0000
committerdtseng@chromium.org <dtseng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-15 22:33:38 +0000
commit5686e18f9855098f6b0993549e3243e4d4f7f947 (patch)
tree9c29fc0a7b16778095d0fbf716c6506a0e5356f8
parent6827bceba32719b03a6cf49faf0b2cde17685f2f (diff)
downloadchromium_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.cc69
-rw-r--r--chrome/browser/extensions/extension_tts_api.h2
-rw-r--r--chrome/browser/extensions/extension_tts_api_mac.mm108
-rw-r--r--chrome/browser/extensions/extension_tts_api_util.cc38
-rw-r--r--chrome/browser/extensions/extension_tts_api_util.h32
-rw-r--r--chrome/browser/extensions/extension_tts_api_win.cc209
-rw-r--r--chrome/chrome_browser.gypi2
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',