From 06bd5ca624b4bea03fb132e4e11f69c7a1b046b2 Mon Sep 17 00:00:00 2001 From: clocks Date: Wed, 19 Jun 2024 15:10:27 -0400 Subject: [PATCH 1/6] Do not tap into the executors or Handlers Bad practice, we can use kotlin coroutines instead. --- .../kotlin/org/vosk/android/StorageService.kt | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/kotlin/src/androidMain/kotlin/org/vosk/android/StorageService.kt b/kotlin/src/androidMain/kotlin/org/vosk/android/StorageService.kt index 75093fcc..557efe1b 100644 --- a/kotlin/src/androidMain/kotlin/org/vosk/android/StorageService.kt +++ b/kotlin/src/androidMain/kotlin/org/vosk/android/StorageService.kt @@ -18,13 +18,13 @@ package org.vosk.android import android.content.Context import android.content.res.AssetManager import android.os.Environment -import android.os.Handler -import android.os.Looper import android.util.Log +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import org.vosk.Model +import org.vosk.exception.IOException import java.io.* -import java.util.concurrent.Executor -import java.util.concurrent.Executors import java.util.function.Consumer /** @@ -34,6 +34,7 @@ import java.util.function.Consumer object StorageService { private val TAG = StorageService::class.simpleName + @Deprecated("Use your own multi-threading. Or maybe just use Kotlin Coroutines.") @JvmStatic fun unpack( context: Context, @@ -42,20 +43,22 @@ object StorageService { completeCallback: Consumer, errorCallback: Consumer ) { - val executor: Executor = - Executors.newSingleThreadExecutor() // change according to your requirements - val handler = Handler(Looper.getMainLooper()) - executor.execute { + GlobalScope.launch(Dispatchers.IO) { try { - val outputPath = sync(context, sourcePath, targetPath) - val model = Model(outputPath) - handler.post { completeCallback.accept(model) } + val model = unpack(context, sourcePath, targetPath) + launch(Dispatchers.Main) { completeCallback.accept(model) } } catch (e: IOException) { - handler.post { errorCallback.accept(e) } + launch(Dispatchers.Main) { errorCallback.accept(e) } } } } + @Throws(IOException::class) + fun unpack(context: Context, sourcePath: String, targetPath: String): Model { + val outputPath = sync(context, sourcePath, targetPath) + return Model(outputPath) + } + @JvmStatic @Throws(IOException::class) fun sync(context: Context, sourcePath: String, targetPath: String): String { From d034dcb7283b99e4ec23897a2392298efb751b7d Mon Sep 17 00:00:00 2001 From: clocks Date: Wed, 19 Jun 2024 15:22:06 -0400 Subject: [PATCH 2/6] SpeechService: Use Coroutines --- .../kotlin/org/vosk/android/SpeechService.kt | 165 ++++++++---------- 1 file changed, 71 insertions(+), 94 deletions(-) diff --git a/kotlin/src/androidMain/kotlin/org/vosk/android/SpeechService.kt b/kotlin/src/androidMain/kotlin/org/vosk/android/SpeechService.kt index 300fccb3..78c22bb5 100644 --- a/kotlin/src/androidMain/kotlin/org/vosk/android/SpeechService.kt +++ b/kotlin/src/androidMain/kotlin/org/vosk/android/SpeechService.kt @@ -19,8 +19,12 @@ import android.annotation.SuppressLint import android.media.AudioFormat import android.media.AudioRecord import android.media.MediaRecorder.AudioSource -import android.os.Handler -import android.os.Looper +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext import org.vosk.Recognizer import java.io.IOException import kotlin.math.roundToInt @@ -37,8 +41,13 @@ class SpeechService @Throws(IOException::class) constructor( private val sampleRate: Int private val bufferSize: Int private val recorder: AudioRecord - private var recognizerThread: RecognizerThread? = null - private val mainHandler = Handler(Looper.getMainLooper()) + + private val scope = CoroutineScope(Dispatchers.IO) + private var recognizerThread: Job? = null + + private var paused = false + private var reset = false + private var interrupt = false /** * Creates speech service. Service holds the AudioRecord object, so you @@ -70,8 +79,7 @@ class SpeechService @Throws(IOException::class) constructor( */ fun startListening(listener: RecognitionListener): Boolean { if (null != recognizerThread) return false - recognizerThread = RecognizerThread(listener) - recognizerThread!!.start() + recognizerThread = scope.launch { startRecognizer(listener) } return true } @@ -86,21 +94,21 @@ class SpeechService @Throws(IOException::class) constructor( */ fun startListening(listener: RecognitionListener, timeout: Int): Boolean { if (null != recognizerThread) return false - recognizerThread = RecognizerThread(listener, timeout) - recognizerThread!!.start() + recognizerThread = scope.launch { startRecognizer(listener, timeout) } return true } - private fun stopRecognizerThread(): Boolean { + private suspend fun stopRecognizerThread(): Boolean { if (null == recognizerThread) return false try { - recognizerThread!!.interrupt() + interrupt = true recognizerThread!!.join() } catch (e: InterruptedException) { // Restore the interrupted status. Thread.currentThread().interrupt() } recognizerThread = null + interrupt = false return true } @@ -111,7 +119,7 @@ class SpeechService @Throws(IOException::class) constructor( * @return true if recognition was actually stopped */ fun stop(): Boolean { - return stopRecognizerThread() + return runBlocking { stopRecognizerThread() } } /** @@ -121,10 +129,8 @@ class SpeechService @Throws(IOException::class) constructor( * @return true if recognition was actually stopped */ fun cancel(): Boolean { - if (recognizerThread != null) { - recognizerThread!!.setPause(true) - } - return stopRecognizerThread() + paused = true + return runBlocking { stopRecognizerThread() } } /** @@ -135,101 +141,72 @@ class SpeechService @Throws(IOException::class) constructor( } fun setPause(paused: Boolean) { - if (recognizerThread != null) { - recognizerThread!!.setPause(paused) - } + this.paused = paused } /** * Resets recognizer in a thread, starts recognition over again */ fun reset() { - if (recognizerThread != null) { - recognizerThread!!.reset() - } + reset = true } - private inner class RecognizerThread @JvmOverloads constructor( - var listener: RecognitionListener, - timeout: Int = Companion.NO_TIMEOUT - ) : Thread() { - private var remainingSamples: Int - private val timeoutSamples: Int + private suspend fun startRecognizer( + listener: RecognitionListener, + timeout: Int = NO_TIMEOUT + ) { + var remainingSamples: Int - @Volatile - private var paused = false + val timeoutSamples: Int = if (timeout != NO_TIMEOUT) { + timeout * sampleRate / 1000 + } else { + NO_TIMEOUT + } - @Volatile - private var reset = false + remainingSamples = timeoutSamples - init { - timeoutSamples = if (timeout != Companion.NO_TIMEOUT) { - timeout * sampleRate / 1000 + recorder.startRecording() + if (recorder.recordingState == AudioRecord.RECORDSTATE_STOPPED) { + recorder.stop() + val ioe = IOException( + "Failed to start recording. Microphone might be already in use." + ) + withContext(Dispatchers.Main) { listener.onError(ioe) } + } + val buffer = ShortArray(bufferSize) + while (!interrupt + && (timeoutSamples == NO_TIMEOUT || remainingSamples > 0) + ) { + val nread = recorder.read(buffer, 0, buffer.size) + if (paused) { + continue + } + if (reset) { + recognizer.reset() + reset = false + } + if (nread < 0) throw RuntimeException("error reading audio buffer") + if (recognizer.acceptWaveform(buffer)) { + val result = recognizer.result + withContext(Dispatchers.Main) { listener.onResult(result) } } else { - Companion.NO_TIMEOUT + val partialResult = recognizer.partialResult + withContext(Dispatchers.Main) { listener.onPartialResult(partialResult) } + } + if (timeoutSamples != NO_TIMEOUT) { + remainingSamples -= nread } - remainingSamples = timeoutSamples - } - - /** - * When we are paused, don't process audio by the recognizer and don't emit - * any listener results - * - * @param paused the status of pause - */ - fun setPause(paused: Boolean) { - this.paused = paused } - /** - * Set reset state to signal reset of the recognizer and start over - */ - fun reset() { - reset = true - } + recorder.stop() - override fun run() { - recorder.startRecording() - if (recorder.recordingState == AudioRecord.RECORDSTATE_STOPPED) { - recorder.stop() - val ioe = IOException( - "Failed to start recording. Microphone might be already in use." - ) - mainHandler.post { listener.onError(ioe) } - } - val buffer = ShortArray(bufferSize) - while (!interrupted() - && (timeoutSamples == Companion.NO_TIMEOUT || remainingSamples > 0) - ) { - val nread = recorder.read(buffer, 0, buffer.size) - if (paused) { - continue - } - if (reset) { - recognizer.reset() - reset = false - } - if (nread < 0) throw RuntimeException("error reading audio buffer") - if (recognizer.acceptWaveform(buffer)) { - val result = recognizer.result - mainHandler.post { listener.onResult(result) } - } else { - val partialResult = recognizer.partialResult - mainHandler.post { listener.onPartialResult(partialResult) } - } - if (timeoutSamples != NO_TIMEOUT) { - remainingSamples -= nread - } - } - recorder.stop() - if (!paused) { - // If we met timeout signal that speech ended - if (timeoutSamples != NO_TIMEOUT && remainingSamples <= 0) { - mainHandler.post { listener.onTimeout() } - } else { - val finalResult = recognizer.finalResult - mainHandler.post { listener.onFinalResult(finalResult) } - } + if (!paused) { + // If we met timeout signal that speech ended + if (timeoutSamples != NO_TIMEOUT && remainingSamples <= 0) { + withContext(Dispatchers.Main) { listener.onTimeout() } + } else { + val finalResult = recognizer.finalResult + withContext(Dispatchers.Main) { listener.onFinalResult(finalResult) } } } } From 6d797d8260430f628e8bd9b0d714d4cf0873a698 Mon Sep 17 00:00:00 2001 From: clocks Date: Wed, 19 Jun 2024 15:27:16 -0400 Subject: [PATCH 3/6] SpeechStreamService: Use Coroutines --- .../org/vosk/android/SpeechStreamService.kt | 105 ++++++++++-------- 1 file changed, 57 insertions(+), 48 deletions(-) diff --git a/kotlin/src/androidMain/kotlin/org/vosk/android/SpeechStreamService.kt b/kotlin/src/androidMain/kotlin/org/vosk/android/SpeechStreamService.kt index ad3f813e..d34bf793 100644 --- a/kotlin/src/androidMain/kotlin/org/vosk/android/SpeechStreamService.kt +++ b/kotlin/src/androidMain/kotlin/org/vosk/android/SpeechStreamService.kt @@ -15,8 +15,12 @@ */ package org.vosk.android -import android.os.Handler -import android.os.Looper +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext import org.vosk.Recognizer import java.io.IOException import java.io.InputStream @@ -35,8 +39,11 @@ class SpeechStreamService( private val inputStream: InputStream private val sampleRate: Int private val bufferSize: Int - private var recognizerThread: Thread? = null - private val mainHandler = Handler(Looper.getMainLooper()) + + private var recognizerThread: Job? = null + private val scope = CoroutineScope(Dispatchers.IO) + + private var interrupt = false /** * Creates speech service. @@ -54,7 +61,7 @@ class SpeechStreamService( */ fun start(listener: RecognitionListener): Boolean { if (null != recognizerThread) return false - recognizerThread = RecognizerThread(listener) + recognizerThread = scope.launch { recognizerThread(listener) } recognizerThread!!.start() return true } @@ -70,7 +77,7 @@ class SpeechStreamService( */ fun start(listener: RecognitionListener, timeout: Int): Boolean { if (null != recognizerThread) return false - recognizerThread = RecognizerThread(listener, timeout) + recognizerThread = scope.launch { recognizerThread(listener, timeout) } recognizerThread!!.start() return true } @@ -84,64 +91,66 @@ class SpeechStreamService( fun stop(): Boolean { if (null == recognizerThread) return false try { - recognizerThread!!.interrupt() - recognizerThread!!.join() + interrupt = true + runBlocking { + recognizerThread!!.join() + } } catch (e: InterruptedException) { // Restore the interrupted status. Thread.currentThread().interrupt() } recognizerThread = null + interrupt = false return true } - private inner class RecognizerThread @JvmOverloads constructor( - var listener: RecognitionListener, - timeout: Int = Companion.NO_TIMEOUT - ) : Thread() { - private var remainingSamples: Int - private val timeoutSamples: Int + suspend fun recognizerThread( + listener: RecognitionListener, + timeout: Int = NO_TIMEOUT + ) { + var remainingSamples: Int + val timeoutSamples: Int - init { - if (timeout != Companion.NO_TIMEOUT) timeoutSamples = - timeout * sampleRate / 1000 else timeoutSamples = Companion.NO_TIMEOUT - remainingSamples = timeoutSamples - } + if (timeout != NO_TIMEOUT) timeoutSamples = + timeout * sampleRate / 1000 else timeoutSamples = NO_TIMEOUT + remainingSamples = timeoutSamples - override fun run() { - val buffer = ByteArray(bufferSize) - while (!interrupted() - && (timeoutSamples == Companion.NO_TIMEOUT || remainingSamples > 0) - ) { - try { - val nread = inputStream.read(buffer, 0, buffer.size) - if (nread < 0) { - break + val buffer = ByteArray(bufferSize) + while (!interrupt + && (timeoutSamples == NO_TIMEOUT || remainingSamples > 0) + ) { + try { + val nread = withContext(Dispatchers.IO) { + inputStream.read(buffer, 0, buffer.size) + } + if (nread < 0) { + break + } else { + val isSilence: Boolean = recognizer.acceptWaveform(buffer) + if (isSilence) { + val result = recognizer.result + withContext(Dispatchers.Main) { listener.onResult(result) } } else { - val isSilence: Boolean = recognizer.acceptWaveform(buffer) - if (isSilence) { - val result = recognizer.result - mainHandler.post { listener.onResult(result) } - } else { - val partialResult = recognizer.partialResult - mainHandler.post { listener.onPartialResult(partialResult) } - } + val partialResult = recognizer.partialResult + withContext(Dispatchers.Main) { listener.onPartialResult(partialResult) } } - if (timeoutSamples != NO_TIMEOUT) { - remainingSamples -= nread - } - } catch (e: IOException) { - mainHandler.post { listener.onError(e) } } + if (timeoutSamples != NO_TIMEOUT) { + remainingSamples -= nread + } + } catch (e: IOException) { + withContext(Dispatchers.Main) { listener.onError(e) } } + } - // If we met timeout signal that speech ended - if (timeoutSamples != NO_TIMEOUT && remainingSamples <= 0) { - mainHandler.post { listener.onTimeout() } - } else { - val finalResult = recognizer.finalResult - mainHandler.post { listener.onFinalResult(finalResult) } - } + // If we met timeout signal that speech ended + if (timeoutSamples != NO_TIMEOUT && remainingSamples <= 0) { + withContext(Dispatchers.Main) { listener.onTimeout() } + } else { + val finalResult = recognizer.finalResult + withContext(Dispatchers.Main) { listener.onFinalResult(finalResult) } } + } companion object { From 1ac577b22578f09a1ae9f6a15fc074fc479e8508 Mon Sep 17 00:00:00 2001 From: clocks Date: Thu, 20 Jun 2024 00:03:21 -0400 Subject: [PATCH 4/6] Correct dependency conflict between jvm & android --- kotlin/build.gradle.kts | 10 +++++++++- .../kotlin/org/vosk/BatchModel.kt | 0 .../kotlin/org/vosk/BatchRecognizer.kt | 0 .../{jvmMain => commonJVM}/kotlin/org/vosk/LibVosk.kt | 0 .../{jvmMain => commonJVM}/kotlin/org/vosk/Model.kt | 0 .../kotlin/org/vosk/Recognizer.kt | 0 .../kotlin/org/vosk/SpeakerModel.kt | 0 .../kotlin/org/vosk/TextProcessor.kt | 0 .../src/{jvmMain => commonJVM}/kotlin/org/vosk/Vosk.kt | 0 .../kotlin/org/vosk/WaveformExt.kt | 0 .../kotlin/org/vosk/exception/IOException.kt | 0 11 files changed, 9 insertions(+), 1 deletion(-) rename kotlin/src/{jvmMain => commonJVM}/kotlin/org/vosk/BatchModel.kt (100%) rename kotlin/src/{jvmMain => commonJVM}/kotlin/org/vosk/BatchRecognizer.kt (100%) rename kotlin/src/{jvmMain => commonJVM}/kotlin/org/vosk/LibVosk.kt (100%) rename kotlin/src/{jvmMain => commonJVM}/kotlin/org/vosk/Model.kt (100%) rename kotlin/src/{jvmMain => commonJVM}/kotlin/org/vosk/Recognizer.kt (100%) rename kotlin/src/{jvmMain => commonJVM}/kotlin/org/vosk/SpeakerModel.kt (100%) rename kotlin/src/{jvmMain => commonJVM}/kotlin/org/vosk/TextProcessor.kt (100%) rename kotlin/src/{jvmMain => commonJVM}/kotlin/org/vosk/Vosk.kt (100%) rename kotlin/src/{jvmMain => commonJVM}/kotlin/org/vosk/WaveformExt.kt (100%) rename kotlin/src/{jvmMain => commonJVM}/kotlin/org/vosk/exception/IOException.kt (100%) diff --git a/kotlin/build.gradle.kts b/kotlin/build.gradle.kts index 7820ef2b..25968ce8 100644 --- a/kotlin/build.gradle.kts +++ b/kotlin/build.gradle.kts @@ -159,7 +159,15 @@ kotlin { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version") } } + val commonJVM = create("commonJVM") { + dependsOn(commonMain) + dependencies { + compileOnly("net.java.dev.jna:jna:$jna_version") + } + } + val jvmMain by getting { + dependsOn(commonJVM) dependencies { api("net.java.dev.jna:jna:$jna_version") } @@ -169,7 +177,7 @@ kotlin { val nativeMain by getting } val androidMain by getting { - dependsOn(jvmMain) + dependsOn(commonJVM) dependencies { api("net.java.dev.jna:jna:$jna_version@aar") } diff --git a/kotlin/src/jvmMain/kotlin/org/vosk/BatchModel.kt b/kotlin/src/commonJVM/kotlin/org/vosk/BatchModel.kt similarity index 100% rename from kotlin/src/jvmMain/kotlin/org/vosk/BatchModel.kt rename to kotlin/src/commonJVM/kotlin/org/vosk/BatchModel.kt diff --git a/kotlin/src/jvmMain/kotlin/org/vosk/BatchRecognizer.kt b/kotlin/src/commonJVM/kotlin/org/vosk/BatchRecognizer.kt similarity index 100% rename from kotlin/src/jvmMain/kotlin/org/vosk/BatchRecognizer.kt rename to kotlin/src/commonJVM/kotlin/org/vosk/BatchRecognizer.kt diff --git a/kotlin/src/jvmMain/kotlin/org/vosk/LibVosk.kt b/kotlin/src/commonJVM/kotlin/org/vosk/LibVosk.kt similarity index 100% rename from kotlin/src/jvmMain/kotlin/org/vosk/LibVosk.kt rename to kotlin/src/commonJVM/kotlin/org/vosk/LibVosk.kt diff --git a/kotlin/src/jvmMain/kotlin/org/vosk/Model.kt b/kotlin/src/commonJVM/kotlin/org/vosk/Model.kt similarity index 100% rename from kotlin/src/jvmMain/kotlin/org/vosk/Model.kt rename to kotlin/src/commonJVM/kotlin/org/vosk/Model.kt diff --git a/kotlin/src/jvmMain/kotlin/org/vosk/Recognizer.kt b/kotlin/src/commonJVM/kotlin/org/vosk/Recognizer.kt similarity index 100% rename from kotlin/src/jvmMain/kotlin/org/vosk/Recognizer.kt rename to kotlin/src/commonJVM/kotlin/org/vosk/Recognizer.kt diff --git a/kotlin/src/jvmMain/kotlin/org/vosk/SpeakerModel.kt b/kotlin/src/commonJVM/kotlin/org/vosk/SpeakerModel.kt similarity index 100% rename from kotlin/src/jvmMain/kotlin/org/vosk/SpeakerModel.kt rename to kotlin/src/commonJVM/kotlin/org/vosk/SpeakerModel.kt diff --git a/kotlin/src/jvmMain/kotlin/org/vosk/TextProcessor.kt b/kotlin/src/commonJVM/kotlin/org/vosk/TextProcessor.kt similarity index 100% rename from kotlin/src/jvmMain/kotlin/org/vosk/TextProcessor.kt rename to kotlin/src/commonJVM/kotlin/org/vosk/TextProcessor.kt diff --git a/kotlin/src/jvmMain/kotlin/org/vosk/Vosk.kt b/kotlin/src/commonJVM/kotlin/org/vosk/Vosk.kt similarity index 100% rename from kotlin/src/jvmMain/kotlin/org/vosk/Vosk.kt rename to kotlin/src/commonJVM/kotlin/org/vosk/Vosk.kt diff --git a/kotlin/src/jvmMain/kotlin/org/vosk/WaveformExt.kt b/kotlin/src/commonJVM/kotlin/org/vosk/WaveformExt.kt similarity index 100% rename from kotlin/src/jvmMain/kotlin/org/vosk/WaveformExt.kt rename to kotlin/src/commonJVM/kotlin/org/vosk/WaveformExt.kt diff --git a/kotlin/src/jvmMain/kotlin/org/vosk/exception/IOException.kt b/kotlin/src/commonJVM/kotlin/org/vosk/exception/IOException.kt similarity index 100% rename from kotlin/src/jvmMain/kotlin/org/vosk/exception/IOException.kt rename to kotlin/src/commonJVM/kotlin/org/vosk/exception/IOException.kt From 30e017a6224071d385a174c24f22b6906d66620d Mon Sep 17 00:00:00 2001 From: clocks Date: Sat, 6 Jul 2024 10:32:27 -0400 Subject: [PATCH 5/6] jdk17 --- kotlin/.idea/compiler.xml | 2 +- kotlin/.idea/gradle.xml | 8 ++++++-- kotlin/.idea/misc.xml | 3 +-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/kotlin/.idea/compiler.xml b/kotlin/.idea/compiler.xml index fb7f4a8a..b589d56e 100644 --- a/kotlin/.idea/compiler.xml +++ b/kotlin/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/kotlin/.idea/gradle.xml b/kotlin/.idea/gradle.xml index 6cec5693..0f1069f4 100644 --- a/kotlin/.idea/gradle.xml +++ b/kotlin/.idea/gradle.xml @@ -4,14 +4,18 @@ diff --git a/kotlin/.idea/misc.xml b/kotlin/.idea/misc.xml index b1f8730f..8978d23d 100644 --- a/kotlin/.idea/misc.xml +++ b/kotlin/.idea/misc.xml @@ -1,7 +1,6 @@ - - + From 82fe40e64819a94a0dbd91849a8748ed472ae2ec Mon Sep 17 00:00:00 2001 From: clocks Date: Wed, 10 Jul 2024 16:13:51 -0400 Subject: [PATCH 6/6] Attempt to compile vosk in android studio Failure, giving up and moving on. --- .gitmodules | 14 +++++ kotlin/.idea/vcs.xml | 4 ++ kotlin/build.gradle.kts | 25 ++++++++- kotlin/clapack/.gitignore | 1 + kotlin/clapack/build.gradle.kts | 45 +++++++++++++++ kotlin/clapack/consumer-rules.pro | 0 kotlin/clapack/proguard-rules.pro | 21 +++++++ kotlin/clapack/src/main/AndroidManifest.xml | 4 ++ kotlin/clapack/src/main/cpp | 1 + kotlin/kaldi/.gitignore | 1 + kotlin/kaldi/build.gradle.kts | 53 ++++++++++++++++++ kotlin/kaldi/consumer-rules.pro | 0 kotlin/kaldi/proguard-rules.pro | 21 +++++++ kotlin/kaldi/src/main/AndroidManifest.xml | 4 ++ kotlin/kaldi/src/main/cpp | 1 + kotlin/openblas/.gitignore | 1 + kotlin/openblas/build.gradle.kts | 45 +++++++++++++++ kotlin/openblas/consumer-rules.pro | 0 kotlin/openblas/proguard-rules.pro | 21 +++++++ kotlin/openblas/src/main/AndroidManifest.xml | 4 ++ kotlin/openblas/src/main/cpp | 1 + kotlin/openfst/.gitignore | 1 + kotlin/openfst/build.gradle.kts | 58 ++++++++++++++++++++ kotlin/openfst/consumer-rules.pro | 0 kotlin/openfst/proguard-rules.pro | 21 +++++++ kotlin/openfst/src/main/AndroidManifest.xml | 4 ++ kotlin/openfst/src/main/cpp | 1 + kotlin/settings.gradle.kts | 6 +- 28 files changed, 354 insertions(+), 4 deletions(-) create mode 100644 .gitmodules create mode 100644 kotlin/clapack/.gitignore create mode 100644 kotlin/clapack/build.gradle.kts create mode 100644 kotlin/clapack/consumer-rules.pro create mode 100644 kotlin/clapack/proguard-rules.pro create mode 100644 kotlin/clapack/src/main/AndroidManifest.xml create mode 160000 kotlin/clapack/src/main/cpp create mode 100644 kotlin/kaldi/.gitignore create mode 100644 kotlin/kaldi/build.gradle.kts create mode 100644 kotlin/kaldi/consumer-rules.pro create mode 100644 kotlin/kaldi/proguard-rules.pro create mode 100644 kotlin/kaldi/src/main/AndroidManifest.xml create mode 160000 kotlin/kaldi/src/main/cpp create mode 100644 kotlin/openblas/.gitignore create mode 100644 kotlin/openblas/build.gradle.kts create mode 100644 kotlin/openblas/consumer-rules.pro create mode 100644 kotlin/openblas/proguard-rules.pro create mode 100644 kotlin/openblas/src/main/AndroidManifest.xml create mode 160000 kotlin/openblas/src/main/cpp create mode 100644 kotlin/openfst/.gitignore create mode 100644 kotlin/openfst/build.gradle.kts create mode 100644 kotlin/openfst/consumer-rules.pro create mode 100644 kotlin/openfst/proguard-rules.pro create mode 100644 kotlin/openfst/src/main/AndroidManifest.xml create mode 160000 kotlin/openfst/src/main/cpp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..424ca224 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,14 @@ +[submodule "kotlin/openblas/src/main/cpp"] + path = kotlin/openblas/src/main/cpp + url = https://github.com/OpenMathLib/OpenBLAS.git +[submodule "kotlin/clapack/src/main/cpp"] + path = kotlin/clapack/src/main/cpp + url = https://github.com/alphacep/clapack.git + branch = v3.2.1 +[submodule "kotlin/kaldi/src/main/cpp"] + path = kotlin/kaldi/src/main/cpp + url = https://github.com/alphacep/kaldi.git + branch = vosk-android +[submodule "kotlin/openfst/src/main/cpp"] + path = kotlin/openfst/src/main/cpp + url = https://github.com/messiaen/openfst.git \ No newline at end of file diff --git a/kotlin/.idea/vcs.xml b/kotlin/.idea/vcs.xml index 6c0b8635..0d494a5c 100644 --- a/kotlin/.idea/vcs.xml +++ b/kotlin/.idea/vcs.xml @@ -2,5 +2,9 @@ + + + + \ No newline at end of file diff --git a/kotlin/build.gradle.kts b/kotlin/build.gradle.kts index 25968ce8..f13892b7 100644 --- a/kotlin/build.gradle.kts +++ b/kotlin/build.gradle.kts @@ -24,14 +24,17 @@ plugins { `maven-publish` id("org.jetbrains.dokka") version "1.9.20" kotlin("plugin.serialization") version "2.0.0" + id("org.jetbrains.kotlin.android") version "1.9.0" apply false } group = "com.alphacephei" version = "0.3.50" -repositories { - google() - mavenCentral() +allprojects { + repositories { + google() + mavenCentral() + } } val dokkaOutputDir = "$buildDir/dokka" @@ -180,6 +183,9 @@ kotlin { dependsOn(commonJVM) dependencies { api("net.java.dev.jna:jna:$jna_version@aar") + implementation(project(":kaldi")) + implementation(project(":openfst")) + implementation(project(":openblas")) } } val androidUnitTest by getting { @@ -197,6 +203,12 @@ android { defaultConfig { minSdk = 24 targetSdk = 34 + externalNativeBuild { + cmake { + cppFlags("") + arguments("-Wno-dev") + } + } } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 @@ -209,4 +221,11 @@ android { allVariants() } } + + externalNativeBuild { + cmake { + path("../CMakeLists.txt") + version = "3.22.1" + } + } } diff --git a/kotlin/clapack/.gitignore b/kotlin/clapack/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/kotlin/clapack/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/kotlin/clapack/build.gradle.kts b/kotlin/clapack/build.gradle.kts new file mode 100644 index 00000000..311ddefd --- /dev/null +++ b/kotlin/clapack/build.gradle.kts @@ -0,0 +1,45 @@ +plugins { + id("com.android.library") +} + +android { + namespace = "page.doomsdayrs.libs.clapack" + compileSdk = 34 + + defaultConfig { + minSdk = 24 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + externalNativeBuild { + cmake { + arguments( + "-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY", + "-DCMAKE_CROSSCOMPILING=True", + "-DCMAKE_SYSTEM_NAME=Generic", + "-Wno-dev" + ) + } + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + externalNativeBuild { + cmake { + path("src/main/cpp/CMakeLists.txt") + version = "3.22.1" + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} \ No newline at end of file diff --git a/kotlin/clapack/consumer-rules.pro b/kotlin/clapack/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/kotlin/clapack/proguard-rules.pro b/kotlin/clapack/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/kotlin/clapack/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/kotlin/clapack/src/main/AndroidManifest.xml b/kotlin/clapack/src/main/AndroidManifest.xml new file mode 100644 index 00000000..a5918e68 --- /dev/null +++ b/kotlin/clapack/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/kotlin/clapack/src/main/cpp b/kotlin/clapack/src/main/cpp new file mode 160000 index 00000000..1cdd625e --- /dev/null +++ b/kotlin/clapack/src/main/cpp @@ -0,0 +1 @@ +Subproject commit 1cdd625ea47651831db3497c8e065c965bdfe7a3 diff --git a/kotlin/kaldi/.gitignore b/kotlin/kaldi/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/kotlin/kaldi/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/kotlin/kaldi/build.gradle.kts b/kotlin/kaldi/build.gradle.kts new file mode 100644 index 00000000..f20610ea --- /dev/null +++ b/kotlin/kaldi/build.gradle.kts @@ -0,0 +1,53 @@ +plugins { + id("com.android.library") +} + +android { + namespace = "page.doomsdayrs.libs.kaldi" + compileSdk = 34 + + defaultConfig { + minSdk = 24 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + externalNativeBuild { + cmake { + arguments( + "-DMATHLIB=OpenBLAS", + "-DBUILD_SHARED_LIBS=ON", + + "-Wno-dev", + "-DKALDI_BUILD_EXE=OFF", + "-DKALDI_BUILD_TEST=OFF", + ) + cppFlags("-O3", "-DFST_NO_DYNAMIC_LINKING") + } + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + externalNativeBuild { + cmake { + path("src/main/cpp/CMakeLists.txt") + version = "3.22.1" + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} + +dependencies { + compileOnly(project(":openfst")) + compileOnly(project(":openblas")) +} \ No newline at end of file diff --git a/kotlin/kaldi/consumer-rules.pro b/kotlin/kaldi/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/kotlin/kaldi/proguard-rules.pro b/kotlin/kaldi/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/kotlin/kaldi/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/kotlin/kaldi/src/main/AndroidManifest.xml b/kotlin/kaldi/src/main/AndroidManifest.xml new file mode 100644 index 00000000..a5918e68 --- /dev/null +++ b/kotlin/kaldi/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/kotlin/kaldi/src/main/cpp b/kotlin/kaldi/src/main/cpp new file mode 160000 index 00000000..b6920778 --- /dev/null +++ b/kotlin/kaldi/src/main/cpp @@ -0,0 +1 @@ +Subproject commit b692077807b4832cb4e1a8dd0889ed5f0a71b5b8 diff --git a/kotlin/openblas/.gitignore b/kotlin/openblas/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/kotlin/openblas/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/kotlin/openblas/build.gradle.kts b/kotlin/openblas/build.gradle.kts new file mode 100644 index 00000000..fe9c6fa0 --- /dev/null +++ b/kotlin/openblas/build.gradle.kts @@ -0,0 +1,45 @@ +plugins { + id("com.android.library") +} + +android { + namespace = "page.doomsdayrs.libs.openblas" + compileSdk = 34 + + defaultConfig { + minSdk = 24 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + ndk { + abiFilters += "arm64-v8a" + abiFilters += "armeabi-v7a" + // TODO x86 + } + externalNativeBuild { + cmake { + cppFlags("-marm", "-mfpu=vfp", "-mfloat-abi=softfp", "-Wno-dev") + } + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + externalNativeBuild { + cmake { + path("src/main/cpp/CMakeLists.txt") + version = "3.22.1" + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} \ No newline at end of file diff --git a/kotlin/openblas/consumer-rules.pro b/kotlin/openblas/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/kotlin/openblas/proguard-rules.pro b/kotlin/openblas/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/kotlin/openblas/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/kotlin/openblas/src/main/AndroidManifest.xml b/kotlin/openblas/src/main/AndroidManifest.xml new file mode 100644 index 00000000..a5918e68 --- /dev/null +++ b/kotlin/openblas/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/kotlin/openblas/src/main/cpp b/kotlin/openblas/src/main/cpp new file mode 160000 index 00000000..d2b11c47 --- /dev/null +++ b/kotlin/openblas/src/main/cpp @@ -0,0 +1 @@ +Subproject commit d2b11c47774b9216660e76e2fc67e87079f26fa1 diff --git a/kotlin/openfst/.gitignore b/kotlin/openfst/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/kotlin/openfst/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/kotlin/openfst/build.gradle.kts b/kotlin/openfst/build.gradle.kts new file mode 100644 index 00000000..34c40b3d --- /dev/null +++ b/kotlin/openfst/build.gradle.kts @@ -0,0 +1,58 @@ +plugins { + id("com.android.library") +} + +android { + namespace = "page.doomsdayrs.libs.openfst" + compileSdk = 34 + + defaultConfig { + minSdk = 24 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + externalNativeBuild { + cmake { + cppFlags("-O3", "-DFST_NO_DYNAMIC_LINKING") + arguments( + "-DBUILD_SHARED_LIBS=ON", + "-DHAVE_BIN=OFF", + "-DHAVE_LOOKAHEAD=ON", + "-DHAVE_NGRAM=ON", + + "-DHAVE_COMPACT=OFF", + "-DHAVE_CONST=OFF", + "-DHAVE_FAR=OFF", + "-DHAVE_GRM=OFF", + "-DHAVE_PDT=OFF", + "-DHAVE_MPDT=OFF", + "-DHAVE_LINEAR=OFF", + "-DHAVE_LOOKAHEAD=OFF", + "-DHAVE_SPECIAL=OFF", + + "-Wno-dev" + ) + } + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + externalNativeBuild { + cmake { + path("src/main/cpp/CMakeLists.txt") + version = "3.22.1" + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} \ No newline at end of file diff --git a/kotlin/openfst/consumer-rules.pro b/kotlin/openfst/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/kotlin/openfst/proguard-rules.pro b/kotlin/openfst/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/kotlin/openfst/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/kotlin/openfst/src/main/AndroidManifest.xml b/kotlin/openfst/src/main/AndroidManifest.xml new file mode 100644 index 00000000..a5918e68 --- /dev/null +++ b/kotlin/openfst/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/kotlin/openfst/src/main/cpp b/kotlin/openfst/src/main/cpp new file mode 160000 index 00000000..7ffa870f --- /dev/null +++ b/kotlin/openfst/src/main/cpp @@ -0,0 +1 @@ +Subproject commit 7ffa870fbe8a17ba5b7b63ac240f23af2f6b39fb diff --git a/kotlin/settings.gradle.kts b/kotlin/settings.gradle.kts index 4aba20b2..7bc9e631 100644 --- a/kotlin/settings.gradle.kts +++ b/kotlin/settings.gradle.kts @@ -28,4 +28,8 @@ pluginManagement { } } } -rootProject.name = "vosk-api-kotlin" \ No newline at end of file +rootProject.name = "vosk-api-kotlin" +include(":kaldi") +include(":openblas") +include(":clapack") +include(":openfst")