Merge change 4398 into donut

* changes:
  Using Locale to specify language and country for a TTS language to load, rather than a String. Cleanup in doc for TextToSpeech, and addition of queue mode constants.
This commit is contained in:
Android (Google) Code Review
2009-06-17 10:36:43 -07:00
5 changed files with 64 additions and 62 deletions

View File

@@ -39,7 +39,7 @@ interface ITts {
void addSpeechFile(in String text, in String filename); void addSpeechFile(in String text, in String filename);
void setLanguage(in String language); void setLanguage(in String language, in String country, in String variant);
boolean synthesizeToFile(in String text, in String[] params, in String outputDirectory); boolean synthesizeToFile(in String text, in String[] params, in String outputDirectory);

View File

@@ -22,13 +22,12 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale;
/** /**
* *
@@ -36,7 +35,7 @@ import java.util.HashMap;
* *
* {@hide} * {@hide}
*/ */
//TODO #TTS# review + complete javadoc //TODO #TTS# review + complete javadoc + add links to constants
public class TextToSpeech { public class TextToSpeech {
/** /**
@@ -52,9 +51,18 @@ public class TextToSpeech {
*/ */
public static final int TTS_ERROR_MISSING_RESOURCE = -2; public static final int TTS_ERROR_MISSING_RESOURCE = -2;
/**
* Queue mode where all entries in the playback queue (media to be played
* and text to be synthesized) are dropped and replaced by the new entry.
*/
public static final int TTS_QUEUE_FLUSH = 0;
/**
* Queue mode where the new entry is added at the end of the playback queue.
*/
public static final int TTS_QUEUE_ADD = 1;
/** /**
* Called when the TTS has initialized * Called when the TTS has initialized.
* *
* The InitListener must implement the onInit function. onInit is passed a * The InitListener must implement the onInit function. onInit is passed a
* status code indicating the result of the TTS initialization. * status code indicating the result of the TTS initialization.
@@ -73,9 +81,9 @@ public class TextToSpeech {
} }
/** /**
* Connection needed for the TTS * Connection needed for the TTS.
*/ */
private ServiceConnection serviceConnection; private ServiceConnection mServiceConnection;
private ITts mITts = null; private ITts mITts = null;
private Context mContext = null; private Context mContext = null;
@@ -104,8 +112,7 @@ public class TextToSpeech {
} }
public void setOnSpeechCompletedListener( public void setOnSpeechCompletedListener(final OnSpeechCompletedListener listener) {
final OnSpeechCompletedListener listener) {
synchronized(mSpeechCompListenerLock) { synchronized(mSpeechCompListenerLock) {
mSpeechCompListener = listener; mSpeechCompListener = listener;
} }
@@ -126,7 +133,7 @@ public class TextToSpeech {
mStarted = false; mStarted = false;
// Initialize the TTS, run the callback after the binding is successful // Initialize the TTS, run the callback after the binding is successful
serviceConnection = new ServiceConnection() { mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
synchronized(mStartLock) { synchronized(mStartLock) {
mITts = ITts.Stub.asInterface(service); mITts = ITts.Stub.asInterface(service);
@@ -176,7 +183,7 @@ public class TextToSpeech {
Intent intent = new Intent("android.intent.action.USE_TTS"); Intent intent = new Intent("android.intent.action.USE_TTS");
intent.addCategory("android.intent.category.TTS"); intent.addCategory("android.intent.category.TTS");
mContext.bindService(intent, serviceConnection, mContext.bindService(intent, mServiceConnection,
Context.BIND_AUTO_CREATE); Context.BIND_AUTO_CREATE);
// TODO handle case where the binding works (should always work) but // TODO handle case where the binding works (should always work) but
// the plugin fails // the plugin fails
@@ -190,7 +197,7 @@ public class TextToSpeech {
*/ */
public void shutdown() { public void shutdown() {
try { try {
mContext.unbindService(serviceConnection); mContext.unbindService(mServiceConnection);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
// Do nothing and fail silently since an error here indicates that // Do nothing and fail silently since an error here indicates that
// binding never succeeded in the first place. // binding never succeeded in the first place.
@@ -291,8 +298,8 @@ public class TextToSpeech {
* @param text * @param text
* The string of text to be spoken. * The string of text to be spoken.
* @param queueMode * @param queueMode
* The queuing strategy to use. Use 0 for no queuing, and 1 for * The queuing strategy to use.
* queuing. * See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
* @param params * @param params
* The hashmap of speech parameters to be used. * The hashmap of speech parameters to be used.
*/ */
@@ -329,12 +336,11 @@ public class TextToSpeech {
* @param earcon * @param earcon
* The earcon that should be played * The earcon that should be played
* @param queueMode * @param queueMode
* 0 for no queue (interrupts all previous utterances), 1 for * See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
* queued
* @param params * @param params
* The hashmap of parameters to be used. * The hashmap of parameters to be used.
*/ */
public void playEarcon(String earcon, int queueMode, public void playEarcon(String earcon, int queueMode,
HashMap<String,String> params) { HashMap<String,String> params) {
synchronized (mStartLock) { synchronized (mStartLock) {
if (!mStarted) { if (!mStarted) {
@@ -358,8 +364,8 @@ public class TextToSpeech {
} }
} }
} }
public void playSilence(long durationInMs, int queueMode) { public void playSilence(long durationInMs, int queueMode) {
// TODO implement, already present in TTS service // TODO implement, already present in TTS service
} }
@@ -429,20 +435,22 @@ public class TextToSpeech {
* Note that the speech rate is not universally supported by all engines and * Note that the speech rate is not universally supported by all engines and
* will be treated as a hint. The TTS library will try to use the specified * will be treated as a hint. The TTS library will try to use the specified
* speech rate, but there is no guarantee. * speech rate, but there is no guarantee.
* * This has no effect on any pre-recorded speech.
* Currently, this will change the speech rate for the espeak engine, but it
* has no effect on any pre-recorded speech.
* *
* @param speechRate * @param speechRate
* The speech rate for the TTS engine. * The speech rate for the TTS engine. 1 is the normal speed,
* lower values slow down the speech (0.5 is half the normal speech rate),
* greater values accelerate it (2 is twice the normal speech rate).
*/ */
public void setSpeechRate(int speechRate) { public void setSpeechRate(float speechRate) {
synchronized (mStartLock) { synchronized (mStartLock) {
if (!mStarted) { if (!mStarted) {
return; return;
} }
try { try {
mITts.setSpeechRate(speechRate); if (speechRate > 0) {
mITts.setSpeechRate((int)(speechRate*100));
}
} catch (RemoteException e) { } catch (RemoteException e) {
// TTS died; restart it. // TTS died; restart it.
mStarted = false; mStarted = false;
@@ -457,24 +465,18 @@ public class TextToSpeech {
* *
* Note that the language is not universally supported by all engines and * Note that the language is not universally supported by all engines and
* will be treated as a hint. The TTS library will try to use the specified * will be treated as a hint. The TTS library will try to use the specified
* language, but there is no guarantee. * language as represented by the Locale, but there is no guarantee.
* *
* Currently, this will change the language for the espeak engine, but it * @param loc
* has no effect on any pre-recorded speech. * The locale describing the language to be used.
*
* @param language
* The language to be used. The languages are specified by their
* IETF language tags as defined by BCP 47. This is the same
* standard used for the lang attribute in HTML. See:
* http://en.wikipedia.org/wiki/IETF_language_tag
*/ */
public void setLanguage(String language) { public void setLanguage(Locale loc) {
synchronized (mStartLock) { synchronized (mStartLock) {
if (!mStarted) { if (!mStarted) {
return; return;
} }
try { try {
mITts.setLanguage(language); mITts.setLanguage(loc.getISO3Language(), loc.getISO3Country(), loc.getVariant());
} catch (RemoteException e) { } catch (RemoteException e) {
// TTS died; restart it. // TTS died; restart it.
mStarted = false; mStarted = false;

View File

@@ -269,10 +269,10 @@ android_tts_SynthProxy_native_finalize(JNIEnv *env, jobject thiz, jint jniData)
} }
} }
// TODO update to use language, country, variant
static void static void
android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData, android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData,
jstring language) jstring language, jstring country, jstring variant)
{ {
if (jniData == 0) { if (jniData == 0) {
LOGE("android_tts_SynthProxy_setLanguage(): invalid JNI data"); LOGE("android_tts_SynthProxy_setLanguage(): invalid JNI data");
@@ -281,14 +281,16 @@ android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData,
SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData; SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
const char *langNativeString = env->GetStringUTFChars(language, 0); const char *langNativeString = env->GetStringUTFChars(language, 0);
const char *countryNativeString = env->GetStringUTFChars(country, 0);
const char *variantNativeString = env->GetStringUTFChars(variant, 0);
// TODO check return codes // TODO check return codes
if (pSynthData->mNativeSynthInterface) { if (pSynthData->mNativeSynthInterface) {
// TODO update to use language, country, variant pSynthData->mNativeSynthInterface->setLanguage(langNativeString, countryNativeString,
// commented out to not break the build variantNativeString);
//pSynthData->mNativeSynthInterface->setLanguage(langNativeString,
// strlen(langNativeString));
} }
env->ReleaseStringUTFChars(language, langNativeString); env->ReleaseStringUTFChars(language, langNativeString);
env->ReleaseStringUTFChars(language, countryNativeString);
env->ReleaseStringUTFChars(language, variantNativeString);
} }
@@ -496,6 +498,7 @@ android_tts_SynthProxy_getLanguage(JNIEnv *env, jobject thiz, jint jniData)
return env->NewStringUTF(buf); return env->NewStringUTF(buf);
} }
JNIEXPORT int JNICALL JNIEXPORT int JNICALL
android_tts_SynthProxy_getRate(JNIEnv *env, jobject thiz, jint jniData) android_tts_SynthProxy_getRate(JNIEnv *env, jobject thiz, jint jniData)
{ {
@@ -531,7 +534,7 @@ static JNINativeMethod gMethods[] = {
(void*)android_tts_SynthProxy_synthesizeToFile (void*)android_tts_SynthProxy_synthesizeToFile
}, },
{ "native_setLanguage", { "native_setLanguage",
"(ILjava/lang/String;)V", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
(void*)android_tts_SynthProxy_setLanguage (void*)android_tts_SynthProxy_setLanguage
}, },
{ "native_setSpeechRate", { "native_setSpeechRate",
@@ -567,7 +570,6 @@ static JNINativeMethod gMethods[] = {
#define SP_JNIDATA_FIELD_NAME "mJniData" #define SP_JNIDATA_FIELD_NAME "mJniData"
#define SP_POSTSPEECHSYNTHESIZED_METHOD_NAME "postNativeSpeechSynthesizedInJava" #define SP_POSTSPEECHSYNTHESIZED_METHOD_NAME "postNativeSpeechSynthesizedInJava"
// TODO: verify this is the correct path
static const char* const kClassPathName = "android/tts/SynthProxy"; static const char* const kClassPathName = "android/tts/SynthProxy";
jint JNI_OnLoad(JavaVM* vm, void* reserved) jint JNI_OnLoad(JavaVM* vm, void* reserved)

View File

@@ -70,8 +70,8 @@ public class SynthProxy {
/** /**
* Sets the language * Sets the language
*/ */
public void setLanguage(String language) { public void setLanguage(String language, String country, String variant) {
native_setLanguage(mJniData, language); native_setLanguage(mJniData, language, country, variant);
} }
/** /**
@@ -141,7 +141,8 @@ public class SynthProxy {
private native final void native_synthesizeToFile(int jniData, String text, String filename); private native final void native_synthesizeToFile(int jniData, String text, String filename);
private native final void native_setLanguage(int jniData, String language); private native final void native_setLanguage(int jniData, String language, String country,
String variant);
private native final void native_setSpeechRate(int jniData, int speechRate); private native final void native_setSpeechRate(int jniData, int speechRate);

View File

@@ -129,7 +129,9 @@ public class TtsService extends Service implements OnCompletionListener {
mSpeechQueue = new ArrayList<SpeechItem>(); mSpeechQueue = new ArrayList<SpeechItem>();
mPlayer = null; mPlayer = null;
setLanguage(prefs.getString("lang_pref", "en-rUS")); // TODO set default settings
//setLanguage(prefs.getString("lang_pref", "en-rUS"));
setLanguage("eng", "USA", "");
setSpeechRate(Integer.parseInt(prefs.getString("rate_pref", "140"))); setSpeechRate(Integer.parseInt(prefs.getString("rate_pref", "140")));
} }
@@ -155,7 +157,7 @@ public class TtsService extends Service implements OnCompletionListener {
nativeSynth.setSpeechRate(rate); nativeSynth.setSpeechRate(rate);
} }
private void setLanguage(String lang) { private void setLanguage(String lang, String country, String variant) {
if (prefs.getBoolean("override_pref", false)) { if (prefs.getBoolean("override_pref", false)) {
// This is set to the default here so that the preview in the prefs // This is set to the default here so that the preview in the prefs
// activity will show the change without a restart, even if apps are // activity will show the change without a restart, even if apps are
@@ -163,7 +165,8 @@ public class TtsService extends Service implements OnCompletionListener {
// allowed to change the defaults. // allowed to change the defaults.
lang = prefs.getString("lang_pref", "en-rUS"); lang = prefs.getString("lang_pref", "en-rUS");
} }
nativeSynth.setLanguage(lang); Log.v("TTS", "TtsService.setLanguage("+lang+", "+country+", "+variant+")");
nativeSynth.setLanguage(lang, country, variant);
} }
/** /**
@@ -683,20 +686,14 @@ public class TtsService extends Service implements OnCompletionListener {
} }
/** /**
* Sets the speech rate for the TTS. Note that this will only have an * Sets the speech rate for the TTS, which affects the synthesized voice.
* effect on synthesized speech; it will not affect pre-recorded speech.
* *
* @param language * @param lang the three letter ISO language code.
* Language values are based on the Android conventions for * @param country the three letter ISO country code.
* localization as described in the Android platform * @param variant the variant code associated with the country and language pair.
* documentation on internationalization. This implies that
* language data is specified in the format xx-rYY, where xx
* is a two letter ISO 639-1 language code in lowercase and
* rYY is a two letter ISO 3166-1-alpha-2 language code in
* uppercase preceded by a lowercase "r".
*/ */
public void setLanguage(String language) { public void setLanguage(String lang, String country, String variant) {
mSelf.setLanguage(language); mSelf.setLanguage(lang, country, variant);
} }
/** /**