From 85da003cb535be60e7842140eebfbbe287dc0ab5 Mon Sep 17 00:00:00 2001 From: David Madl Date: Mon, 1 Jun 2026 02:55:26 +0200 Subject: [PATCH] chore: catch c++ exceptions and translate into Java exceptions --- app/src/main/cpp/LibPasada.cpp | 4 +- app/src/main/cpp/LibPasada.h | 4 +- app/src/main/cpp/jni_libpasada.cpp | 169 +++++++++++++++++++++++++++-- 3 files changed, 162 insertions(+), 15 deletions(-) diff --git a/app/src/main/cpp/LibPasada.cpp b/app/src/main/cpp/LibPasada.cpp index f4b8de2..48cc64b 100644 --- a/app/src/main/cpp/LibPasada.cpp +++ b/app/src/main/cpp/LibPasada.cpp @@ -82,13 +82,13 @@ long LibPasada::getDurationMs() { return 0; } /** Whether adapted audio is actively being output (not paused, not finished). */ 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; } /** Seek within the current track. */ 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 ""; } /** Register listener for async events raised from the audio/native thread. */ diff --git a/app/src/main/cpp/LibPasada.h b/app/src/main/cpp/LibPasada.h index 7c04497..6cc452e 100644 --- a/app/src/main/cpp/LibPasada.h +++ b/app/src/main/cpp/LibPasada.h @@ -82,13 +82,13 @@ public: /** Whether adapted audio is actively being output (not paused, not finished). */ bool isPlaying(); - /** Current native state; see {@link PasadaState}. */ + /** Current native state; see {@link PasadaState}. Must not throw. */ int getState(); /** Seek within the current track. */ 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(); /** Register listener for async events raised from the audio/native thread. */ diff --git a/app/src/main/cpp/jni_libpasada.cpp b/app/src/main/cpp/jni_libpasada.cpp index 2ee9099..52a8fef 100644 --- a/app/src/main/cpp/jni_libpasada.cpp +++ b/app/src/main/cpp/jni_libpasada.cpp @@ -30,8 +30,22 @@ Java_at_lockstep_player_pasada_LibPasada_init( clearListener(env); delete g_libpasada; } - g_libpasada = new LibPasada(); - g_libpasada->init(); + try { + g_libpasada = new LibPasada(); + 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. */ @@ -41,7 +55,22 @@ Java_at_lockstep_player_pasada_LibPasada_feedAccel(JNIEnv *env, jclass clazz, jf jfloat z, jlong timestamp_nanos) { if (g_libpasada == nullptr) return; - g_libpasada->feedAccel(x, y, z, timestamp_nanos); + + try { + 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) { if (g_libpasada == nullptr) return; - g_libpasada->play(fd, offset, length); + + try { + 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). */ extern "C" JNIEXPORT void JNICALL Java_at_lockstep_player_pasada_LibPasada_pause(JNIEnv *env, jclass clazz) { if (g_libpasada == nullptr) return; - g_libpasada->pause(); + try { + 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). */ extern "C" JNIEXPORT void JNICALL Java_at_lockstep_player_pasada_LibPasada_resume(JNIEnv *env, jclass clazz) { if (g_libpasada == nullptr) return; - g_libpasada->resume(); + try { + 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. */ extern "C" JNIEXPORT void JNICALL @@ -82,7 +157,18 @@ Java_at_lockstep_player_pasada_LibPasada_stop(JNIEnv *env, jclass clazz) { clearListener(env); if (g_libpasada == nullptr) return; - g_libpasada->stop(); + try { + 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; g_libpasada = nullptr; } @@ -96,23 +182,67 @@ JNIEXPORT jlong JNICALL Java_at_lockstep_player_pasada_LibPasada_getCurrentPositionMs(JNIEnv *env, jclass clazz) { if (g_libpasada == nullptr) return 0; - return g_libpasada->getCurrentPositionMs(); + try { + 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. */ extern "C" JNIEXPORT jlong JNICALL Java_at_lockstep_player_pasada_LibPasada_getDurationMs(JNIEnv *env, jclass clazz) { if (g_libpasada == nullptr) return 0; - return g_libpasada->getDurationMs(); + try { + 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). */ extern "C" JNIEXPORT jboolean JNICALL Java_at_lockstep_player_pasada_LibPasada_isPlaying(JNIEnv *env, jclass clazz) { if (g_libpasada == nullptr) return false; - return g_libpasada->isPlaying(); + try { + 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}. */ extern "C" @@ -120,15 +250,32 @@ JNIEXPORT jint JNICALL Java_at_lockstep_player_pasada_LibPasada_getState(JNIEnv *env, jclass clazz) { if(g_libpasada == nullptr) 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(); } + /** Seek within the current track. */ extern "C" JNIEXPORT void JNICALL Java_at_lockstep_player_pasada_LibPasada_seekTo(JNIEnv *env, jclass clazz, jlong position_ms) { if (g_libpasada == nullptr) return; - g_libpasada->seekTo((long) position_ms); + try { + 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. */ extern "C"