ivan provalov
Committed by GitHub

JNI Exception Handling (#1452)

... ... @@ -5,6 +5,8 @@
#ifndef SHERPA_ONNX_JNI_COMMON_H_
#define SHERPA_ONNX_JNI_COMMON_H_
#include <string>
#if __ANDROID_API__ >= 9
#include <strstream>
... ... @@ -42,4 +44,62 @@
jobject NewInteger(JNIEnv *env, int32_t value);
jobject NewFloat(JNIEnv *env, float value);
// Template function for non-void return types
template <typename Func, typename ReturnType>
ReturnType SafeJNI(JNIEnv *env, const char *functionName, Func func,
ReturnType defaultValue) {
try {
return func();
} catch (const std::exception &e) {
jclass exClass = env->FindClass("java/lang/RuntimeException");
if (exClass != nullptr) {
std::string errorMessage = std::string(functionName) + ": " + e.what();
env->ThrowNew(exClass, errorMessage.c_str());
}
} catch (...) {
jclass exClass = env->FindClass("java/lang/RuntimeException");
if (exClass != nullptr) {
std::string errorMessage = std::string(functionName) +
": Native exception: caught unknown exception";
env->ThrowNew(exClass, errorMessage.c_str());
}
}
return defaultValue;
}
// Specialization for void return type
template <typename Func>
void SafeJNI(JNIEnv *env, const char *functionName, Func func) {
try {
func();
} catch (const std::exception &e) {
jclass exClass = env->FindClass("java/lang/RuntimeException");
if (exClass != nullptr) {
std::string errorMessage = std::string(functionName) + ": " + e.what();
env->ThrowNew(exClass, errorMessage.c_str());
}
} catch (...) {
jclass exClass = env->FindClass("java/lang/RuntimeException");
if (exClass != nullptr) {
std::string errorMessage = std::string(functionName) +
": Native exception: caught unknown exception";
env->ThrowNew(exClass, errorMessage.c_str());
}
}
}
// Helper function to validate JNI pointers
inline bool ValidatePointer(JNIEnv *env, jlong ptr,
const char *functionName, const char *message) {
if (ptr == 0) {
jclass exClass = env->FindClass("java/lang/NullPointerException");
if (exClass != nullptr) {
std::string errorMessage = std::string(functionName) + ": " + message;
env->ThrowNew(exClass, errorMessage.c_str());
}
return false;
}
return true;
}
#endif // SHERPA_ONNX_JNI_COMMON_H_
... ...
... ... @@ -353,11 +353,19 @@ Java_com_k2fsa_sherpa_onnx_OfflineRecognizer_createStream(JNIEnv * /*env*/,
SHERPA_ONNX_EXTERN_C
JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_OfflineRecognizer_decode(
JNIEnv * /*env*/, jobject /*obj*/, jlong ptr, jlong streamPtr) {
auto recognizer = reinterpret_cast<sherpa_onnx::OfflineRecognizer *>(ptr);
auto stream = reinterpret_cast<sherpa_onnx::OfflineStream *>(streamPtr);
recognizer->DecodeStream(stream);
JNIEnv *env, jobject /*obj*/, jlong ptr, jlong streamPtr) {
SafeJNI(env, "OfflineRecognizer_decode", [&] {
if (!ValidatePointer(env, ptr, "OfflineRecognizer_decode",
"OfflineRecognizer pointer is null.") ||
!ValidatePointer(env, streamPtr, "OfflineRecognizer_decode",
"OfflineStream pointer is null.")) {
return;
}
auto recognizer = reinterpret_cast<sherpa_onnx::OfflineRecognizer *>(ptr);
auto stream = reinterpret_cast<sherpa_onnx::OfflineStream *>(streamPtr);
recognizer->DecodeStream(stream);
});
}
SHERPA_ONNX_EXTERN_C
... ...
... ... @@ -220,16 +220,17 @@ JNIEXPORT jlong JNICALL Java_com_k2fsa_sherpa_onnx_OfflineTts_newFromAsset(
SHERPA_ONNX_EXTERN_C
JNIEXPORT jlong JNICALL Java_com_k2fsa_sherpa_onnx_OfflineTts_newFromFile(
JNIEnv *env, jobject /*obj*/, jobject _config) {
auto config = sherpa_onnx::GetOfflineTtsConfig(env, _config);
SHERPA_ONNX_LOGE("config:\n%s", config.ToString().c_str());
if (!config.Validate()) {
SHERPA_ONNX_LOGE("Errors found in config!");
}
return SafeJNI(env, "OfflineTts_newFromFile", [&] -> jlong {
auto config = sherpa_onnx::GetOfflineTtsConfig(env, _config);
SHERPA_ONNX_LOGE("config:\n%s", config.ToString().c_str());
auto tts = new sherpa_onnx::OfflineTts(config);
if (!config.Validate()) {
SHERPA_ONNX_LOGE("Errors found in config!");
}
return (jlong)tts;
auto tts = new sherpa_onnx::OfflineTts(config);
return reinterpret_cast<jlong>(tts);
}, 0L);
}
SHERPA_ONNX_EXTERN_C
... ...
... ... @@ -112,14 +112,20 @@ JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_Vad_delete(JNIEnv * /*env*/,
SHERPA_ONNX_EXTERN_C
JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_Vad_acceptWaveform(
JNIEnv *env, jobject /*obj*/, jlong ptr, jfloatArray samples) {
auto model = reinterpret_cast<sherpa_onnx::VoiceActivityDetector *>(ptr);
SafeJNI(env, "Vad_acceptWaveform", [&] {
if (!ValidatePointer(env, ptr, "Vad_acceptWaveform",
"VoiceActivityDetector pointer is null.")) {
return;
}
jfloat *p = env->GetFloatArrayElements(samples, nullptr);
jsize n = env->GetArrayLength(samples);
auto model = reinterpret_cast<sherpa_onnx::VoiceActivityDetector *>(ptr);
jfloat *p = env->GetFloatArrayElements(samples, nullptr);
jsize n = env->GetArrayLength(samples);
model->AcceptWaveform(p, n);
model->AcceptWaveform(p, n);
env->ReleaseFloatArrayElements(samples, p, JNI_ABORT);
env->ReleaseFloatArrayElements(samples, p, JNI_ABORT);
});
}
SHERPA_ONNX_EXTERN_C
... ... @@ -173,11 +179,17 @@ JNIEXPORT bool JNICALL Java_com_k2fsa_sherpa_onnx_Vad_isSpeechDetected(
}
SHERPA_ONNX_EXTERN_C
JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_Vad_reset(JNIEnv * /*env*/,
jobject /*obj*/,
jlong ptr) {
auto model = reinterpret_cast<sherpa_onnx::VoiceActivityDetector *>(ptr);
model->Reset();
JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_Vad_reset(
JNIEnv *env, jobject /*obj*/, jlong ptr) {
SafeJNI(env, "Vad_reset", [&] {
if (!ValidatePointer(env, ptr, "Vad_reset",
"VoiceActivityDetector pointer is null.")) {
return;
}
auto model = reinterpret_cast<sherpa_onnx::VoiceActivityDetector *>(ptr);
model->Reset();
});
}
SHERPA_ONNX_EXTERN_C
... ...