diff --git a/android/java/main/java/ai/moonshine/voice/Transcriber.java b/android/java/main/java/ai/moonshine/voice/Transcriber.java --- a/android/java/main/java/ai/moonshine/voice/Transcriber.java +++ b/android/java/main/java/ai/moonshine/voice/Transcriber.java @@ -25,7 +25,7 @@ import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.Map; -public class Transcriber { +public class Transcriber implements AutoCloseable { private int transcriberHandle = -1; private int defaultStreamHandle = -1; private final List> listeners = @@ -85,18 +85,22 @@ public class Transcriber { this.getDefaultStreamHandle(); } - protected void finalize() throws Throwable { + @Override + public synchronized void close() { if (this.transcriberHandle >= 0) { if (this.defaultStreamHandle >= 0) { JNI.moonshineFreeStream(this.transcriberHandle, this.defaultStreamHandle); this.defaultStreamHandle = -1; } + this.removeAllListeners(); JNI.moonshineFreeTranscriber(this.transcriberHandle); this.transcriberHandle = -1; } } + protected void finalize() throws Throwable { this.close(); } + public Transcript transcribeWithoutStreaming(float[] audioData, int sampleRate) { return JNI.moonshineTranscribeWithoutStreaming(this.transcriberHandle, diff --git a/build.gradle.kts b/build.gradle.kts --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,6 +5,28 @@ plugins { id("com.vanniktech.maven.publish") version "0.28.0" } +fun envOrProp(envName: String, propName: String, fallback: String? = null): String? { + val envValue = System.getenv(envName)?.trim() + if (!envValue.isNullOrEmpty()) { + return envValue + } + + val propValue = providers.gradleProperty(propName).orNull?.trim() + if (!propValue.isNullOrEmpty()) { + return propValue + } + + return fallback +} + +val moonshineAbiFilters = envOrProp( + "SITEED_MOONSHINE_ANDROID_ABIS", + "siteedMoonshineAndroidAbis", + "arm64-v8a" +)?.split(",")?.map { it.trim() }?.filter { it.isNotEmpty() } ?: emptyList() +val moonshineOrtLibPath = envOrProp("SITEED_MOONSHINE_ORT_LIB_PATH", "siteedMoonshineOrtLibPath") +val moonshineOrtIncludeDir = envOrProp("SITEED_MOONSHINE_ORT_INCLUDE_DIR", "siteedMoonshineOrtIncludeDir") + android { namespace = "ai.moonshine.voice" compileSdk = 35 @@ -16,12 +38,17 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles("consumer-rules.pro") ndk { - // Only build for ARM64 to match the app module - abiFilters += listOf("arm64-v8a") + abiFilters += moonshineAbiFilters } externalNativeBuild { cmake { arguments("-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON") + if (!moonshineOrtLibPath.isNullOrEmpty()) { + arguments("-DMOONSHINE_ONNXRUNTIME_LIB_PATH=$moonshineOrtLibPath") + } + if (!moonshineOrtIncludeDir.isNullOrEmpty()) { + arguments("-DMOONSHINE_ONNXRUNTIME_INCLUDE_DIR=$moonshineOrtIncludeDir") + } } } } diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -97,7 +97,7 @@ target_include_directories(moonshine PRIVATE ${CMAKE_CURRENT_LIST_DIR}/moonshine-utils ${CMAKE_CURRENT_LIST_DIR}/ort-utils ${CMAKE_CURRENT_LIST_DIR}/bin-tokenizer - ${CMAKE_CURRENT_LIST_DIR}/third-party/onnxruntime/include + ${ONNXRUNTIME_INCLUDE_DIR} ${CMAKE_CURRENT_LIST_DIR}/third-party/utf-8/ ) diff --git a/core/ort-utils/CMakeLists.txt b/core/ort-utils/CMakeLists.txt --- a/core/ort-utils/CMakeLists.txt +++ b/core/ort-utils/CMakeLists.txt @@ -31,7 +31,7 @@ target_compile_options(ort-utils PRIVATE target_include_directories(ort-utils PRIVATE ${MOONSHINE_UTILS_INCLUDE_DIR} - ${CMAKE_CURRENT_LIST_DIR}/../third-party/onnxruntime/include + ${ONNXRUNTIME_INCLUDE_DIR} ) if (ANDROID) @@ -69,7 +69,7 @@ target_include_directories(ort-utils-test PRIVATE ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/../moonshine-utils ${CMAKE_CURRENT_LIST_DIR}/../third-party/doctest - ${CMAKE_CURRENT_LIST_DIR}/../third-party/onnxruntime/include + ${ONNXRUNTIME_INCLUDE_DIR} ) target_link_libraries(ort-utils-test PRIVATE diff --git a/core/third-party/onnxruntime/find-ort-library-path.cmake b/core/third-party/onnxruntime/find-ort-library-path.cmake --- a/core/third-party/onnxruntime/find-ort-library-path.cmake +++ b/core/third-party/onnxruntime/find-ort-library-path.cmake @@ -1,4 +1,16 @@ -if (ANDROID) +if (DEFINED MOONSHINE_ONNXRUNTIME_INCLUDE_DIR AND NOT "${MOONSHINE_ONNXRUNTIME_INCLUDE_DIR}" STREQUAL "") + set(ONNXRUNTIME_INCLUDE_DIR "${MOONSHINE_ONNXRUNTIME_INCLUDE_DIR}" CACHE INTERNAL "") +elseif(DEFINED ENV{MOONSHINE_ONNXRUNTIME_INCLUDE_DIR} AND NOT "$ENV{MOONSHINE_ONNXRUNTIME_INCLUDE_DIR}" STREQUAL "") + set(ONNXRUNTIME_INCLUDE_DIR "$ENV{MOONSHINE_ONNXRUNTIME_INCLUDE_DIR}" CACHE INTERNAL "") +else() + set(ONNXRUNTIME_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/include" CACHE INTERNAL "") +endif() + +if (DEFINED MOONSHINE_ONNXRUNTIME_LIB_PATH AND NOT "${MOONSHINE_ONNXRUNTIME_LIB_PATH}" STREQUAL "") + set(ONNXRUNTIME_LIB_PATH "${MOONSHINE_ONNXRUNTIME_LIB_PATH}" CACHE INTERNAL "") +elseif(DEFINED ENV{MOONSHINE_ONNXRUNTIME_LIB_PATH} AND NOT "$ENV{MOONSHINE_ONNXRUNTIME_LIB_PATH}" STREQUAL "") + set(ONNXRUNTIME_LIB_PATH "$ENV{MOONSHINE_ONNXRUNTIME_LIB_PATH}" CACHE INTERNAL "") +elseif (ANDROID) # Detect Android ABI and map to library directory name if(ANDROID_ABI STREQUAL "armeabi-v7a") set(ONNXRUNTIME_ABI_DIR "armeabi-v7a")