chore: catch c++ exceptions and translate into Java exceptions

This commit is contained in:
2026-06-01 02:55:26 +02:00
parent a924331ede
commit 85da003cb5
3 changed files with 162 additions and 15 deletions

View File

@@ -82,13 +82,13 @@ long LibPasada::getDurationMs() { return 0; }
/** Whether adapted audio is actively being output (not paused, not finished). */ /** Whether adapted audio is actively being output (not paused, not finished). */
bool LibPasada::isPlaying() { return false; } bool LibPasada::isPlaying() { return false; }
/** Current native state; see {@link PasadaState}. */ /** Current native state; see {@link PasadaState}. Must not throw. */
int LibPasada::getState() { return state; } int LibPasada::getState() { return state; }
/** Seek within the current track. */ /** Seek within the current track. */
void LibPasada::seekTo(long positionMs) {} void LibPasada::seekTo(long positionMs) {}
/** Runtime metrics / last error string for logging and debug UI. */ /** Runtime metrics / last error string for logging and debug UI. Must not throw. */
std::string LibPasada::getDiagnostics() { return ""; } std::string LibPasada::getDiagnostics() { return ""; }
/** Register listener for async events raised from the audio/native thread. */ /** Register listener for async events raised from the audio/native thread. */

View File

@@ -82,13 +82,13 @@ public:
/** Whether adapted audio is actively being output (not paused, not finished). */ /** Whether adapted audio is actively being output (not paused, not finished). */
bool isPlaying(); bool isPlaying();
/** Current native state; see {@link PasadaState}. */ /** Current native state; see {@link PasadaState}. Must not throw. */
int getState(); int getState();
/** Seek within the current track. */ /** Seek within the current track. */
void seekTo(long positionMs); void seekTo(long positionMs);
/** Runtime metrics / last error string for logging and debug UI. */ /** Runtime metrics / last error string for logging and debug UI. Must not throw. */
std::string getDiagnostics(); std::string getDiagnostics();
/** Register listener for async events raised from the audio/native thread. */ /** Register listener for async events raised from the audio/native thread. */

View File

