Skip to content

Commit 49b529b

Browse files
authored
whisper.android : add support for loading directly from asset in C (#415)
1 parent 8088a97 commit 49b529b

File tree

4 files changed

+62
-3
lines changed

4 files changed

+62
-3
lines changed

examples/whisper.android/app/src/main/java/com/whispercppdemo/ui/main/MainScreenViewModel.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ class MainScreenViewModel(private val application: Application) : ViewModel() {
7373
printMessage("Loading model...\n")
7474
val models = application.assets.list("models/")
7575
if (models != null) {
76-
val inputstream = application.assets.open("models/" + models[0])
77-
whisperContext = WhisperContext.createContextFromInputStream(inputstream)
76+
whisperContext = WhisperContext.createContextFromAsset(application.assets, "models/" + models[0])
7877
printMessage("Loaded model ${models[0]}.\n")
7978
}
8079

examples/whisper.android/app/src/main/java/com/whispercppdemo/whisper/LibWhisper.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.whispercppdemo.whisper
22

3+
import android.content.res.AssetManager
34
import android.os.Build
45
import android.util.Log
56
import kotlinx.coroutines.*
@@ -56,6 +57,15 @@ class WhisperContext private constructor(private var ptr: Long) {
5657
}
5758
return WhisperContext(ptr)
5859
}
60+
61+
fun createContextFromAsset(assetManager: AssetManager, assetPath: String): WhisperContext {
62+
val ptr = WhisperLib.initContextFromAsset(assetManager, assetPath)
63+
64+
if (ptr == 0L) {
65+
throw java.lang.RuntimeException("Couldn't create context from asset $assetPath")
66+
}
67+
return WhisperContext(ptr)
68+
}
5969
}
6070
}
6171

@@ -87,6 +97,7 @@ private class WhisperLib {
8797

8898
// JNI methods
8999
external fun initContextFromInputStream(inputStream: InputStream): Long
100+
external fun initContextFromAsset(assetManager: AssetManager, assetPath: String): Long
90101
external fun initContext(modelPath: String): Long
91102
external fun freeContext(contextPtr: Long)
92103
external fun fullTranscribe(contextPtr: Long, audioData: FloatArray)

examples/whisper.android/app/src/main/jni/whisper/Whisper.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
WHISPER_LIB_DIR := $(LOCAL_PATH)/../../../../../../../
2-
LOCAL_LDLIBS := -llog
2+
LOCAL_LDLIBS := -landroid -llog
33

44
# Make the final output library smaller by only keeping the symbols referenced from the app.
55
ifneq ($(APP_OPTIM),debug)

examples/whisper.android/app/src/main/jni/whisper/jni.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include <jni.h>
2+
#include <android/asset_manager.h>
3+
#include <android/asset_manager_jni.h>
24
#include <android/log.h>
35
#include <stdlib.h>
46
#include <sys/sysinfo.h>
@@ -9,6 +11,7 @@
911
#define TAG "JNI"
1012

1113
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
14+
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
1215

1316
static inline int min(int a, int b) {
1417
return (a < b) ? a : b;
@@ -91,6 +94,52 @@ Java_com_whispercppdemo_whisper_WhisperLib_00024Companion_initContextFromInputSt
9194
return (jlong) context;
9295
}
9396

97+
static size_t asset_read(void *ctx, void *output, size_t read_size) {
98+
return AAsset_read((AAsset *) ctx, output, read_size);
99+
}
100+
101+
static bool asset_is_eof(void *ctx) {
102+
return AAsset_getRemainingLength64((AAsset *) ctx) <= 0;
103+
}
104+
105+
static void asset_close(void *ctx) {
106+
AAsset_close((AAsset *) ctx);
107+
}
108+
109+
static struct whisper_context *whisper_init_from_asset(
110+
JNIEnv *env,
111+
jobject assetManager,
112+
const char *asset_path
113+
) {
114+
LOGI("Loading model from asset '%s'\n", asset_path);
115+
AAssetManager *asset_manager = AAssetManager_fromJava(env, assetManager);
116+
AAsset *asset = AAssetManager_open(asset_manager, asset_path, AASSET_MODE_STREAMING);
117+
if (!asset) {
118+
LOGW("Failed to open '%s'\n", asset_path);
119+
return NULL;
120+
}
121+
122+
whisper_model_loader loader = {
123+
.context = asset,
124+
.read = &asset_read,
125+
.eof = &asset_is_eof,
126+
.close = &asset_close
127+
};
128+
129+
return whisper_init(&loader);
130+
}
131+
132+
JNIEXPORT jlong JNICALL
133+
Java_com_whispercppdemo_whisper_WhisperLib_00024Companion_initContextFromAsset(
134+
JNIEnv *env, jobject thiz, jobject assetManager, jstring asset_path_str) {
135+
UNUSED(thiz);
136+
struct whisper_context *context = NULL;
137+
const char *asset_path_chars = (*env)->GetStringUTFChars(env, asset_path_str, NULL);
138+
context = whisper_init_from_asset(env, assetManager, asset_path_chars);
139+
(*env)->ReleaseStringUTFChars(env, asset_path_str, asset_path_chars);
140+
return (jlong) context;
141+
}
142+
94143
JNIEXPORT jlong JNICALL
95144
Java_com_whispercppdemo_whisper_WhisperLib_00024Companion_initContext(
96145
JNIEnv *env, jobject thiz, jstring model_path_str) {

0 commit comments

Comments
 (0)