| /* |
| * BRLTTY - A background process providing access to the console screen (when in |
| * text mode) for a blind person using a refreshable braille display. |
| * |
| * Copyright (C) 1995-2023 by The BRLTTY Developers. |
| * |
| * BRLTTY comes with ABSOLUTELY NO WARRANTY. |
| * |
| * This is free software, placed under the terms of the |
| * GNU Lesser General Public License, as published by the Free Software |
| * Foundation; either version 2.1 of the License, or (at your option) any |
| * later version. Please see the file LICENSE-LGPL for details. |
| * |
| * Web Page: http://brltty.app/ |
| * |
| * This software is maintained by Dave Mielke <dave@mielke.cc>. |
| */ |
| |
| #include "prologue.h" |
| |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include "log.h" |
| |
| #include "spk_driver.h" |
| #include "system_java.h" |
| |
| struct SpeechDataStruct { |
| JNIEnv *env; |
| jclass driverClass; |
| jmethodID startMethod; |
| jmethodID stopMethod; |
| jmethodID sayMethod; |
| jmethodID muteMethod; |
| jmethodID setVolumeMethod; |
| jmethodID setRateMethod; |
| jmethodID setPitchMethod; |
| }; |
| |
| static int |
| findDriverClass (SpeechSynthesizer *spk) { |
| return findJavaClass( |
| spk->driver.data->env, &spk->driver.data->driverClass, |
| JAVA_OBJ_BRLTTY("speech/SpeechDriver") |
| ); |
| } |
| |
| static void |
| releaseDriverClass (SpeechSynthesizer *spk) { |
| jclass class = spk->driver.data->driverClass; |
| |
| if (class) { |
| JNIEnv *env = spk->driver.data->env; |
| |
| (*env)->DeleteGlobalRef(env, class); |
| } |
| } |
| |
| static int |
| findDriverMethod (SpeechSynthesizer *spk, jmethodID *method, const char *name, const char *signature) { |
| if (findDriverClass(spk)) { |
| if (findJavaStaticMethod(spk->driver.data->env, method, spk->driver.data->driverClass, name, signature)) { |
| return 1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| JAVA_STATIC_METHOD ( |
| org_a11y_brltty_android_speech_SpeechDriver, tellLocation, void, |
| jlong synthesizer, jint location |
| ) { |
| tellSpeechLocation(javaPtrFromLong(synthesizer), location); |
| } |
| |
| JAVA_STATIC_METHOD ( |
| org_a11y_brltty_android_speech_SpeechDriver, tellFinished, void, |
| jlong synthesizer |
| ) { |
| tellSpeechFinished(javaPtrFromLong(synthesizer)); |
| } |
| |
| static void |
| spk_say (SpeechSynthesizer *spk, const unsigned char *buffer, size_t length, size_t count, const unsigned char *attributes) { |
| if (findDriverMethod(spk, &spk->driver.data->sayMethod, "sayText", |
| JAVA_SIG_METHOD(JAVA_SIG_BOOLEAN, |
| JAVA_SIG_LONG // synthesizer |
| JAVA_SIG_CHAR_SEQUENCE // text |
| ))) { |
| jstring string = (*spk->driver.data->env)->NewStringUTF(spk->driver.data->env, (const char *)buffer); |
| if (string) { |
| jboolean result = (*spk->driver.data->env)->CallStaticBooleanMethod( |
| spk->driver.data->env, spk->driver.data->driverClass, |
| spk->driver.data->sayMethod, javaPtrToLong(spk), string |
| ); |
| |
| (*spk->driver.data->env)->DeleteLocalRef(spk->driver.data->env, string); |
| string = NULL; |
| |
| if (!clearJavaException(spk->driver.data->env, 1)) { |
| if (result == JNI_TRUE) { |
| } |
| } |
| } else { |
| logMallocError(); |
| clearJavaException(spk->driver.data->env, 0); |
| } |
| } |
| } |
| |
| static void |
| spk_mute (SpeechSynthesizer *spk) { |
| if (findDriverMethod(spk, &spk->driver.data->muteMethod, "stopSpeaking", |
| JAVA_SIG_METHOD(JAVA_SIG_BOOLEAN, |
| ))) { |
| jboolean result = (*spk->driver.data->env)->CallStaticBooleanMethod(spk->driver.data->env, spk->driver.data->driverClass, spk->driver.data->muteMethod); |
| |
| if (!clearJavaException(spk->driver.data->env, 1)) { |
| if (result == JNI_TRUE) { |
| } |
| } |
| } |
| } |
| |
| static void |
| spk_setVolume (SpeechSynthesizer *spk, unsigned char setting) { |
| if (findDriverMethod(spk, &spk->driver.data->setVolumeMethod, "setVolume", |
| JAVA_SIG_METHOD(JAVA_SIG_BOOLEAN, |
| JAVA_SIG_FLOAT // volume |
| ))) { |
| jboolean result = (*spk->driver.data->env)->CallStaticBooleanMethod(spk->driver.data->env, spk->driver.data->driverClass, spk->driver.data->setVolumeMethod, getFloatSpeechVolume(setting)); |
| |
| if (!clearJavaException(spk->driver.data->env, 1)) { |
| if (result == JNI_TRUE) { |
| } |
| } |
| } |
| } |
| |
| static void |
| spk_setRate (SpeechSynthesizer *spk, unsigned char setting) { |
| if (findDriverMethod(spk, &spk->driver.data->setRateMethod, "setRate", |
| JAVA_SIG_METHOD(JAVA_SIG_BOOLEAN, |
| JAVA_SIG_FLOAT // rate |
| ))) { |
| jboolean result = (*spk->driver.data->env)->CallStaticBooleanMethod(spk->driver.data->env, spk->driver.data->driverClass, spk->driver.data->setRateMethod, getFloatSpeechRate(setting)); |
| |
| if (!clearJavaException(spk->driver.data->env, 1)) { |
| if (result == JNI_TRUE) { |
| } |
| } |
| } |
| } |
| |
| static void |
| spk_setPitch (SpeechSynthesizer *spk, unsigned char setting) { |
| if (findDriverMethod(spk, &spk->driver.data->setPitchMethod, "setPitch", |
| JAVA_SIG_METHOD(JAVA_SIG_BOOLEAN, |
| JAVA_SIG_FLOAT // pitch |
| ))) { |
| jboolean result = (*spk->driver.data->env)->CallStaticBooleanMethod(spk->driver.data->env, spk->driver.data->driverClass, spk->driver.data->setPitchMethod, getFloatSpeechPitch(setting)); |
| |
| if (!clearJavaException(spk->driver.data->env, 1)) { |
| if (result == JNI_TRUE) { |
| } |
| } |
| } |
| } |
| |
| static int |
| spk_construct (SpeechSynthesizer *spk, char **parameters) { |
| if ((spk->driver.data = malloc(sizeof(*spk->driver.data)))) { |
| memset(spk->driver.data, 0, sizeof(*spk->driver.data)); |
| |
| spk->driver.data->env = getJavaNativeInterface(); |
| spk->driver.data->driverClass = NULL; |
| spk->driver.data->startMethod = 0; |
| spk->driver.data->stopMethod = 0; |
| spk->driver.data->sayMethod = 0; |
| spk->driver.data->muteMethod = 0; |
| spk->driver.data->setVolumeMethod = 0; |
| spk->driver.data->setRateMethod = 0; |
| spk->driver.data->setPitchMethod = 0; |
| |
| spk->setVolume = spk_setVolume; |
| spk->setRate = spk_setRate; |
| spk->setPitch = spk_setPitch; |
| |
| if (spk->driver.data->env) { |
| if (findDriverMethod(spk, &spk->driver.data->startMethod, "startEngine", |
| JAVA_SIG_METHOD(JAVA_SIG_BOOLEAN, |
| ))) { |
| jboolean result = (*spk->driver.data->env)->CallStaticBooleanMethod(spk->driver.data->env, spk->driver.data->driverClass, spk->driver.data->startMethod); |
| |
| if (!clearJavaException(spk->driver.data->env, 1)) { |
| if (result == JNI_TRUE) { |
| return 1; |
| } |
| } |
| } |
| } |
| |
| releaseDriverClass(spk); |
| free(spk->driver.data); |
| } else { |
| logMallocError(); |
| } |
| |
| return 0; |
| } |
| |
| static void |
| spk_destruct (SpeechSynthesizer *spk) { |
| if (findDriverMethod(spk, &spk->driver.data->stopMethod, "stopEngine", |
| JAVA_SIG_METHOD(JAVA_SIG_VOID, |
| ))) { |
| (*spk->driver.data->env)->CallStaticVoidMethod(spk->driver.data->env, spk->driver.data->driverClass, spk->driver.data->stopMethod); |
| clearJavaException(spk->driver.data->env, 1); |
| } |
| |
| releaseDriverClass(spk); |
| free(spk->driver.data); |
| spk->driver.data = NULL; |
| } |