react-native-sherpa-onnx 0.3.5 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/android/prebuilt-download.gradle +1 -1
- package/android/prebuilt-versions.gradle +1 -1
- package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.cpp +306 -6
- package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.h +33 -4
- package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-jni.cpp +266 -7
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxArchiveHelper.kt +100 -0
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxAssetHelper.kt +51 -6
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +60 -0
- package/ios/SherpaOnnx.mm +54 -1
- package/ios/archive/sherpa-onnx-archive-helper.h +7 -0
- package/ios/archive/sherpa-onnx-archive-helper.mm +18 -0
- package/lib/module/NativeSherpaOnnx.js.map +1 -1
- package/lib/module/download/extractTarZst.js +52 -0
- package/lib/module/download/extractTarZst.js.map +1 -0
- package/lib/module/download/index.js +1 -0
- package/lib/module/download/index.js.map +1 -1
- package/lib/module/extraction/index.js +191 -0
- package/lib/module/extraction/index.js.map +1 -0
- package/lib/module/extraction/types.js +2 -0
- package/lib/module/extraction/types.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeSherpaOnnx.d.ts +39 -0
- package/lib/typescript/src/NativeSherpaOnnx.d.ts.map +1 -1
- package/lib/typescript/src/download/extractTarZst.d.ts +14 -0
- package/lib/typescript/src/download/extractTarZst.d.ts.map +1 -0
- package/lib/typescript/src/download/index.d.ts +2 -0
- package/lib/typescript/src/download/index.d.ts.map +1 -1
- package/lib/typescript/src/extraction/index.d.ts +50 -0
- package/lib/typescript/src/extraction/index.d.ts.map +1 -0
- package/lib/typescript/src/extraction/types.d.ts +60 -0
- package/lib/typescript/src/extraction/types.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/NativeSherpaOnnx.ts +56 -0
- package/src/download/extractTarZst.ts +77 -0
- package/src/download/index.ts +2 -0
- package/src/extraction/index.ts +273 -0
- package/src/extraction/types.ts +63 -0
- package/src/index.tsx +1 -0
- package/third_party/libarchive_prebuilt/ANDROID_RELEASE_TAG +1 -1
- package/third_party/libarchive_prebuilt/IOS_RELEASE_TAG +1 -1
|
@@ -49,11 +49,9 @@ Java_com_sherpaonnx_SherpaOnnxArchiveHelper_nativeExtractTarBz2(
|
|
|
49
49
|
j_progress_callback_global = env->NewGlobalRef(j_progress_callback);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
// Get Promise.resolve
|
|
52
|
+
// Get Promise.resolve method
|
|
53
53
|
jclass promise_class = env->GetObjectClass(j_promise);
|
|
54
54
|
jmethodID resolve_method = env->GetMethodID(promise_class, "resolve", "(Ljava/lang/Object;)V");
|
|
55
|
-
jmethodID reject_method = env->GetMethodID(promise_class, "reject",
|
|
56
|
-
"(Ljava/lang/String;Ljava/lang/String;)V");
|
|
57
55
|
|
|
58
56
|
// Get WritableMap from Arguments
|
|
59
57
|
jclass arguments_class = env->FindClass("com/facebook/react/bridge/Arguments");
|
|
@@ -123,15 +121,12 @@ Java_com_sherpaonnx_SherpaOnnxArchiveHelper_nativeExtractTarBz2(
|
|
|
123
121
|
env->CallVoidMethod(result_map, put_string_method,
|
|
124
122
|
env->NewStringUTF("sha256"), env->NewStringUTF(sha256.c_str()));
|
|
125
123
|
}
|
|
126
|
-
env->CallVoidMethod(j_promise, resolve_method, result_map);
|
|
127
124
|
} else {
|
|
128
125
|
__android_log_print(ANDROID_LOG_WARN, "SherpaOnnxNative", "[ARCHIVE_ERROR] %s", error_msg.c_str());
|
|
129
126
|
env->CallVoidMethod(result_map, put_string_method,
|
|
130
127
|
env->NewStringUTF("reason"), env->NewStringUTF(error_msg.c_str()));
|
|
131
|
-
env->CallVoidMethod(j_promise, reject_method,
|
|
132
|
-
env->NewStringUTF("ARCHIVE_ERROR"),
|
|
133
|
-
env->NewStringUTF(error_msg.c_str()));
|
|
134
128
|
}
|
|
129
|
+
env->CallVoidMethod(j_promise, resolve_method, result_map);
|
|
135
130
|
|
|
136
131
|
// Clean up global reference
|
|
137
132
|
if (j_progress_callback_global != nullptr) {
|
|
@@ -144,6 +139,270 @@ Java_com_sherpaonnx_SherpaOnnxArchiveHelper_nativeExtractTarBz2(
|
|
|
144
139
|
env->DeleteLocalRef(writeable_map_class);
|
|
145
140
|
}
|
|
146
141
|
|
|
142
|
+
extern "C" JNIEXPORT void JNICALL
|
|
143
|
+
Java_com_sherpaonnx_SherpaOnnxArchiveHelper_nativeExtractTarZst(
|
|
144
|
+
JNIEnv* env,
|
|
145
|
+
jobject /* jthis */,
|
|
146
|
+
jstring j_source_path,
|
|
147
|
+
jstring j_target_path,
|
|
148
|
+
jboolean j_force,
|
|
149
|
+
jobject j_progress_callback,
|
|
150
|
+
jobject j_promise) {
|
|
151
|
+
const char* source_path = env->GetStringUTFChars(j_source_path, nullptr);
|
|
152
|
+
const char* target_path = env->GetStringUTFChars(j_target_path, nullptr);
|
|
153
|
+
std::string source_str(source_path);
|
|
154
|
+
std::string target_str(target_path);
|
|
155
|
+
env->ReleaseStringUTFChars(j_source_path, source_path);
|
|
156
|
+
env->ReleaseStringUTFChars(j_target_path, target_path);
|
|
157
|
+
|
|
158
|
+
jmethodID on_progress_method = nullptr;
|
|
159
|
+
jobject j_progress_callback_global = nullptr;
|
|
160
|
+
if (j_progress_callback != nullptr) {
|
|
161
|
+
jclass callback_class = env->GetObjectClass(j_progress_callback);
|
|
162
|
+
on_progress_method = env->GetMethodID(callback_class, "invoke", "(JJD)V");
|
|
163
|
+
env->DeleteLocalRef(callback_class);
|
|
164
|
+
j_progress_callback_global = env->NewGlobalRef(j_progress_callback);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
jclass promise_class = env->GetObjectClass(j_promise);
|
|
168
|
+
jmethodID resolve_method = env->GetMethodID(promise_class, "resolve", "(Ljava/lang/Object;)V");
|
|
169
|
+
|
|
170
|
+
jclass arguments_class = env->FindClass("com/facebook/react/bridge/Arguments");
|
|
171
|
+
jmethodID create_map_method = env->GetStaticMethodID(
|
|
172
|
+
arguments_class, "createMap", "()Lcom/facebook/react/bridge/WritableMap;");
|
|
173
|
+
jobject result_map = env->CallStaticObjectMethod(arguments_class, create_map_method);
|
|
174
|
+
|
|
175
|
+
jclass writeable_map_class = env->FindClass("com/facebook/react/bridge/WritableMap");
|
|
176
|
+
jmethodID put_boolean_method = env->GetMethodID(
|
|
177
|
+
writeable_map_class, "putBoolean", "(Ljava/lang/String;Z)V");
|
|
178
|
+
jmethodID put_string_method = env->GetMethodID(
|
|
179
|
+
writeable_map_class, "putString", "(Ljava/lang/String;Ljava/lang/String;)V");
|
|
180
|
+
|
|
181
|
+
auto on_progress = [j_progress_callback_global, on_progress_method](
|
|
182
|
+
long long bytes_extracted, long long total_bytes, double percent) {
|
|
183
|
+
if (j_progress_callback_global != nullptr && on_progress_method != nullptr) {
|
|
184
|
+
JNIEnv* callback_env = nullptr;
|
|
185
|
+
bool should_detach = false;
|
|
186
|
+
if (g_vm->GetEnv(reinterpret_cast<void**>(&callback_env), JNI_VERSION_1_6) == JNI_EDETACHED) {
|
|
187
|
+
if (g_vm->AttachCurrentThread(&callback_env, nullptr) == JNI_OK) {
|
|
188
|
+
should_detach = true;
|
|
189
|
+
} else {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (callback_env != nullptr) {
|
|
194
|
+
callback_env->CallVoidMethod(j_progress_callback_global, on_progress_method,
|
|
195
|
+
bytes_extracted, total_bytes, percent);
|
|
196
|
+
if (callback_env->ExceptionCheck()) {
|
|
197
|
+
callback_env->ExceptionClear();
|
|
198
|
+
}
|
|
199
|
+
if (should_detach) {
|
|
200
|
+
g_vm->DetachCurrentThread();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
std::string error_msg;
|
|
207
|
+
std::string sha256;
|
|
208
|
+
bool success = ArchiveHelper::ExtractTarZst(
|
|
209
|
+
source_str,
|
|
210
|
+
target_str,
|
|
211
|
+
j_force == JNI_TRUE,
|
|
212
|
+
on_progress,
|
|
213
|
+
&error_msg,
|
|
214
|
+
&sha256);
|
|
215
|
+
|
|
216
|
+
env->CallVoidMethod(result_map, put_boolean_method,
|
|
217
|
+
env->NewStringUTF("success"), success ? JNI_TRUE : JNI_FALSE);
|
|
218
|
+
|
|
219
|
+
if (success) {
|
|
220
|
+
env->CallVoidMethod(result_map, put_string_method,
|
|
221
|
+
env->NewStringUTF("path"), env->NewStringUTF(target_str.c_str()));
|
|
222
|
+
if (!sha256.empty()) {
|
|
223
|
+
env->CallVoidMethod(result_map, put_string_method,
|
|
224
|
+
env->NewStringUTF("sha256"), env->NewStringUTF(sha256.c_str()));
|
|
225
|
+
}
|
|
226
|
+
} else {
|
|
227
|
+
__android_log_print(ANDROID_LOG_WARN, "SherpaOnnxNative", "[ARCHIVE_ERROR] %s", error_msg.c_str());
|
|
228
|
+
env->CallVoidMethod(result_map, put_string_method,
|
|
229
|
+
env->NewStringUTF("reason"), env->NewStringUTF(error_msg.c_str()));
|
|
230
|
+
}
|
|
231
|
+
env->CallVoidMethod(j_promise, resolve_method, result_map);
|
|
232
|
+
|
|
233
|
+
if (j_progress_callback_global != nullptr) {
|
|
234
|
+
env->DeleteGlobalRef(j_progress_callback_global);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
env->DeleteLocalRef(result_map);
|
|
238
|
+
env->DeleteLocalRef(promise_class);
|
|
239
|
+
env->DeleteLocalRef(arguments_class);
|
|
240
|
+
env->DeleteLocalRef(writeable_map_class);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
namespace {
|
|
244
|
+
struct InputStreamReadContext {
|
|
245
|
+
JNIEnv* env = nullptr;
|
|
246
|
+
jobject stream_global = nullptr;
|
|
247
|
+
jmethodID read_method = nullptr;
|
|
248
|
+
jbyteArray byte_array = nullptr;
|
|
249
|
+
const size_t buffer_size = 64 * 1024;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
static std::ptrdiff_t JniStreamRead(void* buf, size_t len, void* user_data) {
|
|
253
|
+
auto* ctx = static_cast<InputStreamReadContext*>(user_data);
|
|
254
|
+
if (!ctx || !ctx->env || !ctx->stream_global || !ctx->read_method || !ctx->byte_array) {
|
|
255
|
+
return -1;
|
|
256
|
+
}
|
|
257
|
+
size_t to_read = (len < ctx->buffer_size) ? len : ctx->buffer_size;
|
|
258
|
+
jint n = ctx->env->CallIntMethod(ctx->stream_global, ctx->read_method, ctx->byte_array);
|
|
259
|
+
if (ctx->env->ExceptionCheck()) {
|
|
260
|
+
ctx->env->ExceptionClear();
|
|
261
|
+
return -1;
|
|
262
|
+
}
|
|
263
|
+
if (n <= 0) return 0;
|
|
264
|
+
ctx->env->GetByteArrayRegion(ctx->byte_array, 0, n, static_cast<jbyte*>(buf));
|
|
265
|
+
return static_cast<std::ptrdiff_t>(n);
|
|
266
|
+
}
|
|
267
|
+
} // namespace
|
|
268
|
+
|
|
269
|
+
extern "C" JNIEXPORT void JNICALL
|
|
270
|
+
Java_com_sherpaonnx_SherpaOnnxArchiveHelper_nativeExtractTarZstFromStream(
|
|
271
|
+
JNIEnv* env,
|
|
272
|
+
jobject /* jthis */,
|
|
273
|
+
jobject j_input_stream,
|
|
274
|
+
jstring j_target_path,
|
|
275
|
+
jboolean j_force,
|
|
276
|
+
jobject j_progress_callback,
|
|
277
|
+
jobject j_promise) {
|
|
278
|
+
const char* target_path = env->GetStringUTFChars(j_target_path, nullptr);
|
|
279
|
+
std::string target_str(target_path);
|
|
280
|
+
env->ReleaseStringUTFChars(j_target_path, target_path);
|
|
281
|
+
|
|
282
|
+
jobject stream_global = env->NewGlobalRef(j_input_stream);
|
|
283
|
+
jclass stream_class = env->GetObjectClass(j_input_stream);
|
|
284
|
+
jmethodID read_method = env->GetMethodID(stream_class, "read", "([B)I");
|
|
285
|
+
env->DeleteLocalRef(stream_class);
|
|
286
|
+
if (!read_method) {
|
|
287
|
+
env->DeleteGlobalRef(stream_global);
|
|
288
|
+
jclass promise_class = env->GetObjectClass(j_promise);
|
|
289
|
+
jmethodID reject_method = env->GetMethodID(promise_class, "reject", "(Ljava/lang/String;Ljava/lang/String;)V");
|
|
290
|
+
env->CallVoidMethod(j_promise, reject_method,
|
|
291
|
+
env->NewStringUTF("ARCHIVE_ERROR"),
|
|
292
|
+
env->NewStringUTF("InputStream.read([B)I not found"));
|
|
293
|
+
env->DeleteLocalRef(promise_class);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
jbyteArray byte_array = env->NewByteArray(static_cast<jsize>(64 * 1024));
|
|
298
|
+
if (!byte_array) {
|
|
299
|
+
env->DeleteGlobalRef(stream_global);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
InputStreamReadContext read_ctx;
|
|
304
|
+
read_ctx.env = env;
|
|
305
|
+
read_ctx.stream_global = stream_global;
|
|
306
|
+
read_ctx.read_method = read_method;
|
|
307
|
+
read_ctx.byte_array = byte_array;
|
|
308
|
+
|
|
309
|
+
jmethodID on_progress_method = nullptr;
|
|
310
|
+
jobject j_progress_callback_global = nullptr;
|
|
311
|
+
if (j_progress_callback != nullptr) {
|
|
312
|
+
jclass callback_class = env->GetObjectClass(j_progress_callback);
|
|
313
|
+
on_progress_method = env->GetMethodID(callback_class, "invoke", "(JJD)V");
|
|
314
|
+
env->DeleteLocalRef(callback_class);
|
|
315
|
+
j_progress_callback_global = env->NewGlobalRef(j_progress_callback);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
jclass promise_class = env->GetObjectClass(j_promise);
|
|
319
|
+
jmethodID resolve_method = env->GetMethodID(promise_class, "resolve", "(Ljava/lang/Object;)V");
|
|
320
|
+
|
|
321
|
+
jclass arguments_class = env->FindClass("com/facebook/react/bridge/Arguments");
|
|
322
|
+
jmethodID create_map_method = env->GetStaticMethodID(arguments_class, "createMap", "()Lcom/facebook/react/bridge/WritableMap;");
|
|
323
|
+
jobject result_map = env->CallStaticObjectMethod(arguments_class, create_map_method);
|
|
324
|
+
|
|
325
|
+
jclass writeable_map_class = env->FindClass("com/facebook/react/bridge/WritableMap");
|
|
326
|
+
jmethodID put_boolean_method = env->GetMethodID(writeable_map_class, "putBoolean", "(Ljava/lang/String;Z)V");
|
|
327
|
+
jmethodID put_string_method = env->GetMethodID(writeable_map_class, "putString", "(Ljava/lang/String;Ljava/lang/String;)V");
|
|
328
|
+
|
|
329
|
+
auto on_progress = [j_progress_callback_global, on_progress_method](
|
|
330
|
+
long long bytes_extracted, long long total_bytes, double percent) {
|
|
331
|
+
if (j_progress_callback_global != nullptr && on_progress_method != nullptr) {
|
|
332
|
+
JNIEnv* callback_env = nullptr;
|
|
333
|
+
bool should_detach = false;
|
|
334
|
+
if (g_vm->GetEnv(reinterpret_cast<void**>(&callback_env), JNI_VERSION_1_6) == JNI_EDETACHED) {
|
|
335
|
+
if (g_vm->AttachCurrentThread(&callback_env, nullptr) == JNI_OK) {
|
|
336
|
+
should_detach = true;
|
|
337
|
+
} else {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (callback_env != nullptr) {
|
|
342
|
+
callback_env->CallVoidMethod(j_progress_callback_global, on_progress_method,
|
|
343
|
+
bytes_extracted, total_bytes, percent);
|
|
344
|
+
if (callback_env->ExceptionCheck()) {
|
|
345
|
+
callback_env->ExceptionClear();
|
|
346
|
+
}
|
|
347
|
+
if (should_detach) {
|
|
348
|
+
g_vm->DetachCurrentThread();
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
std::string error_msg;
|
|
355
|
+
std::string sha256;
|
|
356
|
+
bool success = ArchiveHelper::ExtractFromStream(
|
|
357
|
+
&JniStreamRead,
|
|
358
|
+
&read_ctx,
|
|
359
|
+
target_str,
|
|
360
|
+
j_force == JNI_TRUE,
|
|
361
|
+
on_progress,
|
|
362
|
+
&error_msg,
|
|
363
|
+
&sha256);
|
|
364
|
+
|
|
365
|
+
env->CallVoidMethod(result_map, put_boolean_method,
|
|
366
|
+
env->NewStringUTF("success"), success ? JNI_TRUE : JNI_FALSE);
|
|
367
|
+
|
|
368
|
+
if (success) {
|
|
369
|
+
env->CallVoidMethod(result_map, put_string_method,
|
|
370
|
+
env->NewStringUTF("path"), env->NewStringUTF(target_str.c_str()));
|
|
371
|
+
if (!sha256.empty()) {
|
|
372
|
+
env->CallVoidMethod(result_map, put_string_method,
|
|
373
|
+
env->NewStringUTF("sha256"), env->NewStringUTF(sha256.c_str()));
|
|
374
|
+
}
|
|
375
|
+
} else {
|
|
376
|
+
__android_log_print(ANDROID_LOG_WARN, "SherpaOnnxNative", "[ARCHIVE_ERROR] %s", error_msg.c_str());
|
|
377
|
+
env->CallVoidMethod(result_map, put_string_method,
|
|
378
|
+
env->NewStringUTF("reason"), env->NewStringUTF(error_msg.c_str()));
|
|
379
|
+
}
|
|
380
|
+
env->CallVoidMethod(j_promise, resolve_method, result_map);
|
|
381
|
+
|
|
382
|
+
env->DeleteGlobalRef(stream_global);
|
|
383
|
+
env->DeleteLocalRef(byte_array);
|
|
384
|
+
if (j_progress_callback_global != nullptr) {
|
|
385
|
+
env->DeleteGlobalRef(j_progress_callback_global);
|
|
386
|
+
}
|
|
387
|
+
env->DeleteLocalRef(result_map);
|
|
388
|
+
env->DeleteLocalRef(promise_class);
|
|
389
|
+
env->DeleteLocalRef(arguments_class);
|
|
390
|
+
env->DeleteLocalRef(writeable_map_class);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
extern "C" JNIEXPORT void JNICALL
|
|
394
|
+
Java_com_sherpaonnx_SherpaOnnxArchiveHelper_nativeExtractTarBz2FromStream(
|
|
395
|
+
JNIEnv* env,
|
|
396
|
+
jobject jthis,
|
|
397
|
+
jobject j_input_stream,
|
|
398
|
+
jstring j_target_path,
|
|
399
|
+
jboolean j_force,
|
|
400
|
+
jobject j_progress_callback,
|
|
401
|
+
jobject j_promise) {
|
|
402
|
+
Java_com_sherpaonnx_SherpaOnnxArchiveHelper_nativeExtractTarZstFromStream(
|
|
403
|
+
env, jthis, j_input_stream, j_target_path, j_force, j_progress_callback, j_promise);
|
|
404
|
+
}
|
|
405
|
+
|
|
147
406
|
extern "C" JNIEXPORT void JNICALL
|
|
148
407
|
Java_com_sherpaonnx_SherpaOnnxArchiveHelper_nativeCancelExtract(JNIEnv* /* env */, jobject /* jthis */) {
|
|
149
408
|
ArchiveHelper::Cancel();
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
package com.sherpaonnx
|
|
2
2
|
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.util.Log
|
|
3
5
|
import com.facebook.react.bridge.Arguments
|
|
4
6
|
import com.facebook.react.bridge.Promise
|
|
5
7
|
import java.util.concurrent.ExecutorService
|
|
@@ -31,6 +33,11 @@ class SherpaOnnxArchiveHelper {
|
|
|
31
33
|
nativeCancelExtract()
|
|
32
34
|
}
|
|
33
35
|
|
|
36
|
+
fun cancelExtractTarZst() {
|
|
37
|
+
cancelRequested.set(true)
|
|
38
|
+
nativeCancelExtract()
|
|
39
|
+
}
|
|
40
|
+
|
|
34
41
|
fun extractTarBz2(
|
|
35
42
|
sourcePath: String,
|
|
36
43
|
targetPath: String,
|
|
@@ -71,6 +78,83 @@ class SherpaOnnxArchiveHelper {
|
|
|
71
78
|
}
|
|
72
79
|
}
|
|
73
80
|
|
|
81
|
+
fun extractTarZst(
|
|
82
|
+
sourcePath: String,
|
|
83
|
+
targetPath: String,
|
|
84
|
+
force: Boolean,
|
|
85
|
+
promise: Promise,
|
|
86
|
+
onProgress: (bytes: Long, totalBytes: Long, percent: Double) -> Unit
|
|
87
|
+
) {
|
|
88
|
+
val promiseSettled = AtomicBoolean(false)
|
|
89
|
+
fun resolveOnce(success: Boolean, reason: String? = null) {
|
|
90
|
+
if (!promiseSettled.compareAndSet(false, true)) return
|
|
91
|
+
val result = Arguments.createMap()
|
|
92
|
+
result.putBoolean("success", success)
|
|
93
|
+
if (reason != null) result.putString("reason", reason)
|
|
94
|
+
promise.resolve(result)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
cancelRequested.set(false)
|
|
99
|
+
val progressCallback = object : Any() {
|
|
100
|
+
fun invoke(bytesExtracted: Long, totalBytes: Long, percent: Double) {
|
|
101
|
+
onProgress(bytesExtracted, totalBytes, percent)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
extractExecutor.execute {
|
|
105
|
+
try {
|
|
106
|
+
nativeExtractTarZst(sourcePath, targetPath, force, progressCallback, promise)
|
|
107
|
+
} catch (e: Exception) {
|
|
108
|
+
resolveOnce(false, "Archive extraction error: ${e.message}")
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch (e: Exception) {
|
|
112
|
+
resolveOnce(false, "Archive extraction error: ${e.message}")
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
fun extractTarZstFromAsset(
|
|
117
|
+
context: Context,
|
|
118
|
+
assetPath: String,
|
|
119
|
+
targetPath: String,
|
|
120
|
+
force: Boolean,
|
|
121
|
+
promise: Promise,
|
|
122
|
+
onProgress: (bytes: Long, totalBytes: Long, percent: Double) -> Unit
|
|
123
|
+
) {
|
|
124
|
+
if (BuildConfig.DEBUG) {
|
|
125
|
+
Log.i("SherpaOnnx", "extractTarZstFromAsset assetPath=$assetPath targetPath=$targetPath")
|
|
126
|
+
}
|
|
127
|
+
cancelRequested.set(false)
|
|
128
|
+
val progressCallback = object : Any() {
|
|
129
|
+
fun invoke(bytesExtracted: Long, totalBytes: Long, percent: Double) {
|
|
130
|
+
onProgress(bytesExtracted, totalBytes, percent)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
extractExecutor.execute {
|
|
134
|
+
try {
|
|
135
|
+
context.assets.open(assetPath).use { stream ->
|
|
136
|
+
nativeExtractTarZstFromStream(stream, targetPath, force, progressCallback, promise)
|
|
137
|
+
}
|
|
138
|
+
} catch (e: Exception) {
|
|
139
|
+
val result = Arguments.createMap()
|
|
140
|
+
result.putBoolean("success", false)
|
|
141
|
+
result.putString("reason", e.message ?: "Failed to open asset")
|
|
142
|
+
promise.resolve(result)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
fun extractTarBz2FromAsset(
|
|
148
|
+
context: Context,
|
|
149
|
+
assetPath: String,
|
|
150
|
+
targetPath: String,
|
|
151
|
+
force: Boolean,
|
|
152
|
+
promise: Promise,
|
|
153
|
+
onProgress: (bytes: Long, totalBytes: Long, percent: Double) -> Unit
|
|
154
|
+
) {
|
|
155
|
+
extractTarZstFromAsset(context, assetPath, targetPath, force, promise, onProgress)
|
|
156
|
+
}
|
|
157
|
+
|
|
74
158
|
fun computeFileSha256(filePath: String, promise: Promise) {
|
|
75
159
|
nativeComputeFileSha256(filePath, promise)
|
|
76
160
|
}
|
|
@@ -84,6 +168,22 @@ class SherpaOnnxArchiveHelper {
|
|
|
84
168
|
promise: Promise
|
|
85
169
|
)
|
|
86
170
|
|
|
171
|
+
private external fun nativeExtractTarZst(
|
|
172
|
+
sourcePath: String,
|
|
173
|
+
targetPath: String,
|
|
174
|
+
force: Boolean,
|
|
175
|
+
progressCallback: Any?,
|
|
176
|
+
promise: Promise
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
private external fun nativeExtractTarZstFromStream(
|
|
180
|
+
inputStream: java.io.InputStream,
|
|
181
|
+
targetPath: String,
|
|
182
|
+
force: Boolean,
|
|
183
|
+
progressCallback: Any?,
|
|
184
|
+
promise: Promise
|
|
185
|
+
)
|
|
186
|
+
|
|
87
187
|
private external fun nativeCancelExtract()
|
|
88
188
|
|
|
89
189
|
private external fun nativeComputeFileSha256(
|
|
@@ -82,10 +82,12 @@ internal class SherpaOnnxAssetHelper(
|
|
|
82
82
|
try {
|
|
83
83
|
val baseDir = File(path)
|
|
84
84
|
if (!baseDir.exists()) {
|
|
85
|
-
|
|
85
|
+
promise.resolve(Arguments.createArray())
|
|
86
|
+
return
|
|
86
87
|
}
|
|
87
88
|
if (!baseDir.isDirectory) {
|
|
88
|
-
|
|
89
|
+
promise.resolve(Arguments.createArray())
|
|
90
|
+
return
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
val folders = mutableListOf<String>()
|
|
@@ -134,11 +136,18 @@ internal class SherpaOnnxAssetHelper(
|
|
|
134
136
|
try {
|
|
135
137
|
Log.i(logTag, "getAssetPackPath: packName=$packName")
|
|
136
138
|
val assetPackManager = AssetPackManagerFactory.getInstance(context)
|
|
137
|
-
|
|
139
|
+
var location: AssetPackLocation? = assetPackManager.getPackLocation(packName)
|
|
138
140
|
if (location == null) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
val allLocations = assetPackManager.getPackLocations()
|
|
142
|
+
location = allLocations?.get(packName)
|
|
143
|
+
if (allLocations != null) {
|
|
144
|
+
Log.i(logTag, "getAssetPackPath: getPackLocation was null, getPackLocations keys=${allLocations.keys}")
|
|
145
|
+
}
|
|
146
|
+
if (location == null) {
|
|
147
|
+
Log.i(logTag, "getAssetPackPath: location is null for pack '$packName'")
|
|
148
|
+
promise.resolve(null)
|
|
149
|
+
return
|
|
150
|
+
}
|
|
142
151
|
}
|
|
143
152
|
Log.i(logTag, "getAssetPackPath: storageMethod=${location.packStorageMethod()}, " +
|
|
144
153
|
"assetsPath=${location.assetsPath()}, path=${location.path()}")
|
|
@@ -170,6 +179,42 @@ internal class SherpaOnnxAssetHelper(
|
|
|
170
179
|
}
|
|
171
180
|
}
|
|
172
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Lists asset paths of .tar.zst and .tar.bz2 archives in a PAD pack when stored as APK_ASSETS.
|
|
184
|
+
* Returns empty array when pack is null or STORAGE_FILES (caller uses path + readDir in that case).
|
|
185
|
+
* APK_ASSETS: pack content is merged into the app asset root; canonical path is "models"
|
|
186
|
+
* (pack layout src/main/assets/models/). Same for Play Store and bundletool install-time delivery.
|
|
187
|
+
*/
|
|
188
|
+
fun listBundledArchiveAssetPaths(packName: String, promise: Promise) {
|
|
189
|
+
try {
|
|
190
|
+
val assetPackManager = AssetPackManagerFactory.getInstance(context)
|
|
191
|
+
var location: AssetPackLocation? = assetPackManager.getPackLocation(packName)
|
|
192
|
+
if (location == null) {
|
|
193
|
+
location = assetPackManager.getPackLocations()?.get(packName)
|
|
194
|
+
}
|
|
195
|
+
if (location == null) {
|
|
196
|
+
promise.resolve(Arguments.createArray())
|
|
197
|
+
return
|
|
198
|
+
}
|
|
199
|
+
if (location.packStorageMethod() != AssetPackStorageMethod.STORAGE_FILES) {
|
|
200
|
+
val assetPrefix = "models"
|
|
201
|
+
val names = context.assets.list(assetPrefix) ?: emptyArray()
|
|
202
|
+
val archives = names.filter { it.endsWith(".tar.zst") || it.endsWith(".tar.bz2") }
|
|
203
|
+
val result = Arguments.createArray()
|
|
204
|
+
for (name in archives) {
|
|
205
|
+
result.pushString("$assetPrefix/$name")
|
|
206
|
+
}
|
|
207
|
+
Log.i(logTag, "listBundledArchiveAssetPaths: packName=$packName prefix=$assetPrefix count=${result.size()}")
|
|
208
|
+
promise.resolve(result)
|
|
209
|
+
} else {
|
|
210
|
+
promise.resolve(Arguments.createArray())
|
|
211
|
+
}
|
|
212
|
+
} catch (e: Exception) {
|
|
213
|
+
Log.w(logTag, "listBundledArchiveAssetPaths failed: ${e.message}")
|
|
214
|
+
promise.resolve(Arguments.createArray())
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
173
218
|
private fun resolveAssetPath(assetPath: String): String {
|
|
174
219
|
Log.i(logTag, "resolveAssetPath: assetPath=$assetPath")
|
|
175
220
|
val assetManager = context.assets
|
|
@@ -303,6 +303,17 @@ class SherpaOnnxModule(reactContext: ReactApplicationContext) :
|
|
|
303
303
|
promise.resolve(null)
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
+
override fun extractTarZst(sourcePath: String, targetPath: String, force: Boolean, promise: Promise) {
|
|
307
|
+
archiveHelper.extractTarZst(sourcePath, targetPath, force, promise) { bytes, total, percent ->
|
|
308
|
+
emitExtractTarZstProgress(sourcePath, bytes, total, percent)
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
override fun cancelExtractTarZst(promise: Promise) {
|
|
313
|
+
archiveHelper.cancelExtractTarZst()
|
|
314
|
+
promise.resolve(null)
|
|
315
|
+
}
|
|
316
|
+
|
|
306
317
|
override fun computeFileSha256(filePath: String, promise: Promise) {
|
|
307
318
|
archiveHelper.computeFileSha256(filePath, promise)
|
|
308
319
|
}
|
|
@@ -318,6 +329,17 @@ class SherpaOnnxModule(reactContext: ReactApplicationContext) :
|
|
|
318
329
|
eventEmitter.emit("extractTarBz2Progress", payload)
|
|
319
330
|
}
|
|
320
331
|
|
|
332
|
+
private fun emitExtractTarZstProgress(sourcePath: String, bytes: Long, totalBytes: Long, percent: Double) {
|
|
333
|
+
val eventEmitter = reactApplicationContext
|
|
334
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
335
|
+
val payload = Arguments.createMap()
|
|
336
|
+
payload.putString("sourcePath", sourcePath)
|
|
337
|
+
payload.putDouble("bytes", bytes.toDouble())
|
|
338
|
+
payload.putDouble("totalBytes", totalBytes.toDouble())
|
|
339
|
+
payload.putDouble("percent", percent)
|
|
340
|
+
eventEmitter.emit("extractTarZstProgress", payload)
|
|
341
|
+
}
|
|
342
|
+
|
|
321
343
|
/**
|
|
322
344
|
* Resolve asset path - copy from assets to internal storage if needed
|
|
323
345
|
* Preserves the directory structure from assets (e.g., test_wavs/ stays as test_wavs/)
|
|
@@ -997,6 +1019,44 @@ class SherpaOnnxModule(reactContext: ReactApplicationContext) :
|
|
|
997
1019
|
assetHelper.getAssetPackPath(packName, promise)
|
|
998
1020
|
}
|
|
999
1021
|
|
|
1022
|
+
override fun listBundledArchiveAssetPaths(packName: String, promise: Promise) {
|
|
1023
|
+
assetHelper.listBundledArchiveAssetPaths(packName, promise)
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
override fun extractTarZstFromAsset(
|
|
1027
|
+
assetPath: String,
|
|
1028
|
+
targetPath: String,
|
|
1029
|
+
force: Boolean,
|
|
1030
|
+
promise: Promise
|
|
1031
|
+
) {
|
|
1032
|
+
archiveHelper.extractTarZstFromAsset(
|
|
1033
|
+
reactApplicationContext,
|
|
1034
|
+
assetPath,
|
|
1035
|
+
targetPath,
|
|
1036
|
+
force,
|
|
1037
|
+
promise
|
|
1038
|
+
) { bytes, total, percent ->
|
|
1039
|
+
emitExtractTarZstProgress(assetPath, bytes, total, percent)
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
override fun extractTarBz2FromAsset(
|
|
1044
|
+
assetPath: String,
|
|
1045
|
+
targetPath: String,
|
|
1046
|
+
force: Boolean,
|
|
1047
|
+
promise: Promise
|
|
1048
|
+
) {
|
|
1049
|
+
archiveHelper.extractTarBz2FromAsset(
|
|
1050
|
+
reactApplicationContext,
|
|
1051
|
+
assetPath,
|
|
1052
|
+
targetPath,
|
|
1053
|
+
force,
|
|
1054
|
+
promise
|
|
1055
|
+
) { bytes, total, percent ->
|
|
1056
|
+
emitExtractProgress(assetPath, bytes, total, percent)
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1000
1060
|
companion object {
|
|
1001
1061
|
const val NAME = "SherpaOnnx"
|
|
1002
1062
|
|
package/ios/SherpaOnnx.mm
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
- (NSArray<NSString *> *)supportedEvents
|
|
40
40
|
{
|
|
41
|
-
return @[ @"ttsStreamChunk", @"ttsStreamEnd", @"ttsStreamError", @"extractTarBz2Progress", @"pcmLiveStreamData", @"pcmLiveStreamError" ];
|
|
41
|
+
return @[ @"ttsStreamChunk", @"ttsStreamEnd", @"ttsStreamError", @"extractTarBz2Progress", @"extractTarZstProgress", @"pcmLiveStreamData", @"pcmLiveStreamError" ];
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
- (void)resolveModelPath:(JS::NativeSherpaOnnx::SpecResolveModelPathConfig &)config
|
|
@@ -162,6 +162,33 @@
|
|
|
162
162
|
resolve(nil);
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
- (void)extractTarZst:(NSString *)sourcePath
|
|
166
|
+
targetPath:(NSString *)targetPath
|
|
167
|
+
force:(BOOL)force
|
|
168
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
169
|
+
reject:(RCTPromiseRejectBlock)reject
|
|
170
|
+
{
|
|
171
|
+
SherpaOnnxArchiveHelper *helper = [SherpaOnnxArchiveHelper new];
|
|
172
|
+
NSDictionary *result = [helper extractTarZst:sourcePath
|
|
173
|
+
targetPath:targetPath
|
|
174
|
+
force:force
|
|
175
|
+
progress:^(long long bytes, long long totalBytes, double percent) {
|
|
176
|
+
[self sendEventWithName:@"extractTarZstProgress"
|
|
177
|
+
body:@{ @"sourcePath": sourcePath,
|
|
178
|
+
@"bytes": @(bytes),
|
|
179
|
+
@"totalBytes": @(totalBytes),
|
|
180
|
+
@"percent": @(percent) }];
|
|
181
|
+
}];
|
|
182
|
+
resolve(result);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
- (void)cancelExtractTarZst:(RCTPromiseResolveBlock)resolve
|
|
186
|
+
reject:(RCTPromiseRejectBlock)reject
|
|
187
|
+
{
|
|
188
|
+
[SherpaOnnxArchiveHelper cancelExtractTarZst];
|
|
189
|
+
resolve(nil);
|
|
190
|
+
}
|
|
191
|
+
|
|
165
192
|
- (void)computeFileSha256:(NSString *)filePath
|
|
166
193
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
167
194
|
reject:(RCTPromiseRejectBlock)reject
|
|
@@ -184,6 +211,32 @@
|
|
|
184
211
|
resolve([NSNull null]);
|
|
185
212
|
}
|
|
186
213
|
|
|
214
|
+
- (void)listBundledArchiveAssetPaths:(NSString *)packName
|
|
215
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
216
|
+
reject:(RCTPromiseRejectBlock)reject
|
|
217
|
+
{
|
|
218
|
+
// PAD APK_ASSETS listing is Android-only.
|
|
219
|
+
resolve(@[]);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
- (void)extractTarZstFromAsset:(NSString *)assetPath
|
|
223
|
+
targetPath:(NSString *)targetPath
|
|
224
|
+
force:(NSNumber *)force
|
|
225
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
226
|
+
reject:(RCTPromiseRejectBlock)reject
|
|
227
|
+
{
|
|
228
|
+
resolve(@{ @"success": @NO, @"reason": @"Not supported on iOS; use path-based extraction." });
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
- (void)extractTarBz2FromAsset:(NSString *)assetPath
|
|
232
|
+
targetPath:(NSString *)targetPath
|
|
233
|
+
force:(NSNumber *)force
|
|
234
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
235
|
+
reject:(RCTPromiseRejectBlock)reject
|
|
236
|
+
{
|
|
237
|
+
resolve(@{ @"success": @NO, @"reason": @"Not supported on iOS; use path-based extraction." });
|
|
238
|
+
}
|
|
239
|
+
|
|
187
240
|
- (void)convertAudioToFormat:(NSString *)inputPath
|
|
188
241
|
outputPath:(NSString *)outputPath
|
|
189
242
|
format:(NSString *)format
|
|
@@ -11,11 +11,18 @@ typedef void (^SherpaOnnxArchiveProgressBlock)(long long bytes, long long totalB
|
|
|
11
11
|
force:(BOOL)force
|
|
12
12
|
progress:(nullable SherpaOnnxArchiveProgressBlock)progress;
|
|
13
13
|
|
|
14
|
+
- (NSDictionary *)extractTarZst:(NSString *)sourcePath
|
|
15
|
+
targetPath:(NSString *)targetPath
|
|
16
|
+
force:(BOOL)force
|
|
17
|
+
progress:(nullable SherpaOnnxArchiveProgressBlock)progress;
|
|
18
|
+
|
|
14
19
|
- (nullable NSString *)computeFileSha256:(NSString *)filePath
|
|
15
20
|
error:(NSError * _Nullable * _Nullable)error;
|
|
16
21
|
|
|
17
22
|
+ (void)cancelExtractTarBz2;
|
|
18
23
|
|
|
24
|
+
+ (void)cancelExtractTarZst;
|
|
25
|
+
|
|
19
26
|
@end
|
|
20
27
|
|
|
21
28
|
NS_ASSUME_NONNULL_END
|