@@ -30,8 +30,22 @@ Java_at_lockstep_player_pasada_LibPasada_init(
clearListener(env); clearListener(env);
delete g_libpasada; delete g_libpasada;
} }
try {
g_libpasada = new LibPasada(); g_libpasada = new LibPasada();
g_libpasada->init(); g_libpasada->init();
} catch (const std::bad_alloc&) {
jclass cls = env->FindClass("java/lang/OutOfMemoryError");
if (cls) env->ThrowNew(cls, "native allocation failed");
return;
} catch (const std::exception& e) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, e.what());
return;
} catch (...) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, "unknown native exception");
return;
}
} }
/** Submit one accelerometer sample (m/s^2); may be called from a sensor thread. */ /** Submit one accelerometer sample (m/s^2); may be called from a sensor thread. */
@@ -41,7 +55,22 @@ Java_at_lockstep_player_pasada_LibPasada_feedAccel(JNIEnv *env, jclass clazz, jf
jfloat z, jlong timestamp_nanos) { jfloat z, jlong timestamp_nanos) {
if (g_libpasada == nullptr) if (g_libpasada == nullptr)
return; return;
try {
g_libpasada->feedAccel(x, y, z, timestamp_nanos); g_libpasada->feedAccel(x, y, z, timestamp_nanos);
} catch (const std::bad_alloc&) {
jclass cls = env->FindClass("java/lang/OutOfMemoryError");
if (cls) env->ThrowNew(cls, "native allocation failed");
return;
} catch (const std::exception& e) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, e.what());
return;
} catch (...) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, "unknown native exception");
return;
}
} }
/** /**
@@ -57,24 +86,70 @@ Java_at_lockstep_player_pasada_LibPasada_play(JNIEnv *env, jclass clazz, jint fd
jlong length) { jlong length) {
if (g_libpasada == nullptr) if (g_libpasada == nullptr)
return; return;
try {
g_libpasada->play(fd, offset, length); g_libpasada->play(fd, offset, length);
} catch (const std::bad_alloc&) {
jclass cls = env->FindClass("java/lang/OutOfMemoryError");
if (cls) env->ThrowNew(cls, "native allocation failed");
return;
} catch (const std::exception& e) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, e.what());
return;
} catch (...) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, "unknown native exception");
return;
}
} }
/** PLAYING → PAUSED (silent output, graph kept alive). */ /** PLAYING → PAUSED (silent output, graph kept alive). */
extern "C" extern "C"
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_at_lockstep_player_pasada_LibPasada_pause(JNIEnv *env, jclass clazz) { Java_at_lockstep_player_pasada_LibPasada_pause(JNIEnv *env, jclass clazz) {
if (g_libpasada == nullptr) if (g_libpasada == nullptr)
return; return;
try {
g_libpasada->pause(); g_libpasada->pause();
} catch (const std::bad_alloc&) {
jclass cls = env->FindClass("java/lang/OutOfMemoryError");
if (cls) env->ThrowNew(cls, "native allocation failed");
return;
} catch (const std::exception& e) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, e.what());
return;
} catch (...) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, "unknown native exception");
return;
}
} }
/** PAUSED → PLAYING (same track, same decode position, same FD). */ /** PAUSED → PLAYING (same track, same decode position, same FD). */
extern "C" extern "C"
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_at_lockstep_player_pasada_LibPasada_resume(JNIEnv *env, jclass clazz) { Java_at_lockstep_player_pasada_LibPasada_resume(JNIEnv *env, jclass clazz) {
if (g_libpasada == nullptr) if (g_libpasada == nullptr)
return; return;
try {
g_libpasada->resume(); g_libpasada->resume();
} catch (const std::bad_alloc&) {
jclass cls = env->FindClass("java/lang/OutOfMemoryError");
if (cls) env->ThrowNew(cls, "native allocation failed");
return;
} catch (const std::exception& e) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, e.what());
return;
} catch (...) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, "unknown native exception");
return;
}
} }
/** Tear down Oboe for this run segment → STOPPED. */ /** Tear down Oboe for this run segment → STOPPED. */
extern "C" extern "C"
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
@@ -82,7 +157,18 @@ Java_at_lockstep_player_pasada_LibPasada_stop(JNIEnv *env, jclass clazz) {
clearListener(env); clearListener(env);
if (g_libpasada == nullptr) if (g_libpasada == nullptr)
return; return;
try {
g_libpasada->stop(); g_libpasada->stop();
} catch (const std::bad_alloc&) {
jclass cls = env->FindClass("java/lang/OutOfMemoryError");
if (cls) env->ThrowNew(cls, "native allocation failed");
} catch (const std::exception& e) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, e.what());
} catch (...) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, "unknown native exception");
}
delete g_libpasada; delete g_libpasada;
g_libpasada = nullptr; g_libpasada = nullptr;
} }
@@ -96,23 +182,67 @@ JNIEXPORT jlong JNICALL
Java_at_lockstep_player_pasada_LibPasada_getCurrentPositionMs(JNIEnv *env, jclass clazz) { Java_at_lockstep_player_pasada_LibPasada_getCurrentPositionMs(JNIEnv *env, jclass clazz) {
if (g_libpasada == nullptr) if (g_libpasada == nullptr)
return 0; return 0;
try {
return g_libpasada->getCurrentPositionMs(); return g_libpasada->getCurrentPositionMs();
} catch (const std::bad_alloc&) {
jclass cls = env->FindClass("java/lang/OutOfMemoryError");
if (cls) env->ThrowNew(cls, "native allocation failed");
return 0;
} catch (const std::exception& e) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, e.what());
return 0;
} catch (...) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, "unknown native exception");
return 0;
}
} }
/** Track duration in ms, or {@code 0} if not yet known. */ /** Track duration in ms, or {@code 0} if not yet known. */
extern "C" extern "C"
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_at_lockstep_player_pasada_LibPasada_getDurationMs(JNIEnv *env, jclass clazz) { Java_at_lockstep_player_pasada_LibPasada_getDurationMs(JNIEnv *env, jclass clazz) {
if (g_libpasada == nullptr) if (g_libpasada == nullptr)
return 0; return 0;
try {
return g_libpasada->getDurationMs(); return g_libpasada->getDurationMs();
} catch (const std::bad_alloc&) {
jclass cls = env->FindClass("java/lang/OutOfMemoryError");
if (cls) env->ThrowNew(cls, "native allocation failed");
return 0;
} catch (const std::exception& e) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, e.what());
return 0;
} catch (...) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, "unknown native exception");
return 0;
}
} }
/** Whether adapted audio is actively being output (not paused, not finished). */ /** Whether adapted audio is actively being output (not paused, not finished). */
extern "C" extern "C"
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_at_lockstep_player_pasada_LibPasada_isPlaying(JNIEnv *env, jclass clazz) { Java_at_lockstep_player_pasada_LibPasada_isPlaying(JNIEnv *env, jclass clazz) {
if (g_libpasada == nullptr) if (g_libpasada == nullptr)
return false; return false;
try {
return g_libpasada->isPlaying(); return g_libpasada->isPlaying();
} catch (const std::bad_alloc&) {
jclass cls = env->FindClass("java/lang/OutOfMemoryError");
if (cls) env->ThrowNew(cls, "native allocation failed");
return false;
} catch (const std::exception& e) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, e.what());
return false;
} catch (...) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, "unknown native exception");
return false;
}
} }
/** Current native state; see {@link PasadaState}. */ /** Current native state; see {@link PasadaState}. */
extern "C" extern "C"
@@ -120,15 +250,32 @@ JNIEXPORT jint JNICALL
Java_at_lockstep_player_pasada_LibPasada_getState(JNIEnv *env, jclass clazz) { Java_at_lockstep_player_pasada_LibPasada_getState(JNIEnv *env, jclass clazz) {
if(g_libpasada == nullptr) if(g_libpasada == nullptr)
return STOPPED; return STOPPED;
// explicitly no C++/JNI exception translation - keep getState() simple!
// there is no reasonable state for us to return here otherwise.
return g_libpasada->getState(); return g_libpasada->getState();
} }
/** Seek within the current track. */ /** Seek within the current track. */
extern "C" extern "C"
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_at_lockstep_player_pasada_LibPasada_seekTo(JNIEnv *env, jclass clazz, jlong position_ms) { Java_at_lockstep_player_pasada_LibPasada_seekTo(JNIEnv *env, jclass clazz, jlong position_ms) {
if (g_libpasada == nullptr) if (g_libpasada == nullptr)
return; return;
try {
g_libpasada->seekTo((long) position_ms); g_libpasada->seekTo((long) position_ms);
} catch (const std::bad_alloc&) {
jclass cls = env->FindClass("java/lang/OutOfMemoryError");
if (cls) env->ThrowNew(cls, "native allocation failed");
return;
} catch (const std::exception& e) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, e.what());
return;
} catch (...) {
jclass cls = env->FindClass("java/lang/RuntimeException");
if (cls) env->ThrowNew(cls, "unknown native exception");
return;
}
} }
/** Runtime metrics / last error string for logging and debug UI. */ /** Runtime metrics / last error string for logging and debug UI. */
extern "C" extern "C"