Loading packages/TtsService/jni/android_tts_SynthProxy.cpp +24 −18 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,8 @@ #define DEFAULT_TTS_FORMAT AudioSystem::PCM_16_BIT #define DEFAULT_TTS_FORMAT AudioSystem::PCM_16_BIT #define DEFAULT_TTS_NB_CHANNELS 1 #define DEFAULT_TTS_NB_CHANNELS 1 #define DEFAULT_TTS_BUFFERSIZE 1024 #define DEFAULT_TTS_BUFFERSIZE 1024 // TODO use the TTS stream type when available #define DEFAULT_TTS_STREAM_TYPE AudioSystem::MUSIC #define USAGEMODE_PLAY_IMMEDIATELY 0 #define USAGEMODE_PLAY_IMMEDIATELY 0 #define USAGEMODE_WRITE_TO_FILE 1 #define USAGEMODE_WRITE_TO_FILE 1 Loading @@ -46,10 +48,12 @@ struct fields_t { jmethodID synthProxyMethodPost; jmethodID synthProxyMethodPost; }; }; // structure to hold the data that is used each time the TTS engine has synthesized more data struct afterSynthData_t { struct afterSynthData_t { jint jniStorage; jint jniStorage; int usageMode; int usageMode; FILE* outputFile; FILE* outputFile; AudioSystem::stream_type streamType; }; }; // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- Loading @@ -62,6 +66,7 @@ class SynthProxyJniStorage { jobject tts_ref; jobject tts_ref; TtsEngine* mNativeSynthInterface; TtsEngine* mNativeSynthInterface; AudioTrack* mAudioOut; AudioTrack* mAudioOut; AudioSystem::stream_type mStreamType; uint32_t mSampleRate; uint32_t mSampleRate; AudioSystem::audio_format mAudFormat; AudioSystem::audio_format mAudFormat; int mNbChannels; int mNbChannels; Loading @@ -73,6 +78,7 @@ class SynthProxyJniStorage { tts_ref = NULL; tts_ref = NULL; mNativeSynthInterface = NULL; mNativeSynthInterface = NULL; mAudioOut = NULL; mAudioOut = NULL; mStreamType = DEFAULT_TTS_STREAM_TYPE; mSampleRate = DEFAULT_TTS_RATE; mSampleRate = DEFAULT_TTS_RATE; mAudFormat = DEFAULT_TTS_FORMAT; mAudFormat = DEFAULT_TTS_FORMAT; mNbChannels = DEFAULT_TTS_NB_CHANNELS; mNbChannels = DEFAULT_TTS_NB_CHANNELS; Loading @@ -97,34 +103,33 @@ class SynthProxyJniStorage { } } } } void createAudioOut(uint32_t rate, AudioSystem::audio_format format, void createAudioOut(AudioSystem::stream_type streamType, uint32_t rate, int channel) { AudioSystem::audio_format format, int channel) { mSampleRate = rate; mSampleRate = rate; mAudFormat = format; mAudFormat = format; mNbChannels = channel; mNbChannels = channel; // TODO use the TTS stream type mStreamType = streamType; int streamType = AudioSystem::MUSIC; // retrieve system properties to ensure successful creation of the // retrieve system properties to ensure successful creation of the // AudioTrack object for playback // AudioTrack object for playback int afSampleRate; int afSampleRate; if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) { afSampleRate = 44100; afSampleRate = 44100; } } int afFrameCount; int afFrameCount; if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) { afFrameCount = 2048; afFrameCount = 2048; } } uint32_t afLatency; uint32_t afLatency; if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) { if (AudioSystem::getOutputLatency(&afLatency, mStreamType) != NO_ERROR) { afLatency = 500; afLatency = 500; } } uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate); uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate); if (minBufCount < 2) minBufCount = 2; if (minBufCount < 2) minBufCount = 2; int minFrameCount = (afFrameCount * rate * minBufCount)/afSampleRate; int minFrameCount = (afFrameCount * rate * minBufCount)/afSampleRate; mAudioOut = new AudioTrack(streamType, rate, format, channel, mAudioOut = new AudioTrack(mStreamType, rate, format, channel, minFrameCount > 4096 ? minFrameCount : 4096, minFrameCount > 4096 ? minFrameCount : 4096, 0, 0, 0, 0); // not using an AudioTrack callback 0, 0, 0, 0); // not using an AudioTrack callback Loading @@ -142,21 +147,21 @@ class SynthProxyJniStorage { // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- void prepAudioTrack(SynthProxyJniStorage* pJniData, void prepAudioTrack(SynthProxyJniStorage* pJniData, AudioSystem::stream_type streamType, uint32_t rate, AudioSystem::audio_format format, int channel) uint32_t rate, AudioSystem::audio_format format, int channel) { { // Don't bother creating a new audiotrack object if the current // Don't bother creating a new audiotrack object if the current // object is already set. // object is already initialized with the same audio parameters. if ( pJniData->mAudioOut && if ( pJniData->mAudioOut && (rate == pJniData->mSampleRate) && (rate == pJniData->mSampleRate) && (format == pJniData->mAudFormat) && (format == pJniData->mAudFormat) && (channel == pJniData->mNbChannels) ){ (channel == pJniData->mNbChannels) && (streamType == pJniData->mStreamType) ){ return; return; } } if (pJniData->mAudioOut){ if (pJniData->mAudioOut){ pJniData->killAudio(); pJniData->killAudio(); } } pJniData->createAudioOut(rate, format, channel); pJniData->createAudioOut(streamType, rate, format, channel); } } Loading Loading @@ -186,7 +191,7 @@ static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate, } } if (bufferSize > 0) { if (bufferSize > 0) { prepAudioTrack(pJniData, rate, format, channel); prepAudioTrack(pJniData, pForAfter->streamType, rate, format, channel); if (pJniData->mAudioOut) { if (pJniData->mAudioOut) { pJniData->mAudioOut->write(wav, bufferSize); pJniData->mAudioOut->write(wav, bufferSize); //LOGV("AudioTrack wrote: %d bytes", bufferSize); //LOGV("AudioTrack wrote: %d bytes", bufferSize); Loading Loading @@ -241,7 +246,7 @@ android_tts_SynthProxy_native_setup(JNIEnv *env, jobject thiz, SynthProxyJniStorage* pJniStorage = new SynthProxyJniStorage(); SynthProxyJniStorage* pJniStorage = new SynthProxyJniStorage(); prepAudioTrack(pJniStorage, prepAudioTrack(pJniStorage, DEFAULT_TTS_RATE, DEFAULT_TTS_FORMAT, DEFAULT_TTS_NB_CHANNELS); DEFAULT_TTS_STREAM_TYPE, DEFAULT_TTS_RATE, DEFAULT_TTS_FORMAT, DEFAULT_TTS_NB_CHANNELS); const char *nativeSoLibNativeString = const char *nativeSoLibNativeString = env->GetStringUTFChars(nativeSoLib, 0); env->GetStringUTFChars(nativeSoLib, 0); Loading Loading @@ -526,7 +531,7 @@ android_tts_SynthProxy_synthesizeToFile(JNIEnv *env, jobject thiz, jint jniData, static int static int android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData, android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData, jstring textJavaString) jstring textJavaString, jint javaStreamType) { { int result = TTS_FAILURE; int result = TTS_FAILURE; Loading @@ -545,6 +550,7 @@ android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData, afterSynthData_t* pForAfter = new (afterSynthData_t); afterSynthData_t* pForAfter = new (afterSynthData_t); pForAfter->jniStorage = jniData; pForAfter->jniStorage = jniData; pForAfter->usageMode = USAGEMODE_PLAY_IMMEDIATELY; pForAfter->usageMode = USAGEMODE_PLAY_IMMEDIATELY; pForAfter->streamType = (AudioSystem::stream_type) javaStreamType; if (pSynthData->mNativeSynthInterface) { if (pSynthData->mNativeSynthInterface) { const char *textNativeString = env->GetStringUTFChars(textJavaString, 0); const char *textNativeString = env->GetStringUTFChars(textJavaString, 0); Loading Loading @@ -672,7 +678,7 @@ static JNINativeMethod gMethods[] = { (void*)android_tts_SynthProxy_stop (void*)android_tts_SynthProxy_stop }, }, { "native_speak", { "native_speak", "(ILjava/lang/String;)I", "(ILjava/lang/String;I)I", (void*)android_tts_SynthProxy_speak (void*)android_tts_SynthProxy_speak }, }, { "native_synthesizeToFile", { "native_synthesizeToFile", Loading packages/TtsService/src/android/tts/SynthProxy.java +10 −3 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ */ package android.tts; package android.tts; import android.media.AudioManager; import android.media.AudioSystem; import android.util.Log; import android.util.Log; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; Loading Loading @@ -52,8 +54,13 @@ public class SynthProxy { /** /** * Synthesize speech and speak it directly using AudioTrack. * Synthesize speech and speak it directly using AudioTrack. */ */ public int speak(String text) { public int speak(String text, int streamType) { return native_speak(mJniData, text); if ((streamType > -1) && (streamType < AudioSystem.getNumStreamTypes())) { return native_speak(mJniData, text, streamType); } else { Log.e("SynthProxy", "Trying to speak with invalid stream type " + streamType); return native_speak(mJniData, text, AudioManager.STREAM_MUSIC); } } } /** /** Loading Loading @@ -156,7 +163,7 @@ public class SynthProxy { private native final int native_stop(int jniData); private native final int native_stop(int jniData); private native final int native_speak(int jniData, String text); private native final int native_speak(int jniData, String text, int streamType); private native final int native_synthesizeToFile(int jniData, String text, String filename); private native final int native_synthesizeToFile(int jniData, String text, String filename); Loading packages/TtsService/src/android/tts/TtsService.java +33 −5 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnCompletionListener; import android.net.Uri; import android.net.Uri; Loading Loading @@ -109,6 +110,8 @@ public class TtsService extends Service implements OnCompletionListener { private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000; private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000; private static final int MAX_FILENAME_LENGTH = 250; private static final int MAX_FILENAME_LENGTH = 250; // TODO use the TTS stream type when available private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_MUSIC; private static final String ACTION = "android.intent.action.START_TTS_SERVICE"; private static final String ACTION = "android.intent.action.START_TTS_SERVICE"; private static final String CATEGORY = "android.intent.category.TTS"; private static final String CATEGORY = "android.intent.category.TTS"; Loading Loading @@ -450,6 +453,7 @@ public class TtsService extends Service implements OnCompletionListener { synth.start(); synth.start(); return; return; } } int streamType = DEFAULT_STREAM_TYPE; if (params != null){ if (params != null){ String language = ""; String language = ""; String country = ""; String country = ""; Loading @@ -465,6 +469,12 @@ public class TtsService extends Service implements OnCompletionListener { country = params.get(i+1); country = params.get(i+1); } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){ } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){ variant = params.get(i+1); variant = params.get(i+1); } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_STREAM)) { try { streamType = Integer.parseInt(params.get(i + 1)); } catch (NumberFormatException e) { streamType = DEFAULT_STREAM_TYPE; } } } } } } } Loading @@ -472,7 +482,7 @@ public class TtsService extends Service implements OnCompletionListener { setLanguage("", language, country, variant); setLanguage("", language, country, variant); } } } } nativeSynth.speak(text); nativeSynth.speak(text, streamType); } catch (InterruptedException e) { } catch (InterruptedException e) { Log.e("TTS speakInternalOnly", "tryLock interrupted"); Log.e("TTS speakInternalOnly", "tryLock interrupted"); e.printStackTrace(); e.printStackTrace(); Loading Loading @@ -651,8 +661,7 @@ public class TtsService extends Service implements OnCompletionListener { // Utterance is part of the app calling the library // Utterance is part of the app calling the library Context ctx; Context ctx; try { try { ctx = this.createPackageContext(sr.mSourcePackageName, ctx = this.createPackageContext(sr.mSourcePackageName, 0); 0); } catch (NameNotFoundException e) { } catch (NameNotFoundException e) { e.printStackTrace(); e.printStackTrace(); mSpeechQueue.remove(0); // Remove it from the queue and mSpeechQueue.remove(0); // Remove it from the queue and Loading @@ -675,6 +684,7 @@ public class TtsService extends Service implements OnCompletionListener { } } mPlayer.setOnCompletionListener(this); mPlayer.setOnCompletionListener(this); try { try { mPlayer.setAudioStreamType(getStreamTypeFromParams(currentSpeechItem.mParams)); mPlayer.start(); mPlayer.start(); } catch (IllegalStateException e) { } catch (IllegalStateException e) { mSpeechQueue.clear(); mSpeechQueue.clear(); Loading @@ -695,6 +705,24 @@ public class TtsService extends Service implements OnCompletionListener { } } } } private int getStreamTypeFromParams(ArrayList<String> paramList) { int streamType = DEFAULT_STREAM_TYPE; if (paramList == null) { return streamType; } for (int i = 0; i < paramList.size() - 1; i = i + 2) { String param = paramList.get(i); if ((param != null) && (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_STREAM))) { try { streamType = Integer.parseInt(paramList.get(i + 1)); } catch (NumberFormatException e) { streamType = DEFAULT_STREAM_TYPE; } } } return streamType; } private void cleanUpPlayer() { private void cleanUpPlayer() { if (mPlayer != null) { if (mPlayer != null) { mPlayer.release(); mPlayer.release(); Loading Loading
packages/TtsService/jni/android_tts_SynthProxy.cpp +24 −18 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,8 @@ #define DEFAULT_TTS_FORMAT AudioSystem::PCM_16_BIT #define DEFAULT_TTS_FORMAT AudioSystem::PCM_16_BIT #define DEFAULT_TTS_NB_CHANNELS 1 #define DEFAULT_TTS_NB_CHANNELS 1 #define DEFAULT_TTS_BUFFERSIZE 1024 #define DEFAULT_TTS_BUFFERSIZE 1024 // TODO use the TTS stream type when available #define DEFAULT_TTS_STREAM_TYPE AudioSystem::MUSIC #define USAGEMODE_PLAY_IMMEDIATELY 0 #define USAGEMODE_PLAY_IMMEDIATELY 0 #define USAGEMODE_WRITE_TO_FILE 1 #define USAGEMODE_WRITE_TO_FILE 1 Loading @@ -46,10 +48,12 @@ struct fields_t { jmethodID synthProxyMethodPost; jmethodID synthProxyMethodPost; }; }; // structure to hold the data that is used each time the TTS engine has synthesized more data struct afterSynthData_t { struct afterSynthData_t { jint jniStorage; jint jniStorage; int usageMode; int usageMode; FILE* outputFile; FILE* outputFile; AudioSystem::stream_type streamType; }; }; // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- Loading @@ -62,6 +66,7 @@ class SynthProxyJniStorage { jobject tts_ref; jobject tts_ref; TtsEngine* mNativeSynthInterface; TtsEngine* mNativeSynthInterface; AudioTrack* mAudioOut; AudioTrack* mAudioOut; AudioSystem::stream_type mStreamType; uint32_t mSampleRate; uint32_t mSampleRate; AudioSystem::audio_format mAudFormat; AudioSystem::audio_format mAudFormat; int mNbChannels; int mNbChannels; Loading @@ -73,6 +78,7 @@ class SynthProxyJniStorage { tts_ref = NULL; tts_ref = NULL; mNativeSynthInterface = NULL; mNativeSynthInterface = NULL; mAudioOut = NULL; mAudioOut = NULL; mStreamType = DEFAULT_TTS_STREAM_TYPE; mSampleRate = DEFAULT_TTS_RATE; mSampleRate = DEFAULT_TTS_RATE; mAudFormat = DEFAULT_TTS_FORMAT; mAudFormat = DEFAULT_TTS_FORMAT; mNbChannels = DEFAULT_TTS_NB_CHANNELS; mNbChannels = DEFAULT_TTS_NB_CHANNELS; Loading @@ -97,34 +103,33 @@ class SynthProxyJniStorage { } } } } void createAudioOut(uint32_t rate, AudioSystem::audio_format format, void createAudioOut(AudioSystem::stream_type streamType, uint32_t rate, int channel) { AudioSystem::audio_format format, int channel) { mSampleRate = rate; mSampleRate = rate; mAudFormat = format; mAudFormat = format; mNbChannels = channel; mNbChannels = channel; // TODO use the TTS stream type mStreamType = streamType; int streamType = AudioSystem::MUSIC; // retrieve system properties to ensure successful creation of the // retrieve system properties to ensure successful creation of the // AudioTrack object for playback // AudioTrack object for playback int afSampleRate; int afSampleRate; if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) { afSampleRate = 44100; afSampleRate = 44100; } } int afFrameCount; int afFrameCount; if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) { afFrameCount = 2048; afFrameCount = 2048; } } uint32_t afLatency; uint32_t afLatency; if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) { if (AudioSystem::getOutputLatency(&afLatency, mStreamType) != NO_ERROR) { afLatency = 500; afLatency = 500; } } uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate); uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate); if (minBufCount < 2) minBufCount = 2; if (minBufCount < 2) minBufCount = 2; int minFrameCount = (afFrameCount * rate * minBufCount)/afSampleRate; int minFrameCount = (afFrameCount * rate * minBufCount)/afSampleRate; mAudioOut = new AudioTrack(streamType, rate, format, channel, mAudioOut = new AudioTrack(mStreamType, rate, format, channel, minFrameCount > 4096 ? minFrameCount : 4096, minFrameCount > 4096 ? minFrameCount : 4096, 0, 0, 0, 0); // not using an AudioTrack callback 0, 0, 0, 0); // not using an AudioTrack callback Loading @@ -142,21 +147,21 @@ class SynthProxyJniStorage { // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- void prepAudioTrack(SynthProxyJniStorage* pJniData, void prepAudioTrack(SynthProxyJniStorage* pJniData, AudioSystem::stream_type streamType, uint32_t rate, AudioSystem::audio_format format, int channel) uint32_t rate, AudioSystem::audio_format format, int channel) { { // Don't bother creating a new audiotrack object if the current // Don't bother creating a new audiotrack object if the current // object is already set. // object is already initialized with the same audio parameters. if ( pJniData->mAudioOut && if ( pJniData->mAudioOut && (rate == pJniData->mSampleRate) && (rate == pJniData->mSampleRate) && (format == pJniData->mAudFormat) && (format == pJniData->mAudFormat) && (channel == pJniData->mNbChannels) ){ (channel == pJniData->mNbChannels) && (streamType == pJniData->mStreamType) ){ return; return; } } if (pJniData->mAudioOut){ if (pJniData->mAudioOut){ pJniData->killAudio(); pJniData->killAudio(); } } pJniData->createAudioOut(rate, format, channel); pJniData->createAudioOut(streamType, rate, format, channel); } } Loading Loading @@ -186,7 +191,7 @@ static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate, } } if (bufferSize > 0) { if (bufferSize > 0) { prepAudioTrack(pJniData, rate, format, channel); prepAudioTrack(pJniData, pForAfter->streamType, rate, format, channel); if (pJniData->mAudioOut) { if (pJniData->mAudioOut) { pJniData->mAudioOut->write(wav, bufferSize); pJniData->mAudioOut->write(wav, bufferSize); //LOGV("AudioTrack wrote: %d bytes", bufferSize); //LOGV("AudioTrack wrote: %d bytes", bufferSize); Loading Loading @@ -241,7 +246,7 @@ android_tts_SynthProxy_native_setup(JNIEnv *env, jobject thiz, SynthProxyJniStorage* pJniStorage = new SynthProxyJniStorage(); SynthProxyJniStorage* pJniStorage = new SynthProxyJniStorage(); prepAudioTrack(pJniStorage, prepAudioTrack(pJniStorage, DEFAULT_TTS_RATE, DEFAULT_TTS_FORMAT, DEFAULT_TTS_NB_CHANNELS); DEFAULT_TTS_STREAM_TYPE, DEFAULT_TTS_RATE, DEFAULT_TTS_FORMAT, DEFAULT_TTS_NB_CHANNELS); const char *nativeSoLibNativeString = const char *nativeSoLibNativeString = env->GetStringUTFChars(nativeSoLib, 0); env->GetStringUTFChars(nativeSoLib, 0); Loading Loading @@ -526,7 +531,7 @@ android_tts_SynthProxy_synthesizeToFile(JNIEnv *env, jobject thiz, jint jniData, static int static int android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData, android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData, jstring textJavaString) jstring textJavaString, jint javaStreamType) { { int result = TTS_FAILURE; int result = TTS_FAILURE; Loading @@ -545,6 +550,7 @@ android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData, afterSynthData_t* pForAfter = new (afterSynthData_t); afterSynthData_t* pForAfter = new (afterSynthData_t); pForAfter->jniStorage = jniData; pForAfter->jniStorage = jniData; pForAfter->usageMode = USAGEMODE_PLAY_IMMEDIATELY; pForAfter->usageMode = USAGEMODE_PLAY_IMMEDIATELY; pForAfter->streamType = (AudioSystem::stream_type) javaStreamType; if (pSynthData->mNativeSynthInterface) { if (pSynthData->mNativeSynthInterface) { const char *textNativeString = env->GetStringUTFChars(textJavaString, 0); const char *textNativeString = env->GetStringUTFChars(textJavaString, 0); Loading Loading @@ -672,7 +678,7 @@ static JNINativeMethod gMethods[] = { (void*)android_tts_SynthProxy_stop (void*)android_tts_SynthProxy_stop }, }, { "native_speak", { "native_speak", "(ILjava/lang/String;)I", "(ILjava/lang/String;I)I", (void*)android_tts_SynthProxy_speak (void*)android_tts_SynthProxy_speak }, }, { "native_synthesizeToFile", { "native_synthesizeToFile", Loading
packages/TtsService/src/android/tts/SynthProxy.java +10 −3 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ */ package android.tts; package android.tts; import android.media.AudioManager; import android.media.AudioSystem; import android.util.Log; import android.util.Log; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; Loading Loading @@ -52,8 +54,13 @@ public class SynthProxy { /** /** * Synthesize speech and speak it directly using AudioTrack. * Synthesize speech and speak it directly using AudioTrack. */ */ public int speak(String text) { public int speak(String text, int streamType) { return native_speak(mJniData, text); if ((streamType > -1) && (streamType < AudioSystem.getNumStreamTypes())) { return native_speak(mJniData, text, streamType); } else { Log.e("SynthProxy", "Trying to speak with invalid stream type " + streamType); return native_speak(mJniData, text, AudioManager.STREAM_MUSIC); } } } /** /** Loading Loading @@ -156,7 +163,7 @@ public class SynthProxy { private native final int native_stop(int jniData); private native final int native_stop(int jniData); private native final int native_speak(int jniData, String text); private native final int native_speak(int jniData, String text, int streamType); private native final int native_synthesizeToFile(int jniData, String text, String filename); private native final int native_synthesizeToFile(int jniData, String text, String filename); Loading
packages/TtsService/src/android/tts/TtsService.java +33 −5 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnCompletionListener; import android.net.Uri; import android.net.Uri; Loading Loading @@ -109,6 +110,8 @@ public class TtsService extends Service implements OnCompletionListener { private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000; private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000; private static final int MAX_FILENAME_LENGTH = 250; private static final int MAX_FILENAME_LENGTH = 250; // TODO use the TTS stream type when available private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_MUSIC; private static final String ACTION = "android.intent.action.START_TTS_SERVICE"; private static final String ACTION = "android.intent.action.START_TTS_SERVICE"; private static final String CATEGORY = "android.intent.category.TTS"; private static final String CATEGORY = "android.intent.category.TTS"; Loading Loading @@ -450,6 +453,7 @@ public class TtsService extends Service implements OnCompletionListener { synth.start(); synth.start(); return; return; } } int streamType = DEFAULT_STREAM_TYPE; if (params != null){ if (params != null){ String language = ""; String language = ""; String country = ""; String country = ""; Loading @@ -465,6 +469,12 @@ public class TtsService extends Service implements OnCompletionListener { country = params.get(i+1); country = params.get(i+1); } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){ } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){ variant = params.get(i+1); variant = params.get(i+1); } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_STREAM)) { try { streamType = Integer.parseInt(params.get(i + 1)); } catch (NumberFormatException e) { streamType = DEFAULT_STREAM_TYPE; } } } } } } } Loading @@ -472,7 +482,7 @@ public class TtsService extends Service implements OnCompletionListener { setLanguage("", language, country, variant); setLanguage("", language, country, variant); } } } } nativeSynth.speak(text); nativeSynth.speak(text, streamType); } catch (InterruptedException e) { } catch (InterruptedException e) { Log.e("TTS speakInternalOnly", "tryLock interrupted"); Log.e("TTS speakInternalOnly", "tryLock interrupted"); e.printStackTrace(); e.printStackTrace(); Loading Loading @@ -651,8 +661,7 @@ public class TtsService extends Service implements OnCompletionListener { // Utterance is part of the app calling the library // Utterance is part of the app calling the library Context ctx; Context ctx; try { try { ctx = this.createPackageContext(sr.mSourcePackageName, ctx = this.createPackageContext(sr.mSourcePackageName, 0); 0); } catch (NameNotFoundException e) { } catch (NameNotFoundException e) { e.printStackTrace(); e.printStackTrace(); mSpeechQueue.remove(0); // Remove it from the queue and mSpeechQueue.remove(0); // Remove it from the queue and Loading @@ -675,6 +684,7 @@ public class TtsService extends Service implements OnCompletionListener { } } mPlayer.setOnCompletionListener(this); mPlayer.setOnCompletionListener(this); try { try { mPlayer.setAudioStreamType(getStreamTypeFromParams(currentSpeechItem.mParams)); mPlayer.start(); mPlayer.start(); } catch (IllegalStateException e) { } catch (IllegalStateException e) { mSpeechQueue.clear(); mSpeechQueue.clear(); Loading @@ -695,6 +705,24 @@ public class TtsService extends Service implements OnCompletionListener { } } } } private int getStreamTypeFromParams(ArrayList<String> paramList) { int streamType = DEFAULT_STREAM_TYPE; if (paramList == null) { return streamType; } for (int i = 0; i < paramList.size() - 1; i = i + 2) { String param = paramList.get(i); if ((param != null) && (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_STREAM))) { try { streamType = Integer.parseInt(paramList.get(i + 1)); } catch (NumberFormatException e) { streamType = DEFAULT_STREAM_TYPE; } } } return streamType; } private void cleanUpPlayer() { private void cleanUpPlayer() { if (mPlayer != null) { if (mPlayer != null) { mPlayer.release(); mPlayer.release(); Loading