From 2c14bba00fe4d5ff84a82731091a3845cf86f090 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 03:36:33 +0000 Subject: [PATCH 1/7] Initial plan From 2a13a989daad029bbf5d29825dba2c8e39cc0716 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 03:40:47 +0000 Subject: [PATCH 2/7] Update AsrModule API: remove transcribeBlocking, make transcribe synchronous Co-authored-by: kirklandsign <107070759+kirklandsign@users.noreply.github.com> --- .../executorch/extension/asr/AsrModule.kt | 84 ++++++++------ .../executorch/extension/asr/AsrModuleTest.kt | 104 ++++++++++++++++++ 2 files changed, 154 insertions(+), 34 deletions(-) create mode 100644 extension/android/executorch_android/src/test/java/org/pytorch/executorch/extension/asr/AsrModuleTest.kt diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt index b875fc05353..7349fa0d31a 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt @@ -20,6 +20,32 @@ import org.pytorch.executorch.annotations.Experimental * The module loads a WAV file, optionally preprocesses it using a preprocessor module (e.g., for * mel-spectrogram extraction), and then runs the ASR model to generate transcriptions. * + * The `transcribe()` method is synchronous and returns the complete transcription as a String. + * If you need asynchronous behavior, you can implement it using threading or coroutines: + * + * Example using Kotlin Coroutines: + * ```kotlin + * launch(Dispatchers.IO) { + * val transcription = asrModule.transcribe(wavPath) + * withContext(Dispatchers.Main) { + * // Update UI with transcription + * } + * } + * ``` + * + * Example using Java threads: + * ```java + * ExecutorService executor = Executors.newSingleThreadExecutor(); + * executor.submit(() -> { + * try { + * String transcription = asrModule.transcribe(wavPath); + * // Handle the result + * } catch (RuntimeException e) { + * // Handle transcription errors + * } + * }); + * ``` + * * Warning: These APIs are experimental and subject to change without notice * * @param modelPath Path to the ExecuTorch model file (.pte). The model must expose exactly two @@ -127,69 +153,59 @@ class AsrModule( /** * Transcribe audio from a WAV file with default configuration. * + * This is a synchronous blocking call that returns the complete transcription. + * * @param wavPath Path to the WAV audio file - * @param callback Callback to receive tokens, can be null - * @return 0 on success, error code otherwise + * @param config Configuration for transcription + * @return The complete transcribed text * @throws IllegalStateException if the module has been destroyed + * @throws RuntimeException if transcription fails (non-zero result code) */ - fun transcribe(wavPath: String, callback: AsrCallback? = null): Int = - transcribe(wavPath, AsrTranscribeConfig(), callback) + @JvmOverloads + fun transcribe( + wavPath: String, + config: AsrTranscribeConfig = AsrTranscribeConfig(), + ): String = + transcribe(wavPath, config, null) /** * Transcribe audio from a WAV file with custom configuration. * + * This is a synchronous blocking call that returns the complete transcription. + * * @param wavPath Path to the WAV audio file * @param config Configuration for transcription - * @param callback Callback to receive tokens, can be null - * @return 0 on success, error code otherwise + * @param callback Optional callback to receive tokens as they are generated (can be null) + * @return The complete transcribed text * @throws IllegalStateException if the module has been destroyed + * @throws RuntimeException if transcription fails (non-zero result code) */ fun transcribe( wavPath: String, config: AsrTranscribeConfig, callback: AsrCallback? = null, - ): Int { + ): String { val handle = nativeHandle.get() check(handle != 0L) { "AsrModule has been destroyed" } val wavFile = File(wavPath) require(wavFile.canRead() && wavFile.isFile) { "Cannot read WAV file: $wavPath" } - return nativeTranscribe( - handle, - wavPath, - config.maxNewTokens, - config.temperature, - config.decoderStartTokenId, - callback, - ) - } - /** - * Transcribe audio from a WAV file and return the full transcription. - * - * This is a blocking call that collects all tokens and returns the complete transcription. - * - * @param wavPath Path to the WAV audio file - * @param config Configuration for transcription - * @return The transcribed text - * @throws RuntimeException if transcription fails - */ - @JvmOverloads - fun transcribeBlocking( - wavPath: String, - config: AsrTranscribeConfig = AsrTranscribeConfig(), - ): String { val result = StringBuilder() val status = - transcribe( + nativeTranscribe( + handle, wavPath, - config, + config.maxNewTokens, + config.temperature, + config.decoderStartTokenId, object : AsrCallback { override fun onToken(token: String) { result.append(token) + callback?.onToken(token) } override fun onComplete(transcription: String) { - // Tokens already collected + callback?.onComplete(transcription) } }, ) diff --git a/extension/android/executorch_android/src/test/java/org/pytorch/executorch/extension/asr/AsrModuleTest.kt b/extension/android/executorch_android/src/test/java/org/pytorch/executorch/extension/asr/AsrModuleTest.kt new file mode 100644 index 00000000000..ec9a10c1210 --- /dev/null +++ b/extension/android/executorch_android/src/test/java/org/pytorch/executorch/extension/asr/AsrModuleTest.kt @@ -0,0 +1,104 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +package org.pytorch.executorch.extension.asr + +import org.junit.Assert.assertThrows +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +/** + * Unit tests for [AsrModule]. + * + * Note: These are behavioral tests that verify the API contract. Full integration tests + * with actual models should be done in androidTest. + */ +@RunWith(JUnit4::class) +class AsrModuleTest { + + @Test + fun testTranscribeWithInvalidModelPathThrowsException() { + // Verify that AsrModule constructor throws when model file doesn't exist + assertThrows(IllegalArgumentException::class.java) { + AsrModule( + modelPath = "/nonexistent/model.pte", + tokenizerPath = "/tmp", + ) + } + } + + @Test + fun testTranscribeWithInvalidTokenizerPathThrowsException() { + // Create a temporary model file + val tempModelFile = java.io.File.createTempFile("model", ".pte") + try { + tempModelFile.writeText("dummy content") + + // Verify that AsrModule constructor throws when tokenizer doesn't exist + assertThrows(IllegalArgumentException::class.java) { + AsrModule( + modelPath = tempModelFile.absolutePath, + tokenizerPath = "/nonexistent/tokenizer", + ) + } + } finally { + tempModelFile.delete() + } + } + + @Test + fun testAsrTranscribeConfigValidation() { + // Test that maxNewTokens must be positive + assertThrows(IllegalArgumentException::class.java) { + AsrTranscribeConfig(maxNewTokens = 0) + } + + assertThrows(IllegalArgumentException::class.java) { + AsrTranscribeConfig(maxNewTokens = -1) + } + + // Test that temperature must be non-negative + assertThrows(IllegalArgumentException::class.java) { + AsrTranscribeConfig(temperature = -0.1f) + } + } + + @Test + fun testAsrTranscribeConfigBuilder() { + // Test builder pattern for Java interoperability + val config = AsrTranscribeConfig.Builder() + .setMaxNewTokens(256) + .setTemperature(0.5f) + .setDecoderStartTokenId(123) + .build() + + assertTrue(config.maxNewTokens == 256L) + assertTrue(config.temperature == 0.5f) + assertTrue(config.decoderStartTokenId == 123L) + } + + @Test + fun testAsrTranscribeConfigBuilderValidation() { + // Test that builder validates maxNewTokens + assertThrows(IllegalArgumentException::class.java) { + AsrTranscribeConfig.Builder() + .setMaxNewTokens(0) + .build() + } + + // Test that builder validates temperature + assertThrows(IllegalArgumentException::class.java) { + AsrTranscribeConfig.Builder() + .setTemperature(-1.0f) + .build() + } + } +} + From e8f2705847f54b86f178fd9e6830077c85d94af9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 03:43:55 +0000 Subject: [PATCH 3/7] Simplify API: remove tests, async docs, make config nullable Co-authored-by: kirklandsign <107070759+kirklandsign@users.noreply.github.com> --- .../executorch/extension/asr/AsrModule.kt | 58 ++-------- .../executorch/extension/asr/AsrModuleTest.kt | 104 ------------------ 2 files changed, 8 insertions(+), 154 deletions(-) delete mode 100644 extension/android/executorch_android/src/test/java/org/pytorch/executorch/extension/asr/AsrModuleTest.kt diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt index 7349fa0d31a..8b1726e4d81 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt @@ -20,32 +20,6 @@ import org.pytorch.executorch.annotations.Experimental * The module loads a WAV file, optionally preprocesses it using a preprocessor module (e.g., for * mel-spectrogram extraction), and then runs the ASR model to generate transcriptions. * - * The `transcribe()` method is synchronous and returns the complete transcription as a String. - * If you need asynchronous behavior, you can implement it using threading or coroutines: - * - * Example using Kotlin Coroutines: - * ```kotlin - * launch(Dispatchers.IO) { - * val transcription = asrModule.transcribe(wavPath) - * withContext(Dispatchers.Main) { - * // Update UI with transcription - * } - * } - * ``` - * - * Example using Java threads: - * ```java - * ExecutorService executor = Executors.newSingleThreadExecutor(); - * executor.submit(() -> { - * try { - * String transcription = asrModule.transcribe(wavPath); - * // Handle the result - * } catch (RuntimeException e) { - * // Handle transcription errors - * } - * }); - * ``` - * * Warning: These APIs are experimental and subject to change without notice * * @param modelPath Path to the ExecuTorch model file (.pte). The model must expose exactly two @@ -151,38 +125,21 @@ class AsrModule( } /** - * Transcribe audio from a WAV file with default configuration. + * Transcribe audio from a WAV file. * * This is a synchronous blocking call that returns the complete transcription. * * @param wavPath Path to the WAV audio file - * @param config Configuration for transcription - * @return The complete transcribed text - * @throws IllegalStateException if the module has been destroyed - * @throws RuntimeException if transcription fails (non-zero result code) - */ - @JvmOverloads - fun transcribe( - wavPath: String, - config: AsrTranscribeConfig = AsrTranscribeConfig(), - ): String = - transcribe(wavPath, config, null) - - /** - * Transcribe audio from a WAV file with custom configuration. - * - * This is a synchronous blocking call that returns the complete transcription. - * - * @param wavPath Path to the WAV audio file - * @param config Configuration for transcription + * @param config Configuration for transcription (null uses default configuration) * @param callback Optional callback to receive tokens as they are generated (can be null) * @return The complete transcribed text * @throws IllegalStateException if the module has been destroyed * @throws RuntimeException if transcription fails (non-zero result code) */ + @JvmOverloads fun transcribe( wavPath: String, - config: AsrTranscribeConfig, + config: AsrTranscribeConfig? = null, callback: AsrCallback? = null, ): String { val handle = nativeHandle.get() @@ -190,14 +147,15 @@ class AsrModule( val wavFile = File(wavPath) require(wavFile.canRead() && wavFile.isFile) { "Cannot read WAV file: $wavPath" } + val effectiveConfig = config ?: AsrTranscribeConfig() val result = StringBuilder() val status = nativeTranscribe( handle, wavPath, - config.maxNewTokens, - config.temperature, - config.decoderStartTokenId, + effectiveConfig.maxNewTokens, + effectiveConfig.temperature, + effectiveConfig.decoderStartTokenId, object : AsrCallback { override fun onToken(token: String) { result.append(token) diff --git a/extension/android/executorch_android/src/test/java/org/pytorch/executorch/extension/asr/AsrModuleTest.kt b/extension/android/executorch_android/src/test/java/org/pytorch/executorch/extension/asr/AsrModuleTest.kt deleted file mode 100644 index ec9a10c1210..00000000000 --- a/extension/android/executorch_android/src/test/java/org/pytorch/executorch/extension/asr/AsrModuleTest.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -package org.pytorch.executorch.extension.asr - -import org.junit.Assert.assertThrows -import org.junit.Assert.assertTrue -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 - -/** - * Unit tests for [AsrModule]. - * - * Note: These are behavioral tests that verify the API contract. Full integration tests - * with actual models should be done in androidTest. - */ -@RunWith(JUnit4::class) -class AsrModuleTest { - - @Test - fun testTranscribeWithInvalidModelPathThrowsException() { - // Verify that AsrModule constructor throws when model file doesn't exist - assertThrows(IllegalArgumentException::class.java) { - AsrModule( - modelPath = "/nonexistent/model.pte", - tokenizerPath = "/tmp", - ) - } - } - - @Test - fun testTranscribeWithInvalidTokenizerPathThrowsException() { - // Create a temporary model file - val tempModelFile = java.io.File.createTempFile("model", ".pte") - try { - tempModelFile.writeText("dummy content") - - // Verify that AsrModule constructor throws when tokenizer doesn't exist - assertThrows(IllegalArgumentException::class.java) { - AsrModule( - modelPath = tempModelFile.absolutePath, - tokenizerPath = "/nonexistent/tokenizer", - ) - } - } finally { - tempModelFile.delete() - } - } - - @Test - fun testAsrTranscribeConfigValidation() { - // Test that maxNewTokens must be positive - assertThrows(IllegalArgumentException::class.java) { - AsrTranscribeConfig(maxNewTokens = 0) - } - - assertThrows(IllegalArgumentException::class.java) { - AsrTranscribeConfig(maxNewTokens = -1) - } - - // Test that temperature must be non-negative - assertThrows(IllegalArgumentException::class.java) { - AsrTranscribeConfig(temperature = -0.1f) - } - } - - @Test - fun testAsrTranscribeConfigBuilder() { - // Test builder pattern for Java interoperability - val config = AsrTranscribeConfig.Builder() - .setMaxNewTokens(256) - .setTemperature(0.5f) - .setDecoderStartTokenId(123) - .build() - - assertTrue(config.maxNewTokens == 256L) - assertTrue(config.temperature == 0.5f) - assertTrue(config.decoderStartTokenId == 123L) - } - - @Test - fun testAsrTranscribeConfigBuilderValidation() { - // Test that builder validates maxNewTokens - assertThrows(IllegalArgumentException::class.java) { - AsrTranscribeConfig.Builder() - .setMaxNewTokens(0) - .build() - } - - // Test that builder validates temperature - assertThrows(IllegalArgumentException::class.java) { - AsrTranscribeConfig.Builder() - .setTemperature(-1.0f) - .build() - } - } -} - From 29b9b35695d25ab5500ce34e05a46f8d9904dd40 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 03:53:04 +0000 Subject: [PATCH 4/7] Remove onComplete callback - function return indicates completion Co-authored-by: kirklandsign <107070759+kirklandsign@users.noreply.github.com> --- .../executorch/extension/asr/AsrCallback.kt | 12 +++--------- .../executorch/extension/asr/AsrModule.kt | 4 ---- extension/android/jni/jni_layer_asr.cpp | 17 ----------------- 3 files changed, 3 insertions(+), 30 deletions(-) diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrCallback.kt b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrCallback.kt index e2012d84c26..50b51caa0e4 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrCallback.kt +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrCallback.kt @@ -12,7 +12,7 @@ import org.pytorch.executorch.annotations.Experimental /** * Callback interface for ASR (Automatic Speech Recognition) module. Users can implement this - * interface to receive the transcribed tokens and completion notification. + * interface to receive the transcribed tokens as they are generated. * * Warning: These APIs are experimental and subject to change without notice */ @@ -20,16 +20,10 @@ import org.pytorch.executorch.annotations.Experimental interface AsrCallback { /** * Called when a new token is available from JNI. Users will keep getting onToken() invocations - * until transcription finishes. + * until transcription finishes (when the transcribe method returns). * * @param token The decoded text token */ fun onToken(token: String) - - /** - * Called when transcription is complete. - * - * @param transcription The complete transcription (may be empty if tokens were streamed) - */ - fun onComplete(transcription: String) {} } + diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt index 8b1726e4d81..4179e02828d 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt @@ -161,10 +161,6 @@ class AsrModule( result.append(token) callback?.onToken(token) } - - override fun onComplete(transcription: String) { - callback?.onComplete(transcription) - } }, ) diff --git a/extension/android/jni/jni_layer_asr.cpp b/extension/android/jni/jni_layer_asr.cpp index 50a3656b437..2eb5f0a7968 100644 --- a/extension/android/jni/jni_layer_asr.cpp +++ b/extension/android/jni/jni_layer_asr.cpp @@ -80,7 +80,6 @@ bool utf8_check_validity(const char* str, size_t length) { struct AsrCallbackCache { jclass callbackClass = nullptr; jmethodID onTokenMethod = nullptr; - jmethodID onCompleteMethod = nullptr; }; AsrCallbackCache callbackCache; @@ -97,10 +96,6 @@ void initCallbackCache(JNIEnv* env) { (jclass)localEnv->NewGlobalRef(localClass); callbackCache.onTokenMethod = localEnv->GetMethodID( callbackCache.callbackClass, "onToken", "(Ljava/lang/String;)V"); - callbackCache.onCompleteMethod = localEnv->GetMethodID( - callbackCache.callbackClass, - "onComplete", - "(Ljava/lang/String;)V"); localEnv->DeleteLocalRef(localClass); } }, @@ -411,18 +406,6 @@ Java_org_pytorch_executorch_extension_asr_AsrModule_nativeTranscribe( auto result = handle->runner->transcribe(featuresTensor, config, tokenCallback); - // Call onComplete if callback provided - if (scopedCallback) { - jstring emptyStr = env->NewStringUTF(""); - env->CallVoidMethod( - scopedCallback.get(), callbackCache.onCompleteMethod, emptyStr); - if (env->ExceptionCheck()) { - ET_LOG(Error, "Exception occurred in AsrCallback.onComplete"); - env->ExceptionClear(); - } - env->DeleteLocalRef(emptyStr); - } - if (!result.ok()) { return static_cast(result.error()); } From 8e7d2abd77c262aa8bef05a489f0b72adb2c623a Mon Sep 17 00:00:00 2001 From: Hansong Zhang <107070759+kirklandsign@users.noreply.github.com> Date: Thu, 29 Jan 2026 19:54:11 -0800 Subject: [PATCH 5/7] Update documentation for transcribe method --- .../main/java/org/pytorch/executorch/extension/asr/AsrModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt index 4179e02828d..301147c2d7f 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt @@ -127,7 +127,7 @@ class AsrModule( /** * Transcribe audio from a WAV file. * - * This is a synchronous blocking call that returns the complete transcription. + * This is a blocking call that returns the complete transcription. * * @param wavPath Path to the WAV audio file * @param config Configuration for transcription (null uses default configuration) From 7e1bfeac7a2f196ced3e8fdfe9bd480fc9b8d590 Mon Sep 17 00:00:00 2001 From: hsz Date: Thu, 29 Jan 2026 20:16:37 -0800 Subject: [PATCH 6/7] Update --- .../pytorch/executorch/extension/asr/AsrModule.kt | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt index 301147c2d7f..7cde116d506 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt @@ -88,7 +88,7 @@ class AsrModule( ): Int } - /** Check if the native handle is valid. */ + /** Check if the native handle is valid (not yet closed). */ val isValid: Boolean get() = nativeHandle.get() != 0L @@ -99,19 +99,16 @@ class AsrModule( return handle != 0L && nativeIsLoaded(handle) } - /** Releases native resources. Call this when done with the module. */ - fun destroy() { + /** + * Releases native resources. Call this when done with the module. + */ + override fun close() { val handle = nativeHandle.getAndSet(0L) if (handle != 0L) { nativeDestroy(handle) } } - /** Closeable implementation for use with use {} blocks. */ - override fun close() { - destroy() - } - /** * Force loading the module. Otherwise the model is loaded during first transcribe() call. * From e9b55adb1d4e89a1092c712c41481728d48cf425 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Fri, 30 Jan 2026 11:27:31 -0800 Subject: [PATCH 7/7] Lint --- .../java/org/pytorch/executorch/extension/asr/AsrCallback.kt | 1 - .../java/org/pytorch/executorch/extension/asr/AsrModule.kt | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrCallback.kt b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrCallback.kt index 50b51caa0e4..51a220167c0 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrCallback.kt +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrCallback.kt @@ -26,4 +26,3 @@ interface AsrCallback { */ fun onToken(token: String) } - diff --git a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt index 7cde116d506..987cb3ec3be 100644 --- a/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt +++ b/extension/android/executorch_android/src/main/java/org/pytorch/executorch/extension/asr/AsrModule.kt @@ -99,9 +99,7 @@ class AsrModule( return handle != 0L && nativeIsLoaded(handle) } - /** - * Releases native resources. Call this when done with the module. - */ + /** Releases native resources. Call this when done with the module. */ override fun close() { val handle = nativeHandle.getAndSet(0L) if (handle != 0L) {