JNI Exception Handling (#1452)

This commit is contained in:
ivan provalov
2025-02-19 07:02:28 -08:00
committed by GitHub
parent 654d2285eb
commit 4801094133
4 changed files with 103 additions and 22 deletions

View File

@@ -5,6 +5,8 @@
#ifndef SHERPA_ONNX_JNI_COMMON_H_ #ifndef SHERPA_ONNX_JNI_COMMON_H_
#define SHERPA_ONNX_JNI_COMMON_H_ #define SHERPA_ONNX_JNI_COMMON_H_
#include <string>
#if __ANDROID_API__ >= 9 #if __ANDROID_API__ >= 9
#include <strstream> #include <strstream>
@@ -42,4 +44,62 @@
jobject NewInteger(JNIEnv *env, int32_t value); jobject NewInteger(JNIEnv *env, int32_t value);
jobject NewFloat(JNIEnv *env, float 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_ #endif // SHERPA_ONNX_JNI_COMMON_H_

View File

@@ -353,11 +353,19 @@ Java_com_k2fsa_sherpa_onnx_OfflineRecognizer_createStream(JNIEnv * /*env*/,
SHERPA_ONNX_EXTERN_C SHERPA_ONNX_EXTERN_C
JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_OfflineRecognizer_decode( JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_OfflineRecognizer_decode(
JNIEnv * /*env*/, jobject /*obj*/, jlong ptr, jlong streamPtr) { JNIEnv *env, jobject /*obj*/, jlong ptr, jlong streamPtr) {
auto recognizer = reinterpret_cast<sherpa_onnx::OfflineRecognizer *>(ptr); SafeJNI(env, "OfflineRecognizer_decode", [&] {
auto stream = reinterpret_cast<sherpa_onnx::OfflineStream *>(streamPtr); if (!ValidatePointer(env, ptr, "OfflineRecognizer_decode",
"OfflineRecognizer pointer is null.") ||
!ValidatePointer(env, streamPtr, "OfflineRecognizer_decode",
"OfflineStream pointer is null.")) {
return;
}
recognizer->DecodeStream(stream); auto recognizer = reinterpret_cast<sherpa_onnx::OfflineRecognizer *>(ptr);
auto stream = reinterpret_cast<sherpa_onnx::OfflineStream *>(streamPtr);
recognizer->DecodeStream(stream);
});
} }
SHERPA_ONNX_EXTERN_C SHERPA_ONNX_EXTERN_C

View File

@@ -220,16 +220,17 @@ JNIEXPORT jlong JNICALL Java_com_k2fsa_sherpa_onnx_OfflineTts_newFromAsset(
SHERPA_ONNX_EXTERN_C SHERPA_ONNX_EXTERN_C
JNIEXPORT jlong JNICALL Java_com_k2fsa_sherpa_onnx_OfflineTts_newFromFile( JNIEXPORT jlong JNICALL Java_com_k2fsa_sherpa_onnx_OfflineTts_newFromFile(
JNIEnv *env, jobject /*obj*/, jobject _config) { JNIEnv *env, jobject /*obj*/, jobject _config) {
auto config = sherpa_onnx::GetOfflineTtsConfig(env, _config); return SafeJNI(env, "OfflineTts_newFromFile", [&] -> jlong {
SHERPA_ONNX_LOGE("config:\n%s", config.ToString().c_str()); auto config = sherpa_onnx::GetOfflineTtsConfig(env, _config);
SHERPA_ONNX_LOGE("config:\n%s", config.ToString().c_str());
if (!config.Validate()) { if (!config.Validate()) {
SHERPA_ONNX_LOGE("Errors found in config!"); SHERPA_ONNX_LOGE("Errors found in config!");
} }
auto tts = new sherpa_onnx::OfflineTts(config); auto tts = new sherpa_onnx::OfflineTts(config);
return reinterpret_cast<jlong>(tts);
return (jlong)tts; }, 0L);
} }
SHERPA_ONNX_EXTERN_C SHERPA_ONNX_EXTERN_C

View File

@@ -112,14 +112,20 @@ JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_Vad_delete(JNIEnv * /*env*/,
SHERPA_ONNX_EXTERN_C SHERPA_ONNX_EXTERN_C
JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_Vad_acceptWaveform( JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_Vad_acceptWaveform(
JNIEnv *env, jobject /*obj*/, jlong ptr, jfloatArray samples) { 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); auto model = reinterpret_cast<sherpa_onnx::VoiceActivityDetector *>(ptr);
jsize n = env->GetArrayLength(samples); 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 SHERPA_ONNX_EXTERN_C
@@ -173,11 +179,17 @@ JNIEXPORT bool JNICALL Java_com_k2fsa_sherpa_onnx_Vad_isSpeechDetected(
} }
SHERPA_ONNX_EXTERN_C SHERPA_ONNX_EXTERN_C
JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_Vad_reset(JNIEnv * /*env*/, JNIEXPORT void JNICALL Java_com_k2fsa_sherpa_onnx_Vad_reset(
jobject /*obj*/, JNIEnv *env, jobject /*obj*/, jlong ptr) {
jlong ptr) { SafeJNI(env, "Vad_reset", [&] {
auto model = reinterpret_cast<sherpa_onnx::VoiceActivityDetector *>(ptr); if (!ValidatePointer(env, ptr, "Vad_reset",
model->Reset(); "VoiceActivityDetector pointer is null.")) {
return;
}
auto model = reinterpret_cast<sherpa_onnx::VoiceActivityDetector *>(ptr);
model->Reset();
});
} }
SHERPA_ONNX_EXTERN_C SHERPA_ONNX_EXTERN_C