summaryrefslogtreecommitdiffstats
path: root/pico/compat/jni/com_android_tts_compat_SynthProxy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'pico/compat/jni/com_android_tts_compat_SynthProxy.cpp')
-rw-r--r--pico/compat/jni/com_android_tts_compat_SynthProxy.cpp706
1 files changed, 706 insertions, 0 deletions
diff --git a/pico/compat/jni/com_android_tts_compat_SynthProxy.cpp b/pico/compat/jni/com_android_tts_compat_SynthProxy.cpp
new file mode 100644
index 0000000..c9c38c4
--- /dev/null
+++ b/pico/compat/jni/com_android_tts_compat_SynthProxy.cpp
@@ -0,0 +1,706 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#define LOG_TAG "SynthProxyJNI"
+
+#include <utils/Log.h>
+#include <nativehelper/jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <media/AudioTrack.h>
+#include <math.h>
+
+#include <dlfcn.h>
+
+#include "tts.h"
+
+#define DEFAULT_TTS_RATE 16000
+#define DEFAULT_TTS_BUFFERSIZE 2048
+
+// EQ + BOOST parameters
+#define FILTER_LOWSHELF_ATTENUATION -18.0f // in dB
+#define FILTER_TRANSITION_FREQ 1100.0f // in Hz
+#define FILTER_SHELF_SLOPE 1.0f // Q
+#define FILTER_GAIN 5.5f // linear gain
+
+// android.media.AudioFormat.ENCODING_ values
+#define AUDIO_FORMAT_ENCODING_DEFAULT 1
+#define AUDIO_FORMAT_ENCODING_PCM_16_BIT 2
+#define AUDIO_FORMAT_ENCODING_PCM_8_BIT 3
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+// EQ data
+static double m_fa, m_fb, m_fc, m_fd, m_fe;
+static double x0; // x[n]
+static double x1; // x[n-1]
+static double x2; // x[n-2]
+static double out0;// y[n]
+static double out1;// y[n-1]
+static double out2;// y[n-2]
+
+static float fFilterLowshelfAttenuation = FILTER_LOWSHELF_ATTENUATION;
+static float fFilterTransitionFreq = FILTER_TRANSITION_FREQ;
+static float fFilterShelfSlope = FILTER_SHELF_SLOPE;
+static float fFilterGain = FILTER_GAIN;
+static bool bUseFilter = false;
+
+void initializeEQ() {
+ double amp = float(pow(10.0, fFilterLowshelfAttenuation / 40.0));
+ double w = 2.0 * M_PI * (fFilterTransitionFreq / DEFAULT_TTS_RATE);
+ double sinw = float(sin(w));
+ double cosw = float(cos(w));
+ double beta = float(sqrt(amp)/fFilterShelfSlope);
+
+ // initialize low-shelf parameters
+ double b0 = amp * ((amp+1.0F) - ((amp-1.0F)*cosw) + (beta*sinw));
+ double b1 = 2.0F * amp * ((amp-1.0F) - ((amp+1.0F)*cosw));
+ double b2 = amp * ((amp+1.0F) - ((amp-1.0F)*cosw) - (beta*sinw));
+ double a0 = (amp+1.0F) + ((amp-1.0F)*cosw) + (beta*sinw);
+ double a1 = 2.0F * ((amp-1.0F) + ((amp+1.0F)*cosw));
+ double a2 = -((amp+1.0F) + ((amp-1.0F)*cosw) - (beta*sinw));
+
+ m_fa = fFilterGain * b0/a0;
+ m_fb = fFilterGain * b1/a0;
+ m_fc = fFilterGain * b2/a0;
+ m_fd = a1/a0;
+ m_fe = a2/a0;
+}
+
+void initializeFilter() {
+ x0 = 0.0f;
+ x1 = 0.0f;
+ x2 = 0.0f;
+ out0 = 0.0f;
+ out1 = 0.0f;
+ out2 = 0.0f;
+}
+
+void applyFilter(int16_t* buffer, size_t sampleCount) {
+
+ for (size_t i=0 ; i<sampleCount ; i++) {
+
+ x0 = (double) buffer[i];
+
+ out0 = (m_fa*x0) + (m_fb*x1) + (m_fc*x2) + (m_fd*out1) + (m_fe*out2);
+
+ x2 = x1;
+ x1 = x0;
+
+ out2 = out1;
+ out1 = out0;
+
+ if (out0 > 32767.0f) {
+ buffer[i] = 32767;
+ } else if (out0 < -32768.0f) {
+ buffer[i] = -32768;
+ } else {
+ buffer[i] = (int16_t) out0;
+ }
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+
+static jmethodID synthesisRequest_start;
+static jmethodID synthesisRequest_audioAvailable;
+static jmethodID synthesisRequest_done;
+
+static Mutex engineMutex;
+
+
+
+typedef android_tts_engine_t *(*android_tts_entrypoint)();
+
+// ----------------------------------------------------------------------------
+class SynthProxyJniStorage {
+ public:
+ android_tts_engine_t *mEngine;
+ void *mEngineLibHandle;
+ int8_t *mBuffer;
+ size_t mBufferSize;
+
+ SynthProxyJniStorage() {
+ mEngine = NULL;
+ mEngineLibHandle = NULL;
+ mBufferSize = DEFAULT_TTS_BUFFERSIZE;
+ mBuffer = new int8_t[mBufferSize];
+ memset(mBuffer, 0, mBufferSize);
+ }
+
+ ~SynthProxyJniStorage() {
+ if (mEngine) {
+ mEngine->funcs->shutdown(mEngine);
+ mEngine = NULL;
+ }
+ if (mEngineLibHandle) {
+ int res = dlclose(mEngineLibHandle);
+ LOGE_IF( res != 0, "~SynthProxyJniStorage(): dlclose returned %d", res);
+ }
+ delete[] mBuffer;
+ }
+
+};
+
+// ----------------------------------------------------------------------------
+
+struct SynthRequestData {
+ SynthProxyJniStorage *jniStorage;
+ JNIEnv *env;
+ jobject request;
+ bool startCalled;
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * Calls into Java
+ */
+
+static bool checkException(JNIEnv *env)
+{
+ jthrowable ex = env->ExceptionOccurred();
+ if (ex == NULL) {
+ return false;
+ }
+ env->ExceptionClear();
+ LOGE_EX(env, ex);
+ env->DeleteLocalRef(ex);
+ return true;
+}
+
+static int callRequestStart(JNIEnv *env, jobject request,
+ uint32_t rate, android_tts_audio_format_t format, int channelCount)
+{
+ int encoding;
+
+ switch (format) {
+ case ANDROID_TTS_AUDIO_FORMAT_DEFAULT:
+ encoding = AUDIO_FORMAT_ENCODING_DEFAULT;
+ break;
+ case ANDROID_TTS_AUDIO_FORMAT_PCM_8_BIT:
+ encoding = AUDIO_FORMAT_ENCODING_PCM_8_BIT;
+ break;
+ case ANDROID_TTS_AUDIO_FORMAT_PCM_16_BIT:
+ encoding = AUDIO_FORMAT_ENCODING_PCM_16_BIT;
+ break;
+ default:
+ LOGE("Can't play, bad format");
+ return ANDROID_TTS_FAILURE;
+ }
+
+ int result = env->CallIntMethod(request, synthesisRequest_start, rate, encoding, channelCount);
+ if (checkException(env)) {
+ return ANDROID_TTS_FAILURE;
+ }
+ return result;
+}
+
+static int callRequestAudioAvailable(JNIEnv *env, jobject request, int8_t *buffer,
+ int offset, int length)
+{
+ // TODO: Not nice to have to copy the buffer. Use ByteBuffer?
+ jbyteArray javaBuffer = env->NewByteArray(length);
+ if (javaBuffer == NULL) {
+ LOGE("Failed to allocate byte array");
+ return ANDROID_TTS_FAILURE;
+ }
+
+ env->SetByteArrayRegion(javaBuffer, 0, length, static_cast<jbyte *>(buffer + offset));
+ if (checkException(env)) {
+ env->DeleteLocalRef(javaBuffer);
+ return ANDROID_TTS_FAILURE;
+ }
+ int result = env->CallIntMethod(request, synthesisRequest_audioAvailable,
+ javaBuffer, offset, length);
+ if (checkException(env)) {
+ env->DeleteLocalRef(javaBuffer);
+ return ANDROID_TTS_FAILURE;
+ }
+ env->DeleteLocalRef(javaBuffer);
+ return result;
+}
+
+static int callRequestDone(JNIEnv *env, jobject request)
+{
+ int result = env->CallIntMethod(request, synthesisRequest_done);
+ if (checkException(env)) {
+ return ANDROID_TTS_FAILURE;
+ }
+ return result;
+}
+
+/*
+ * Callback from TTS engine.
+ */
+extern "C" android_tts_callback_status_t
+__ttsSynthDoneCB(void **pUserdata, uint32_t rate,
+ android_tts_audio_format_t format, int channelCount,
+ int8_t **pWav, size_t *pBufferSize,
+ android_tts_synth_status_t status)
+{
+ if (*pUserdata == NULL){
+ LOGE("userdata == NULL");
+ return ANDROID_TTS_CALLBACK_HALT;
+ }
+
+ SynthRequestData *pRequestData = static_cast<SynthRequestData*>(*pUserdata);
+ SynthProxyJniStorage *pJniData = pRequestData->jniStorage;
+ JNIEnv *env = pRequestData->env;
+
+ if (*pWav != NULL && *pBufferSize > 0) {
+ if (bUseFilter) {
+ applyFilter(reinterpret_cast<int16_t*>(*pWav), *pBufferSize/2);
+ }
+
+ if (!pRequestData->startCalled) {
+ // TODO: is encoding one of the AudioFormat.ENCODING_* constants?
+ pRequestData->startCalled = true;
+ if (callRequestStart(env, pRequestData->request, rate, format, channelCount)
+ != ANDROID_TTS_SUCCESS) {
+ return ANDROID_TTS_CALLBACK_HALT;
+ }
+ }
+
+ if (callRequestAudioAvailable(env, pRequestData->request, *pWav, 0, *pBufferSize)
+ != ANDROID_TTS_SUCCESS) {
+ return ANDROID_TTS_CALLBACK_HALT;
+ }
+
+ memset(*pWav, 0, *pBufferSize);
+ }
+
+ if (pWav == NULL || status == ANDROID_TTS_SYNTH_DONE) {
+ callRequestDone(env, pRequestData->request);
+ env->DeleteGlobalRef(pRequestData->request);
+ delete pRequestData;
+ pRequestData = NULL;
+ return ANDROID_TTS_CALLBACK_HALT;
+ }
+
+ *pBufferSize = pJniData->mBufferSize;
+
+ return ANDROID_TTS_CALLBACK_CONTINUE;
+}
+
+
+// ----------------------------------------------------------------------------
+static int
+com_android_tts_compat_SynthProxy_setLowShelf(JNIEnv *env, jobject thiz, jboolean applyFilter,
+ jfloat filterGain, jfloat attenuationInDb, jfloat freqInHz, jfloat slope)
+{
+ bUseFilter = applyFilter;
+ if (applyFilter) {
+ fFilterLowshelfAttenuation = attenuationInDb;
+ fFilterTransitionFreq = freqInHz;
+ fFilterShelfSlope = slope;
+ fFilterGain = filterGain;
+
+ if (fFilterShelfSlope != 0.0f) {
+ initializeEQ();
+ } else {
+ LOGE("Invalid slope, can't be null");
+ return ANDROID_TTS_FAILURE;
+ }
+ }
+
+ return ANDROID_TTS_SUCCESS;
+}
+
+// ----------------------------------------------------------------------------
+static jint
+com_android_tts_compat_SynthProxy_native_setup(JNIEnv *env, jobject thiz,
+ jstring nativeSoLib, jstring engConfig)
+{
+ int result = 0;
+ bUseFilter = false;
+
+ const char *nativeSoLibNativeString = env->GetStringUTFChars(nativeSoLib, 0);
+ const char *engConfigString = env->GetStringUTFChars(engConfig, 0);
+
+ void *engine_lib_handle = dlopen(nativeSoLibNativeString,
+ RTLD_NOW | RTLD_LOCAL);
+ if (engine_lib_handle == NULL) {
+ LOGE("com_android_tts_compat_SynthProxy_native_setup(): engine_lib_handle == NULL");
+ } else {
+ android_tts_entrypoint get_TtsEngine =
+ reinterpret_cast<android_tts_entrypoint>(dlsym(engine_lib_handle, "android_getTtsEngine"));
+
+ // Support obsolete/legacy binary modules
+ if (get_TtsEngine == NULL) {
+ get_TtsEngine =
+ reinterpret_cast<android_tts_entrypoint>(dlsym(engine_lib_handle, "getTtsEngine"));
+ }
+
+ android_tts_engine_t *engine = (*get_TtsEngine)();
+ if (engine) {
+ Mutex::Autolock l(engineMutex);
+ engine->funcs->init(engine, __ttsSynthDoneCB, engConfigString);
+
+ SynthProxyJniStorage *pSynthData = new SynthProxyJniStorage();
+ pSynthData->mEngine = engine;
+ pSynthData->mEngineLibHandle = engine_lib_handle;
+ result = reinterpret_cast<jint>(pSynthData);
+ }
+ }
+
+ env->ReleaseStringUTFChars(nativeSoLib, nativeSoLibNativeString);
+ env->ReleaseStringUTFChars(engConfig, engConfigString);
+
+ return result;
+}
+
+static SynthProxyJniStorage *getSynthData(jint jniData)
+{
+ if (jniData == 0) {
+ LOGE("Engine not initialized");
+ return NULL;
+ }
+ return reinterpret_cast<SynthProxyJniStorage *>(jniData);
+}
+
+static void
+com_android_tts_compat_SynthProxy_native_finalize(JNIEnv *env, jobject thiz, jint jniData)
+{
+ SynthProxyJniStorage* pSynthData = getSynthData(jniData);
+ if (pSynthData == NULL) {
+ return;
+ }
+
+ Mutex::Autolock l(engineMutex);
+
+ delete pSynthData;
+}
+
+static void
+com_android_tts_compat_SynthProxy_shutdown(JNIEnv *env, jobject thiz, jint jniData)
+{
+ com_android_tts_compat_SynthProxy_native_finalize(env, thiz, jniData);
+}
+
+static int
+com_android_tts_compat_SynthProxy_isLanguageAvailable(JNIEnv *env, jobject thiz, jint jniData,
+ jstring language, jstring country, jstring variant)
+{
+ SynthProxyJniStorage* pSynthData = getSynthData(jniData);
+ if (pSynthData == NULL) {
+ return ANDROID_TTS_LANG_NOT_SUPPORTED;
+ }
+
+ android_tts_engine_t *engine = pSynthData->mEngine;
+ if (!engine) {
+ return ANDROID_TTS_LANG_NOT_SUPPORTED;
+ }
+
+ const char *langNativeString = env->GetStringUTFChars(language, 0);
+ const char *countryNativeString = env->GetStringUTFChars(country, 0);
+ const char *variantNativeString = env->GetStringUTFChars(variant, 0);
+
+ int result = engine->funcs->isLanguageAvailable(engine, langNativeString,
+ countryNativeString, variantNativeString);
+
+ env->ReleaseStringUTFChars(language, langNativeString);
+ env->ReleaseStringUTFChars(country, countryNativeString);
+ env->ReleaseStringUTFChars(variant, variantNativeString);
+
+ return result;
+}
+
+static int
+com_android_tts_compat_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData,
+ jstring language, jstring country, jstring variant)
+{
+ SynthProxyJniStorage* pSynthData = getSynthData(jniData);
+ if (pSynthData == NULL) {
+ return ANDROID_TTS_LANG_NOT_SUPPORTED;
+ }
+
+ Mutex::Autolock l(engineMutex);
+
+ android_tts_engine_t *engine = pSynthData->mEngine;
+ if (!engine) {
+ return ANDROID_TTS_LANG_NOT_SUPPORTED;
+ }
+
+ const char *langNativeString = env->GetStringUTFChars(language, 0);
+ const char *countryNativeString = env->GetStringUTFChars(country, 0);
+ const char *variantNativeString = env->GetStringUTFChars(variant, 0);
+
+ int result = engine->funcs->setLanguage(engine, langNativeString,
+ countryNativeString, variantNativeString);
+
+ env->ReleaseStringUTFChars(language, langNativeString);
+ env->ReleaseStringUTFChars(country, countryNativeString);
+ env->ReleaseStringUTFChars(variant, variantNativeString);
+
+ return result;
+}
+
+
+static int
+com_android_tts_compat_SynthProxy_loadLanguage(JNIEnv *env, jobject thiz, jint jniData,
+ jstring language, jstring country, jstring variant)
+{
+ SynthProxyJniStorage* pSynthData = getSynthData(jniData);
+ if (pSynthData == NULL) {
+ return ANDROID_TTS_LANG_NOT_SUPPORTED;
+ }
+
+ android_tts_engine_t *engine = pSynthData->mEngine;
+ if (!engine) {
+ return ANDROID_TTS_LANG_NOT_SUPPORTED;
+ }
+
+ const char *langNativeString = env->GetStringUTFChars(language, 0);
+ const char *countryNativeString = env->GetStringUTFChars(country, 0);
+ const char *variantNativeString = env->GetStringUTFChars(variant, 0);
+
+ int result = engine->funcs->loadLanguage(engine, langNativeString,
+ countryNativeString, variantNativeString);
+
+ env->ReleaseStringUTFChars(language, langNativeString);
+ env->ReleaseStringUTFChars(country, countryNativeString);
+ env->ReleaseStringUTFChars(variant, variantNativeString);
+
+ return result;
+}
+
+static int
+com_android_tts_compat_SynthProxy_setProperty(JNIEnv *env, jobject thiz, jint jniData,
+ jstring name, jstring value)
+{
+ SynthProxyJniStorage* pSynthData = getSynthData(jniData);
+ if (pSynthData == NULL) {
+ return ANDROID_TTS_FAILURE;
+ }
+
+ Mutex::Autolock l(engineMutex);
+
+ android_tts_engine_t *engine = pSynthData->mEngine;
+ if (!engine) {
+ return ANDROID_TTS_FAILURE;
+ }
+
+ const char *nameChars = env->GetStringUTFChars(name, 0);
+ const char *valueChars = env->GetStringUTFChars(value, 0);
+ size_t valueLength = env->GetStringUTFLength(value);
+
+ int result = engine->funcs->setProperty(engine, nameChars, valueChars, valueLength);
+
+ env->ReleaseStringUTFChars(name, nameChars);
+ env->ReleaseStringUTFChars(name, valueChars);
+
+ return result;
+}
+
+static int
+com_android_tts_compat_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData,
+ jstring textJavaString, jobject request)
+{
+ SynthProxyJniStorage* pSynthData = getSynthData(jniData);
+ if (pSynthData == NULL) {
+ return ANDROID_TTS_FAILURE;
+ }
+
+ initializeFilter();
+
+ Mutex::Autolock l(engineMutex);
+
+ android_tts_engine_t *engine = pSynthData->mEngine;
+ if (!engine) {
+ return ANDROID_TTS_FAILURE;
+ }
+
+ SynthRequestData *pRequestData = new SynthRequestData;
+ pRequestData->jniStorage = pSynthData;
+ pRequestData->env = env;
+ pRequestData->request = env->NewGlobalRef(request);
+ pRequestData->startCalled = false;
+
+ const char *textNativeString = env->GetStringUTFChars(textJavaString, 0);
+ memset(pSynthData->mBuffer, 0, pSynthData->mBufferSize);
+
+ int result = engine->funcs->synthesizeText(engine, textNativeString,
+ pSynthData->mBuffer, pSynthData->mBufferSize, static_cast<void *>(pRequestData));
+ env->ReleaseStringUTFChars(textJavaString, textNativeString);
+
+ return result;
+}
+
+static int
+com_android_tts_compat_SynthProxy_stop(JNIEnv *env, jobject thiz, jint jniData)
+{
+ SynthProxyJniStorage* pSynthData = getSynthData(jniData);
+ if (pSynthData == NULL) {
+ return ANDROID_TTS_FAILURE;
+ }
+
+ android_tts_engine_t *engine = pSynthData->mEngine;
+ if (!engine) {
+ return ANDROID_TTS_FAILURE;
+ }
+
+ return engine->funcs->stop(engine);
+}
+
+static int
+com_android_tts_compat_SynthProxy_stopSync(JNIEnv *env, jobject thiz, jint jniData)
+{
+ SynthProxyJniStorage* pSynthData = getSynthData(jniData);
+ if (pSynthData == NULL) {
+ return ANDROID_TTS_FAILURE;
+ }
+
+ // perform a regular stop
+ int result = com_android_tts_compat_SynthProxy_stop(env, thiz, jniData);
+ // but wait on the engine having released the engine mutex which protects
+ // the synthesizer resources.
+ engineMutex.lock();
+ engineMutex.unlock();
+
+ return result;
+}
+
+static jobjectArray
+com_android_tts_compat_SynthProxy_getLanguage(JNIEnv *env, jobject thiz, jint jniData)
+{
+ SynthProxyJniStorage* pSynthData = getSynthData(jniData);
+ if (pSynthData == NULL) {
+ return NULL;
+ }
+
+ if (pSynthData->mEngine) {
+ size_t bufSize = 100;
+ char lang[bufSize];
+ char country[bufSize];
+ char variant[bufSize];
+ memset(lang, 0, bufSize);
+ memset(country, 0, bufSize);
+ memset(variant, 0, bufSize);
+ jobjectArray retLocale = (jobjectArray)env->NewObjectArray(3,
+ env->FindClass("java/lang/String"), env->NewStringUTF(""));
+
+ 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));
+ return retLocale;
+ } else {
+ return NULL;
+ }
+}
+
+
+// Dalvik VM type signatures
+static JNINativeMethod gMethods[] = {
+ { "native_stop",
+ "(I)I",
+ (void*)com_android_tts_compat_SynthProxy_stop
+ },
+ { "native_stopSync",
+ "(I)I",
+ (void*)com_android_tts_compat_SynthProxy_stopSync
+ },
+ { "native_speak",
+ "(ILjava/lang/String;Landroid/speech/tts/SynthesisRequest;)I",
+ (void*)com_android_tts_compat_SynthProxy_speak
+ },
+ { "native_isLanguageAvailable",
+ "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+ (void*)com_android_tts_compat_SynthProxy_isLanguageAvailable
+ },
+ { "native_setLanguage",
+ "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+ (void*)com_android_tts_compat_SynthProxy_setLanguage
+ },
+ { "native_loadLanguage",
+ "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+ (void*)com_android_tts_compat_SynthProxy_loadLanguage
+ },
+ { "native_setProperty",
+ "(ILjava/lang/String;Ljava/lang/String;)I",
+ (void*)com_android_tts_compat_SynthProxy_setProperty
+ },
+ { "native_getLanguage",
+ "(I)[Ljava/lang/String;",
+ (void*)com_android_tts_compat_SynthProxy_getLanguage
+ },
+ { "native_shutdown",
+ "(I)V",
+ (void*)com_android_tts_compat_SynthProxy_shutdown
+ },
+ { "native_setup",
+ "(Ljava/lang/String;Ljava/lang/String;)I",
+ (void*)com_android_tts_compat_SynthProxy_native_setup
+ },
+ { "native_setLowShelf",
+ "(ZFFFF)I",
+ (void*)com_android_tts_compat_SynthProxy_setLowShelf
+ },
+ { "native_finalize",
+ "(I)V",
+ (void*)com_android_tts_compat_SynthProxy_native_finalize
+ }
+};
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+ JNIEnv* env = NULL;
+
+ if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+ LOGE("ERROR: GetEnv failed\n");
+ return -1;
+ }
+ assert(env != NULL);
+
+ jclass classSynthesisRequest = env->FindClass(
+ "android/speech/tts/SynthesisRequest");
+ if (classSynthesisRequest == NULL) {
+ return -1;
+ }
+
+ synthesisRequest_start = env->GetMethodID(classSynthesisRequest,
+ "start", "(III)I");
+ if (synthesisRequest_start == NULL) {
+ return -1;
+ }
+
+ synthesisRequest_audioAvailable = env->GetMethodID(classSynthesisRequest,
+ "audioAvailable", "([BII)I");
+ if (synthesisRequest_audioAvailable == NULL) {
+ return -1;
+ }
+
+ synthesisRequest_done = env->GetMethodID(classSynthesisRequest,
+ "done", "()I");
+ if (synthesisRequest_done == NULL) {
+ return -1;
+ }
+
+ if (jniRegisterNativeMethods(
+ env, "com/android/tts/compat/SynthProxy", gMethods, NELEM(gMethods)) < 0) {
+ return -1;
+ }
+
+ /* success -- return valid version number */
+ return JNI_VERSION_1_4;
+}