diff options
author | David 'Digit' Turner <digit@google.com> | 2010-05-20 16:57:34 -0700 |
---|---|---|
committer | David 'Digit' Turner <digit@google.com> | 2010-06-11 18:02:51 -0700 |
commit | 01f2f960e73701633a169fbb2b777a4915a5b12c (patch) | |
tree | 6dac2d44f0b9df824a9fe3912e6b89d5066f7c42 | |
parent | 28d01123754b10dc467a344650238ba583159ec9 (diff) | |
download | frameworks_base-01f2f960e73701633a169fbb2b777a4915a5b12c.zip frameworks_base-01f2f960e73701633a169fbb2b777a4915a5b12c.tar.gz frameworks_base-01f2f960e73701633a169fbb2b777a4915a5b12c.tar.bz2 |
Improved native TTS interface header.
The purpose of this patch is to add a C-based ABI that can be exposed by the NDK
for developers wanting to write a TTS Engine. This replaces the C++ ABI that is
currently under frameworks/base/include/tts/TtsEngine.h but is *binary* compatible
with it.
As a consequence, the svox pico plugin under external/svox/pico/tts/, which
links against tts/TtsEngine.h can be loaded by the TTS service properly.
Another patch would modify the pico tts to use <android/tts.h>, then we will
be able to get rid of <tts/TtsEngine.h> in the source tree.
Change-Id: I16844cef9b5b006cc32655a29e4f9f193c8c1a91
-rw-r--r-- | native/include/android/tts.h | 308 | ||||
-rwxr-xr-x | packages/TtsService/jni/Android.mk | 1 | ||||
-rw-r--r-- | packages/TtsService/jni/android_tts_SynthProxy.cpp | 202 |
3 files changed, 437 insertions, 74 deletions
diff --git a/native/include/android/tts.h b/native/include/android/tts.h new file mode 100644 index 0000000..e5c99f7 --- /dev/null +++ b/native/include/android/tts.h @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ANDROID_TTS_H +#define ANDROID_TTS_H + +// This header defines the interface used by the Android platform +// to access Text-To-Speech functionality in shared libraries that implement +// speech synthesis and the management of resources associated with the +// synthesis. + +// The shared library must contain a function named "android_getTtsEngine" +// that returns an 'android_tts_engine_t' instance. + +#ifdef __cplusplus +extern "C" { +#endif + +#define ANDROID_TTS_ENGINE_PROPERTY_CONFIG "engineConfig" +#define ANDROID_TTS_ENGINE_PROPERTY_PITCH "pitch" +#define ANDROID_TTS_ENGINE_PROPERTY_RATE "rate" +#define ANDROID_TTS_ENGINE_PROPERTY_VOLUME "volume" + +typedef enum { + ANDROID_TTS_SUCCESS = 0, + ANDROID_TTS_FAILURE = -1, + ANDROID_TTS_FEATURE_UNSUPPORTED = -2, + ANDROID_TTS_VALUE_INVALID = -3, + ANDROID_TTS_PROPERTY_UNSUPPORTED = -4, + ANDROID_TTS_PROPERTY_SIZE_TOO_SMALL = -5, + ANDROID_TTS_MISSING_RESOURCES = -6 +} android_tts_result_t; + +typedef enum { + ANDROID_TTS_LANG_COUNTRY_VAR_AVAILABLE = 2, + ANDROID_TTS_LANG_COUNTRY_AVAILABLE = 1, + ANDROID_TTS_LANG_AVAILABLE = 0, + ANDROID_TTS_LANG_MISSING_DATA = -1, + ANDROID_TTS_LANG_NOT_SUPPORTED = -2 +} android_tts_support_result_t; + +typedef enum { + ANDROID_TTS_SYNTH_DONE = 0, + ANDROID_TTS_SYNTH_PENDING = 1 +} android_tts_synth_status_t; + +typedef enum { + ANDROID_TTS_CALLBACK_HALT = 0, + ANDROID_TTS_CALLBACK_CONTINUE = 1 +} android_tts_callback_status_t; + +// Supported audio formats +typedef enum { + ANDROID_TTS_AUDIO_FORMAT_INVALID = -1, + ANDROID_TTS_AUDIO_FORMAT_DEFAULT = 0, + ANDROID_TTS_AUDIO_FORMAT_PCM_16_BIT = 1, + ANDROID_TTS_AUDIO_FORMAT_PCM_8_BIT = 2, +} android_tts_audio_format_t; + + +/* An android_tts_engine_t object can be anything, but must have, + * as its first field, a pointer to a table of functions. + * + * See the full definition of struct android_tts_engine_t_funcs_t + * below for details. + */ +typedef struct android_tts_engine_funcs_t android_tts_engine_funcs_t; + +typedef struct { + android_tts_engine_funcs_t *funcs; +} android_tts_engine_t; + +/* This function must be located in the TTS Engine shared library + * and must return the address of an android_tts_engine_t library. + */ +extern android_tts_engine_t *android_getTtsEngine(); + +// A callback type used to notify the framework of new synthetized +// audio samples, status will be SYNTH_DONE for the last sample of +// the last request, of SYNTH_PENDING otherwise. +// +// This is passed by the framework to the engine through the +// 'engine_init' function (see below). +// +// The callback for synthesis completed takes: +// @param [inout] void *& - The userdata pointer set in the original +// synth call +// @param [in] uint32_t - Track sampling rate in Hz +// @param [in] uint32_t - The audio format +// @param [in] int - The number of channels +// @param [inout] int8_t *& - A buffer of audio data only valid during the +// execution of the callback +// @param [inout] size_t & - The size of the buffer +// @param [in] tts_synth_status - indicate whether the synthesis is done, or +// if more data is to be synthesized. +// @return TTS_CALLBACK_HALT to indicate the synthesis must stop, +// TTS_CALLBACK_CONTINUE to indicate the synthesis must continue if +// there is more data to produce. +typedef android_tts_callback_status_t (*android_tts_synth_cb_t) + (void **pUserData, + uint32_t trackSamplingHz, + android_tts_audio_format_t audioFormat, + int channelCount, + int8_t **pAudioBuffer, + size_t *pBufferSize, + android_tts_synth_status_t status); + + +// The table of function pointers that the android_tts_engine_t must point to. +// Note that each of these functions will take a handle to the engine itself +// as their first parameter. +// + +struct android_tts_engine_funcs_t { + // reserved fields, ignored by the framework + // they must be placed here to ensure binary compatibility + // of legacy binary plugins. + void *reserved[2]; + + // Initialize the TTS engine and returns whether initialization succeeded. + // @param synthDoneCBPtr synthesis callback function pointer + // @return TTS_SUCCESS, or TTS_FAILURE + android_tts_result_t (*init) + (void *engine, + android_tts_synth_cb_t synthDonePtr, + const char *engineConfig); + + // Shut down the TTS engine and releases all associated resources. + // @return TTS_SUCCESS, or TTS_FAILURE + android_tts_result_t (*shutdown) + (void *engine); + + // Interrupt synthesis and flushes any synthesized data that hasn't been + // output yet. This will block until callbacks underway are completed. + // @return TTS_SUCCESS, or TTS_FAILURE + android_tts_result_t (*stop) + (void *engine); + + // Returns the level of support for the language, country and variant. + // @return TTS_LANG_COUNTRY_VAR_AVAILABLE if the language, country and variant are supported, + // and the corresponding resources are correctly installed + // TTS_LANG_COUNTRY_AVAILABLE if the language and country are supported and the + // corresponding resources are correctly installed, but there is no match for + // the specified variant + // TTS_LANG_AVAILABLE if the language is supported and the + // corresponding resources are correctly installed, but there is no match for + // the specified country and variant + // TTS_LANG_MISSING_DATA if the required resources to provide any level of support + // for the language are not correctly installed + // TTS_LANG_NOT_SUPPORTED if the language is not supported by the TTS engine. + android_tts_support_result_t (*isLanguageAvailable) + (void *engine, + const char *lang, + const char *country, + const char *variant); + + // Load the resources associated with the specified language. The loaded + // language will only be used once a call to setLanguage() with the same + // language value is issued. Language and country values are coded according to the ISO three + // letter codes for languages and countries, as can be retrieved from a java.util.Locale + // instance. The variant value is encoded as the variant string retrieved from a + // java.util.Locale instance built with that variant data. + // @param lang pointer to the ISO three letter code for the language + // @param country pointer to the ISO three letter code for the country + // @param variant pointer to the variant code + // @return TTS_SUCCESS, or TTS_FAILURE + android_tts_result_t (*loadLanguage) + (void *engine, + const char *lang, + const char *country, + const char *variant); + + // Load the resources associated with the specified language, country and Locale variant. + // The loaded language will only be used once a call to setLanguageFromLocale() with the same + // language value is issued. Language and country values are coded according to the ISO three + // letter codes for languages and countries, as can be retrieved from a java.util.Locale + // instance. The variant value is encoded as the variant string retrieved from a + // java.util.Locale instance built with that variant data. + // @param lang pointer to the ISO three letter code for the language + // @param country pointer to the ISO three letter code for the country + // @param variant pointer to the variant code + // @return TTS_SUCCESS, or TTS_FAILURE + android_tts_result_t (*setLanguage) + (void *engine, + const char *lang, + const char *country, + const char *variant); + + // Retrieve the currently set language, country and variant, or empty strings if none of + // parameters have been set. Language and country are represented by their 3-letter ISO code + // @param[out] pointer to the retrieved 3-letter code language value + // @param[out] pointer to the retrieved 3-letter code country value + // @param[out] pointer to the retrieved variant value + // @return TTS_SUCCESS, or TTS_FAILURE + android_tts_result_t (*getLanguage) + (void *engine, + char *language, + char *country, + char *variant); + + // Notifies the engine what audio parameters should be used for the synthesis. + // This is meant to be used as a hint, the engine implementation will set the output values + // to those of the synthesis format, based on a given hint. + // @param[inout] encoding in: the desired audio sample format + // out: the format used by the TTS engine + // @param[inout] rate in: the desired audio sample rate + // out: the sample rate used by the TTS engine + // @param[inout] channels in: the desired number of audio channels + // out: the number of channels used by the TTS engine + // @return TTS_SUCCESS, or TTS_FAILURE + android_tts_result_t (*setAudioFormat) + (void *engine, + android_tts_audio_format_t* pEncoding, + uint32_t* pRate, + int* pChannels); + + // Set a property for the the TTS engine + // "size" is the maximum size of "value" for properties "property" + // @param property pointer to the property name + // @param value pointer to the property value + // @param size maximum size required to store this type of property + // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS, or TTS_FAILURE, + // or TTS_VALUE_INVALID + android_tts_result_t (*setProperty) + (void *engine, + const char *property, + const char *value, + const size_t size); + + // Retrieve a property from the TTS engine + // @param property pointer to the property name + // @param[out] value pointer to the retrieved language value + // @param[inout] iosize in: stores the size available to store the + // property value. + // out: stores the size required to hold the language + // value if getLanguage() returned + // TTS_PROPERTY_SIZE_TOO_SMALL, unchanged otherwise + // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS, + // or TTS_PROPERTY_SIZE_TOO_SMALL + android_tts_result_t (*getProperty) + (void *engine, + const char *property, + char *value, + size_t *iosize); + + // Synthesize the text. + // As the synthesis is performed, the engine invokes the callback to notify + // the TTS framework that it has filled the given buffer, and indicates how + // many bytes it wrote. The callback is called repeatedly until the engine + // has generated all the audio data corresponding to the text. + // Note about the format of the input: the text parameter may use the + // following elements + // and their respective attributes as defined in the SSML 1.0 specification: + // * lang + // * say-as: + // o interpret-as + // * phoneme + // * voice: + // o gender, + // o age, + // o variant, + // o name + // * emphasis + // * break: + // o strength, + // o time + // * prosody: + // o pitch, + // o contour, + // o range, + // o rate, + // o duration, + // o volume + // * mark + // Differences between this text format and SSML are: + // * full SSML documents are not supported + // * namespaces are not supported + // Text is coded in UTF-8. + // @param text the UTF-8 text to synthesize + // @param userdata pointer to be returned when the call is invoked + // @param buffer the location where the synthesized data must be written + // @param bufferSize the number of bytes that can be written in buffer + // @return TTS_SUCCESS or TTS_FAILURE + android_tts_result_t (*synthesizeText) + (void *engine, + const char *text, + int8_t *buffer, + size_t bufferSize, + void *userdata); +}; + +#ifdef __cplusplus +} +#endif + +#endif /* ANDROID_TTS_H */ diff --git a/packages/TtsService/jni/Android.mk b/packages/TtsService/jni/Android.mk index b41759a..5dc0c30 100755 --- a/packages/TtsService/jni/Android.mk +++ b/packages/TtsService/jni/Android.mk @@ -5,6 +5,7 @@ LOCAL_SRC_FILES:= \ android_tts_SynthProxy.cpp LOCAL_C_INCLUDES += \ + frameworks/base/native/include \ $(JNI_H_INCLUDE) LOCAL_SHARED_LIBRARIES := \ diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp index 1d69361..8dc88db 100644 --- a/packages/TtsService/jni/android_tts_SynthProxy.cpp +++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. + * Copyright (C) 2009-2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ #include <nativehelper/jni.h> #include <nativehelper/JNIHelp.h> #include <android_runtime/AndroidRuntime.h> -#include <tts/TtsEngine.h> +#include <android/tts.h> #include <media/AudioTrack.h> #include <math.h> @@ -154,7 +154,7 @@ static Mutex engineMutex; class SynthProxyJniStorage { public : jobject tts_ref; - TtsEngine* mNativeSynthInterface; + android_tts_engine_t* mEngine; void* mEngineLibHandle; AudioTrack* mAudioOut; int8_t mPlayState; @@ -168,7 +168,7 @@ class SynthProxyJniStorage { SynthProxyJniStorage() { tts_ref = NULL; - mNativeSynthInterface = NULL; + mEngine = NULL; mEngineLibHandle = NULL; mAudioOut = NULL; mPlayState = SYNTHPLAYSTATE_IS_STOPPED; @@ -184,9 +184,9 @@ class SynthProxyJniStorage { ~SynthProxyJniStorage() { //LOGV("entering ~SynthProxyJniStorage()"); killAudio(); - if (mNativeSynthInterface) { - mNativeSynthInterface->shutdown(); - mNativeSynthInterface = NULL; + if (mEngine) { + mEngine->funcs->shutdown(mEngine); + mEngine = NULL; } if (mEngineLibHandle) { //LOGE("~SynthProxyJniStorage(): before close library"); @@ -273,28 +273,45 @@ void prepAudioTrack(SynthProxyJniStorage* pJniData, AudioSystem::stream_type str * Callback from TTS engine. * Directly speaks using AudioTrack or write to file */ -static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate, - uint32_t format, int channel, - int8_t *&wav, size_t &bufferSize, tts_synth_status status) { +extern "C" android_tts_callback_status_t +__ttsSynthDoneCB(void ** pUserdata, uint32_t rate, + android_tts_audio_format_t format, int channel, + int8_t **pWav, size_t *pBufferSize, + android_tts_synth_status_t status) +{ //LOGV("ttsSynthDoneCallback: %d bytes", bufferSize); + AudioSystem::audio_format encoding; - if (userdata == NULL){ + if (*pUserdata == NULL){ LOGE("userdata == NULL"); - return TTS_CALLBACK_HALT; + return ANDROID_TTS_CALLBACK_HALT; + } + switch (format) { + case ANDROID_TTS_AUDIO_FORMAT_PCM_8_BIT: + encoding = AudioSystem::PCM_8_BIT; + break; + case ANDROID_TTS_AUDIO_FORMAT_PCM_16_BIT: + encoding = AudioSystem::PCM_16_BIT; + break; + default: + LOGE("Can't play, bad format"); + return ANDROID_TTS_CALLBACK_HALT; } - afterSynthData_t* pForAfter = (afterSynthData_t*)userdata; + afterSynthData_t* pForAfter = (afterSynthData_t*) *pUserdata; SynthProxyJniStorage* pJniData = (SynthProxyJniStorage*)(pForAfter->jniStorage); if (pForAfter->usageMode == USAGEMODE_PLAY_IMMEDIATELY){ //LOGV("Direct speech"); - if (wav == NULL) { + if (*pWav == NULL) { delete pForAfter; + pForAfter = NULL; LOGV("Null: speech has completed"); + return ANDROID_TTS_CALLBACK_HALT; } - if (bufferSize > 0) { - prepAudioTrack(pJniData, pForAfter->streamType, rate, (AudioSystem::audio_format)format, channel); + if (*pBufferSize > 0) { + prepAudioTrack(pJniData, pForAfter->streamType, rate, encoding, channel); if (pJniData->mAudioOut) { pJniData->mPlayLock.lock(); if(pJniData->mAudioOut->stopped() @@ -303,28 +320,31 @@ static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate, } pJniData->mPlayLock.unlock(); if (bUseFilter) { - applyFilter((int16_t*)wav, bufferSize/2); + applyFilter((int16_t*)*pWav, *pBufferSize/2); } - pJniData->mAudioOut->write(wav, bufferSize); - memset(wav, 0, bufferSize); + pJniData->mAudioOut->write(*pWav, *pBufferSize); + memset(*pWav, 0, *pBufferSize); //LOGV("AudioTrack wrote: %d bytes", bufferSize); } else { LOGE("Can't play, null audiotrack"); + delete pForAfter; + pForAfter = NULL; + return ANDROID_TTS_CALLBACK_HALT; } } } else if (pForAfter->usageMode == USAGEMODE_WRITE_TO_FILE) { //LOGV("Save to file"); - if (wav == NULL) { + if (*pWav == NULL) { delete pForAfter; LOGV("Null: speech has completed"); - return TTS_CALLBACK_HALT; + return ANDROID_TTS_CALLBACK_HALT; } - if (bufferSize > 0){ + if (*pBufferSize > 0){ if (bUseFilter) { - applyFilter((int16_t*)wav, bufferSize/2); + applyFilter((int16_t*)*pWav, *pBufferSize/2); } - fwrite(wav, 1, bufferSize, pForAfter->outputFile); - memset(wav, 0, bufferSize); + fwrite(*pWav, 1, *pBufferSize, pForAfter->outputFile); + memset(*pWav, 0, *pBufferSize); } } // Future update: @@ -332,7 +352,7 @@ static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate, // javaTTSFields.synthProxyMethodPost methode to notify // playback has completed if the synthesis is done or if a marker has been reached. - if (status == TTS_SYNTH_DONE) { + if (status == ANDROID_TTS_SYNTH_DONE) { // this struct was allocated in the original android_tts_SynthProxy_speak call, // all processing matching this call is now done. LOGV("Speech synthesis done."); @@ -342,16 +362,16 @@ static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate, delete pForAfter; pForAfter = NULL; } - return TTS_CALLBACK_HALT; + return ANDROID_TTS_CALLBACK_HALT; } // we don't update the wav (output) parameter as we'll let the next callback // write at the same location, we've consumed the data already, but we need // to update bufferSize to let the TTS engine know how much it can write the // next time it calls this function. - bufferSize = pJniData->mBufferSize; + *pBufferSize = pJniData->mBufferSize; - return TTS_CALLBACK_CONTINUE; + return ANDROID_TTS_CALLBACK_CONTINUE; } @@ -360,7 +380,7 @@ static int android_tts_SynthProxy_setLowShelf(JNIEnv *env, jobject thiz, jboolean applyFilter, jfloat filterGain, jfloat attenuationInDb, jfloat freqInHz, jfloat slope) { - int result = TTS_SUCCESS; + int result = ANDROID_TTS_SUCCESS; bUseFilter = applyFilter; if (applyFilter) { @@ -373,7 +393,7 @@ android_tts_SynthProxy_setLowShelf(JNIEnv *env, jobject thiz, jboolean applyFilt initializeEQ(); } else { LOGE("Invalid slope, can't be null"); - result = TTS_FAILURE; + result = ANDROID_TTS_FAILURE; } } @@ -385,7 +405,7 @@ static int android_tts_SynthProxy_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, jstring nativeSoLib, jstring engConfig) { - int result = TTS_FAILURE; + int result = ANDROID_TTS_FAILURE; bUseFilter = false; @@ -402,18 +422,28 @@ android_tts_SynthProxy_native_setup(JNIEnv *env, jobject thiz, if (engine_lib_handle == NULL) { LOGE("android_tts_SynthProxy_native_setup(): engine_lib_handle == NULL"); } else { - TtsEngine *(*get_TtsEngine)() = - reinterpret_cast<TtsEngine* (*)()>(dlsym(engine_lib_handle, "getTtsEngine")); + android_tts_engine_t * (*get_TtsEngine)() = + reinterpret_cast<android_tts_engine_t* (*)()>(dlsym(engine_lib_handle, "android_getTtsEngine")); + + // Support obsolete/legacy binary modules + if (get_TtsEngine == NULL) { + get_TtsEngine = + reinterpret_cast<android_tts_engine_t* (*)()>(dlsym(engine_lib_handle, "getTtsEngine")); + } - pJniStorage->mNativeSynthInterface = (*get_TtsEngine)(); + pJniStorage->mEngine = (*get_TtsEngine)(); pJniStorage->mEngineLibHandle = engine_lib_handle; - if (pJniStorage->mNativeSynthInterface) { + android_tts_engine_t *engine = pJniStorage->mEngine; + if (engine) { Mutex::Autolock l(engineMutex); - pJniStorage->mNativeSynthInterface->init(ttsSynthDoneCB, engConfigString); + engine->funcs->init( + engine, + __ttsSynthDoneCB, + engConfigString); } - result = TTS_SUCCESS; + result = ANDROID_TTS_SUCCESS; } // we use a weak reference so the SynthProxy object can be garbage collected. @@ -462,7 +492,7 @@ static int android_tts_SynthProxy_isLanguageAvailable(JNIEnv *env, jobject thiz, jint jniData, jstring language, jstring country, jstring variant) { - int result = TTS_LANG_NOT_SUPPORTED; + int result = ANDROID_TTS_LANG_NOT_SUPPORTED; if (jniData == 0) { LOGE("android_tts_SynthProxy_isLanguageAvailable(): invalid JNI data"); @@ -474,8 +504,10 @@ android_tts_SynthProxy_isLanguageAvailable(JNIEnv *env, jobject thiz, jint jniDa const char *countryNativeString = env->GetStringUTFChars(country, 0); const char *variantNativeString = env->GetStringUTFChars(variant, 0); - if (pSynthData->mNativeSynthInterface) { - result = pSynthData->mNativeSynthInterface->isLanguageAvailable(langNativeString, + android_tts_engine_t *engine = pSynthData->mEngine; + + if (engine) { + result = engine->funcs->isLanguageAvailable(engine,langNativeString, countryNativeString, variantNativeString); } env->ReleaseStringUTFChars(language, langNativeString); @@ -487,7 +519,7 @@ android_tts_SynthProxy_isLanguageAvailable(JNIEnv *env, jobject thiz, jint jniDa static int android_tts_SynthProxy_setConfig(JNIEnv *env, jobject thiz, jint jniData, jstring engineConfig) { - int result = TTS_FAILURE; + int result = ANDROID_TTS_FAILURE; if (jniData == 0) { LOGE("android_tts_SynthProxy_setConfig(): invalid JNI data"); @@ -498,9 +530,10 @@ android_tts_SynthProxy_setConfig(JNIEnv *env, jobject thiz, jint jniData, jstrin SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData; const char *engineConfigNativeString = env->GetStringUTFChars(engineConfig, 0); + android_tts_engine_t *engine = pSynthData->mEngine; - if (pSynthData->mNativeSynthInterface) { - result = pSynthData->mNativeSynthInterface->setProperty(ANDROID_TTS_ENGINE_PROPERTY_CONFIG, + if (engine) { + result = engine->funcs->setProperty(engine,ANDROID_TTS_ENGINE_PROPERTY_CONFIG, engineConfigNativeString, strlen(engineConfigNativeString)); } env->ReleaseStringUTFChars(engineConfig, engineConfigNativeString); @@ -512,7 +545,7 @@ static int android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData, jstring language, jstring country, jstring variant) { - int result = TTS_LANG_NOT_SUPPORTED; + int result = ANDROID_TTS_LANG_NOT_SUPPORTED; if (jniData == 0) { LOGE("android_tts_SynthProxy_setLanguage(): invalid JNI data"); @@ -525,9 +558,10 @@ android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData, const char *langNativeString = env->GetStringUTFChars(language, 0); const char *countryNativeString = env->GetStringUTFChars(country, 0); const char *variantNativeString = env->GetStringUTFChars(variant, 0); + android_tts_engine_t *engine = pSynthData->mEngine; - if (pSynthData->mNativeSynthInterface) { - result = pSynthData->mNativeSynthInterface->setLanguage(langNativeString, + if (engine) { + result = engine->funcs->setLanguage(engine, langNativeString, countryNativeString, variantNativeString); } env->ReleaseStringUTFChars(language, langNativeString); @@ -541,7 +575,7 @@ static int android_tts_SynthProxy_loadLanguage(JNIEnv *env, jobject thiz, jint jniData, jstring language, jstring country, jstring variant) { - int result = TTS_LANG_NOT_SUPPORTED; + int result = ANDROID_TTS_LANG_NOT_SUPPORTED; if (jniData == 0) { LOGE("android_tts_SynthProxy_loadLanguage(): invalid JNI data"); @@ -552,9 +586,10 @@ android_tts_SynthProxy_loadLanguage(JNIEnv *env, jobject thiz, jint jniData, const char *langNativeString = env->GetStringUTFChars(language, 0); const char *countryNativeString = env->GetStringUTFChars(country, 0); const char *variantNativeString = env->GetStringUTFChars(variant, 0); + android_tts_engine_t *engine = pSynthData->mEngine; - if (pSynthData->mNativeSynthInterface) { - result = pSynthData->mNativeSynthInterface->loadLanguage(langNativeString, + if (engine) { + result = engine->funcs->loadLanguage(engine, langNativeString, countryNativeString, variantNativeString); } env->ReleaseStringUTFChars(language, langNativeString); @@ -569,7 +604,7 @@ static int android_tts_SynthProxy_setSpeechRate(JNIEnv *env, jobject thiz, jint jniData, jint speechRate) { - int result = TTS_FAILURE; + int result = ANDROID_TTS_FAILURE; if (jniData == 0) { LOGE("android_tts_SynthProxy_setSpeechRate(): invalid JNI data"); @@ -584,9 +619,10 @@ android_tts_SynthProxy_setSpeechRate(JNIEnv *env, jobject thiz, jint jniData, SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData; LOGI("setting speech rate to %d", speechRate); + android_tts_engine_t *engine = pSynthData->mEngine; - if (pSynthData->mNativeSynthInterface) { - result = pSynthData->mNativeSynthInterface->setProperty("rate", buffer, bufSize); + if (engine) { + result = engine->funcs->setProperty(engine, "rate", buffer, bufSize); } return result; @@ -597,7 +633,7 @@ static int android_tts_SynthProxy_setPitch(JNIEnv *env, jobject thiz, jint jniData, jint pitch) { - int result = TTS_FAILURE; + int result = ANDROID_TTS_FAILURE; if (jniData == 0) { LOGE("android_tts_SynthProxy_setPitch(): invalid JNI data"); @@ -612,9 +648,10 @@ android_tts_SynthProxy_setPitch(JNIEnv *env, jobject thiz, jint jniData, SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData; LOGI("setting pitch to %d", pitch); + android_tts_engine_t *engine = pSynthData->mEngine; - if (pSynthData->mNativeSynthInterface) { - result = pSynthData->mNativeSynthInterface->setProperty("pitch", buffer, bufSize); + if (engine) { + result = engine->funcs->setProperty(engine, "pitch", buffer, bufSize); } return result; @@ -625,7 +662,7 @@ static int android_tts_SynthProxy_synthesizeToFile(JNIEnv *env, jobject thiz, jint jniData, jstring textJavaString, jstring filenameJavaString) { - int result = TTS_FAILURE; + int result = ANDROID_TTS_FAILURE; if (jniData == 0) { LOGE("android_tts_SynthProxy_synthesizeToFile(): invalid JNI data"); @@ -633,7 +670,7 @@ android_tts_SynthProxy_synthesizeToFile(JNIEnv *env, jobject thiz, jint jniData, } SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData; - if (!pSynthData->mNativeSynthInterface) { + if (!pSynthData->mEngine) { LOGE("android_tts_SynthProxy_synthesizeToFile(): invalid engine handle"); return result; } @@ -643,12 +680,22 @@ android_tts_SynthProxy_synthesizeToFile(JNIEnv *env, jobject thiz, jint jniData, Mutex::Autolock l(engineMutex); // Retrieve audio parameters before writing the file header - AudioSystem::audio_format encoding = DEFAULT_TTS_FORMAT; + AudioSystem::audio_format encoding; uint32_t rate = DEFAULT_TTS_RATE; int channels = DEFAULT_TTS_NB_CHANNELS; - pSynthData->mNativeSynthInterface->setAudioFormat(encoding, rate, channels); - - if ((encoding != AudioSystem::PCM_16_BIT) && (encoding != AudioSystem::PCM_8_BIT)) { + android_tts_engine_t *engine = pSynthData->mEngine; + android_tts_audio_format_t format = ANDROID_TTS_AUDIO_FORMAT_DEFAULT; + + engine->funcs->setAudioFormat(engine, &format, &rate, &channels); + + switch (format) { + case ANDROID_TTS_AUDIO_FORMAT_PCM_16_BIT: + encoding = AudioSystem::PCM_16_BIT; + break; + case ANDROID_TTS_AUDIO_FORMAT_PCM_8_BIT: + encoding = AudioSystem::PCM_8_BIT; + break; + default: LOGE("android_tts_SynthProxy_synthesizeToFile(): engine uses invalid format"); return result; } @@ -677,7 +724,8 @@ android_tts_SynthProxy_synthesizeToFile(JNIEnv *env, jobject thiz, jint jniData, unsigned int unique_identifier; memset(pSynthData->mBuffer, 0, pSynthData->mBufferSize); - result = pSynthData->mNativeSynthInterface->synthesizeText(textNativeString, + + result = engine->funcs->synthesizeText(engine, textNativeString, pSynthData->mBuffer, pSynthData->mBufferSize, (void *)pForAfter); long filelen = ftell(pForAfter->outputFile); @@ -737,7 +785,7 @@ static int android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData, jstring textJavaString, jint javaStreamType) { - int result = TTS_FAILURE; + int result = ANDROID_TTS_FAILURE; if (jniData == 0) { LOGE("android_tts_SynthProxy_speak(): invalid JNI data"); @@ -759,10 +807,12 @@ android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData, pForAfter->usageMode = USAGEMODE_PLAY_IMMEDIATELY; pForAfter->streamType = (AudioSystem::stream_type) javaStreamType; - if (pSynthData->mNativeSynthInterface) { + if (pSynthData->mEngine) { const char *textNativeString = env->GetStringUTFChars(textJavaString, 0); memset(pSynthData->mBuffer, 0, pSynthData->mBufferSize); - result = pSynthData->mNativeSynthInterface->synthesizeText(textNativeString, + android_tts_engine_t *engine = pSynthData->mEngine; + + result = engine->funcs->synthesizeText(engine, textNativeString, pSynthData->mBuffer, pSynthData->mBufferSize, (void *)pForAfter); env->ReleaseStringUTFChars(textJavaString, textNativeString); } @@ -774,7 +824,7 @@ android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData, static int android_tts_SynthProxy_stop(JNIEnv *env, jobject thiz, jint jniData) { - int result = TTS_FAILURE; + int result = ANDROID_TTS_FAILURE; if (jniData == 0) { LOGE("android_tts_SynthProxy_stop(): invalid JNI data"); @@ -790,8 +840,9 @@ android_tts_SynthProxy_stop(JNIEnv *env, jobject thiz, jint jniData) } pSynthData->mPlayLock.unlock(); - if (pSynthData->mNativeSynthInterface) { - result = pSynthData->mNativeSynthInterface->stop(); + android_tts_engine_t *engine = pSynthData->mEngine; + if (engine) { + result = engine->funcs->stop(engine); } return result; @@ -801,7 +852,7 @@ android_tts_SynthProxy_stop(JNIEnv *env, jobject thiz, jint jniData) static int android_tts_SynthProxy_stopSync(JNIEnv *env, jobject thiz, jint jniData) { - int result = TTS_FAILURE; + int result = ANDROID_TTS_FAILURE; if (jniData == 0) { LOGE("android_tts_SynthProxy_stop(): invalid JNI data"); @@ -829,7 +880,7 @@ android_tts_SynthProxy_getLanguage(JNIEnv *env, jobject thiz, jint jniData) SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData; - if (pSynthData->mNativeSynthInterface) { + if (pSynthData->mEngine) { size_t bufSize = 100; char lang[bufSize]; char country[bufSize]; @@ -839,7 +890,9 @@ android_tts_SynthProxy_getLanguage(JNIEnv *env, jobject thiz, jint jniData) memset(variant, 0, bufSize); jobjectArray retLocale = (jobjectArray)env->NewObjectArray(3, env->FindClass("java/lang/String"), env->NewStringUTF("")); - pSynthData->mNativeSynthInterface->getLanguage(lang, country, variant); + + android_tts_engine_t *engine = pSynthData->mEngine; + engine->funcs->getLanguage(engine, lang, country, variant); env->SetObjectArrayElement(retLocale, 0, env->NewStringUTF(lang)); env->SetObjectArrayElement(retLocale, 1, env->NewStringUTF(country)); env->SetObjectArrayElement(retLocale, 2, env->NewStringUTF(variant)); @@ -864,8 +917,9 @@ android_tts_SynthProxy_getRate(JNIEnv *env, jobject thiz, jint jniData) char buf[bufSize]; memset(buf, 0, bufSize); // TODO check return codes - if (pSynthData->mNativeSynthInterface) { - pSynthData->mNativeSynthInterface->getProperty("rate", buf, &bufSize); + android_tts_engine_t *engine = pSynthData->mEngine; + if (engine) { + engine->funcs->getProperty(engine,"rate", buf, &bufSize); } return atoi(buf); } |