react-native-sherpa-onnx 0.2.0 → 0.3.0

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.
Files changed (175) hide show
  1. package/README.md +232 -236
  2. package/SherpaOnnx.podspec +68 -64
  3. package/android/build.gradle +182 -192
  4. package/android/codegen.gradle +57 -0
  5. package/android/prebuilt-download.gradle +428 -0
  6. package/android/prebuilt-versions.gradle +43 -0
  7. package/android/proguard-rules.pro +10 -0
  8. package/android/src/main/assets/testModels/add_mul_add.onnx +28 -0
  9. package/android/src/main/assets/testModels/nnapi_internal_uint8_support.onnx +0 -0
  10. package/android/src/main/assets/testModels/qnn_multi_ctx_embed.onnx +0 -0
  11. package/android/src/main/cpp/CMakeLists.txt +166 -129
  12. package/android/src/main/cpp/CMakePresets.json +54 -0
  13. package/android/src/main/cpp/crypto/sha256.cpp +174 -0
  14. package/android/src/main/cpp/crypto/sha256.h +16 -0
  15. package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.cpp +404 -0
  16. package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.h +56 -0
  17. package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-jni.cpp +181 -0
  18. package/android/src/main/cpp/jni/audio/sherpa-onnx-audio-convert-jni.cpp +888 -0
  19. package/{ios → android/src/main/cpp/jni/model_detect}/sherpa-onnx-common.h +18 -18
  20. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-detect-jni-common.cpp +86 -0
  21. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-detect-jni-common.h +20 -0
  22. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-helper.cpp +423 -0
  23. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-helper.h +55 -0
  24. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-stt.cpp +399 -0
  25. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-tts.cpp +238 -0
  26. package/{ios → android/src/main/cpp/jni/model_detect}/sherpa-onnx-model-detect.h +122 -89
  27. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-stt-wrapper.cpp +99 -0
  28. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-stt-wrapper.h +16 -0
  29. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-tts-wrapper.cpp +78 -0
  30. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-tts-wrapper.h +16 -0
  31. package/android/src/main/cpp/jni/module/sherpa-onnx-module-jni.cpp +190 -0
  32. package/android/src/main/cpp/jni/tts/sherpa-onnx-tts-zipvoice-jni.cpp +301 -0
  33. package/android/src/main/java/com/sherpaonnx/SherpaOnnxArchiveHelper.kt +94 -0
  34. package/android/src/main/java/com/sherpaonnx/{SherpaOnnxCoreHelper.kt → SherpaOnnxAssetHelper.kt} +350 -236
  35. package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +791 -483
  36. package/android/src/main/java/com/sherpaonnx/SherpaOnnxSttHelper.kt +699 -109
  37. package/android/src/main/java/com/sherpaonnx/SherpaOnnxTtsHelper.kt +1123 -668
  38. package/android/src/main/java/com/sherpaonnx/ZipvoiceTtsWrapper.kt +187 -0
  39. package/ios/SherpaOnnx+Assets.h +11 -0
  40. package/ios/SherpaOnnx+Assets.mm +325 -0
  41. package/ios/SherpaOnnx+STT.mm +455 -118
  42. package/ios/SherpaOnnx+TTS.mm +1101 -712
  43. package/ios/SherpaOnnx.h +17 -6
  44. package/ios/SherpaOnnx.mm +206 -311
  45. package/ios/SherpaOnnx.xcconfig +19 -19
  46. package/ios/SherpaOnnxCoreMLHelper.swift +24 -0
  47. package/ios/archive/sherpa-onnx-archive-helper.h +21 -0
  48. package/ios/archive/sherpa-onnx-archive-helper.mm +296 -0
  49. package/ios/libarchive_darwin_config.h +153 -0
  50. package/{android/src/main/cpp/jni → ios/model_detect}/sherpa-onnx-common.h +18 -18
  51. package/ios/model_detect/sherpa-onnx-model-detect-helper.h +49 -0
  52. package/ios/model_detect/sherpa-onnx-model-detect-helper.mm +210 -0
  53. package/ios/model_detect/sherpa-onnx-model-detect-stt.mm +344 -0
  54. package/ios/model_detect/sherpa-onnx-model-detect-tts.mm +201 -0
  55. package/{android/src/main/cpp/jni → ios/model_detect}/sherpa-onnx-model-detect.h +117 -89
  56. package/ios/scripts/patch-libarchive-includes.sh +61 -0
  57. package/ios/scripts/setup-ios-libarchive.sh +98 -0
  58. package/ios/stt/sherpa-onnx-stt-wrapper.h +129 -0
  59. package/ios/stt/sherpa-onnx-stt-wrapper.mm +523 -0
  60. package/ios/{sherpa-onnx-tts-wrapper.h → tts/sherpa-onnx-tts-wrapper.h} +90 -85
  61. package/ios/{sherpa-onnx-tts-wrapper.mm → tts/sherpa-onnx-tts-wrapper.mm} +376 -345
  62. package/lib/module/NativeSherpaOnnx.js +3 -0
  63. package/lib/module/NativeSherpaOnnx.js.map +1 -1
  64. package/lib/module/audio/index.js +22 -0
  65. package/lib/module/audio/index.js.map +1 -0
  66. package/lib/module/diarization/index.js +1 -1
  67. package/lib/module/diarization/index.js.map +1 -1
  68. package/lib/module/download/ModelDownloadManager.js +918 -0
  69. package/lib/module/download/ModelDownloadManager.js.map +1 -0
  70. package/lib/module/download/extractTarBz2.js +53 -0
  71. package/lib/module/download/extractTarBz2.js.map +1 -0
  72. package/lib/module/download/index.js +6 -0
  73. package/lib/module/download/index.js.map +1 -0
  74. package/lib/module/download/validation.js +178 -0
  75. package/lib/module/download/validation.js.map +1 -0
  76. package/lib/module/enhancement/index.js +1 -1
  77. package/lib/module/enhancement/index.js.map +1 -1
  78. package/lib/module/index.js +41 -3
  79. package/lib/module/index.js.map +1 -1
  80. package/lib/module/separation/index.js +1 -1
  81. package/lib/module/separation/index.js.map +1 -1
  82. package/lib/module/stt/index.js +127 -60
  83. package/lib/module/stt/index.js.map +1 -1
  84. package/lib/module/stt/sttModelLanguages.js +512 -0
  85. package/lib/module/stt/sttModelLanguages.js.map +1 -0
  86. package/lib/module/stt/types.js +53 -1
  87. package/lib/module/stt/types.js.map +1 -1
  88. package/lib/module/tts/index.js +216 -289
  89. package/lib/module/tts/index.js.map +1 -1
  90. package/lib/module/tts/types.js +86 -1
  91. package/lib/module/tts/types.js.map +1 -1
  92. package/lib/module/types.js.map +1 -1
  93. package/lib/module/utils.js +86 -73
  94. package/lib/module/utils.js.map +1 -1
  95. package/lib/module/vad/index.js +1 -1
  96. package/lib/module/vad/index.js.map +1 -1
  97. package/lib/typescript/src/NativeSherpaOnnx.d.ts +192 -38
  98. package/lib/typescript/src/NativeSherpaOnnx.d.ts.map +1 -1
  99. package/lib/typescript/src/audio/index.d.ts +13 -0
  100. package/lib/typescript/src/audio/index.d.ts.map +1 -0
  101. package/lib/typescript/src/diarization/index.d.ts +3 -2
  102. package/lib/typescript/src/diarization/index.d.ts.map +1 -1
  103. package/lib/typescript/src/download/ModelDownloadManager.d.ts +108 -0
  104. package/lib/typescript/src/download/ModelDownloadManager.d.ts.map +1 -0
  105. package/lib/typescript/src/download/extractTarBz2.d.ts +14 -0
  106. package/lib/typescript/src/download/extractTarBz2.d.ts.map +1 -0
  107. package/lib/typescript/src/download/index.d.ts +7 -0
  108. package/lib/typescript/src/download/index.d.ts.map +1 -0
  109. package/lib/typescript/src/download/validation.d.ts +57 -0
  110. package/lib/typescript/src/download/validation.d.ts.map +1 -0
  111. package/lib/typescript/src/enhancement/index.d.ts +3 -2
  112. package/lib/typescript/src/enhancement/index.d.ts.map +1 -1
  113. package/lib/typescript/src/index.d.ts +26 -2
  114. package/lib/typescript/src/index.d.ts.map +1 -1
  115. package/lib/typescript/src/separation/index.d.ts +3 -2
  116. package/lib/typescript/src/separation/index.d.ts.map +1 -1
  117. package/lib/typescript/src/stt/index.d.ts +31 -43
  118. package/lib/typescript/src/stt/index.d.ts.map +1 -1
  119. package/lib/typescript/src/stt/sttModelLanguages.d.ts +52 -0
  120. package/lib/typescript/src/stt/sttModelLanguages.d.ts.map +1 -0
  121. package/lib/typescript/src/stt/types.d.ts +196 -9
  122. package/lib/typescript/src/stt/types.d.ts.map +1 -1
  123. package/lib/typescript/src/tts/index.d.ts +25 -211
  124. package/lib/typescript/src/tts/index.d.ts.map +1 -1
  125. package/lib/typescript/src/tts/types.d.ts +148 -25
  126. package/lib/typescript/src/tts/types.d.ts.map +1 -1
  127. package/lib/typescript/src/types.d.ts +0 -32
  128. package/lib/typescript/src/types.d.ts.map +1 -1
  129. package/lib/typescript/src/utils.d.ts +28 -13
  130. package/lib/typescript/src/utils.d.ts.map +1 -1
  131. package/lib/typescript/src/vad/index.d.ts +3 -2
  132. package/lib/typescript/src/vad/index.d.ts.map +1 -1
  133. package/package.json +250 -222
  134. package/scripts/check-qnn-support.sh +78 -0
  135. package/scripts/setup-ios-framework.sh +379 -282
  136. package/src/NativeSherpaOnnx.ts +474 -251
  137. package/src/audio/index.ts +32 -0
  138. package/src/diarization/index.ts +4 -2
  139. package/src/download/ModelDownloadManager.ts +1325 -0
  140. package/src/download/extractTarBz2.ts +78 -0
  141. package/src/download/index.ts +43 -0
  142. package/src/download/validation.ts +279 -0
  143. package/src/enhancement/index.ts +4 -2
  144. package/src/index.tsx +78 -27
  145. package/src/separation/index.ts +4 -2
  146. package/src/stt/index.ts +249 -89
  147. package/src/stt/sttModelLanguages.ts +237 -0
  148. package/src/stt/types.ts +263 -9
  149. package/src/tts/index.ts +470 -458
  150. package/src/tts/types.ts +373 -218
  151. package/src/types.ts +0 -44
  152. package/src/utils.ts +145 -131
  153. package/src/vad/index.ts +4 -2
  154. package/third_party/ffmpeg_prebuilt/ANDROID_RELEASE_TAG +1 -0
  155. package/third_party/libarchive_prebuilt/ANDROID_RELEASE_TAG +1 -0
  156. package/third_party/libarchive_prebuilt/IOS_RELEASE_TAG +1 -0
  157. package/third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG +1 -0
  158. package/third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG +1 -0
  159. package/android/src/main/cpp/include/sherpa-onnx/c-api/c-api.h +0 -1918
  160. package/android/src/main/cpp/include/sherpa-onnx/c-api/cxx-api.h +0 -841
  161. package/android/src/main/cpp/jni/sherpa-onnx-model-detect.cpp +0 -541
  162. package/android/src/main/cpp/jni/sherpa-onnx-stt-jni.cpp +0 -336
  163. package/android/src/main/cpp/jni/sherpa-onnx-stt-wrapper.cpp +0 -222
  164. package/android/src/main/cpp/jni/sherpa-onnx-stt-wrapper.h +0 -68
  165. package/android/src/main/cpp/jni/sherpa-onnx-tts-jni.cpp +0 -823
  166. package/android/src/main/cpp/jni/sherpa-onnx-tts-wrapper.cpp +0 -387
  167. package/android/src/main/cpp/jni/sherpa-onnx-tts-wrapper.h +0 -147
  168. package/ios/Frameworks/sherpa_onnx.xcframework.zip +0 -0
  169. package/ios/include/sherpa-onnx/c-api/c-api.h +0 -1918
  170. package/ios/include/sherpa-onnx/c-api/cxx-api.h +0 -841
  171. package/ios/sherpa-onnx-model-detect.mm +0 -441
  172. package/ios/sherpa-onnx-stt-wrapper.h +0 -48
  173. package/ios/sherpa-onnx-stt-wrapper.mm +0 -201
  174. package/scripts/copy-headers.js +0 -184
  175. package/scripts/setup-assets.js +0 -323
@@ -0,0 +1,301 @@
1
+ /**
2
+ * sherpa-onnx-tts-zipvoice-jni.cpp
3
+ *
4
+ * Purpose: JNI for Zipvoice TTS using the sherpa-onnx C-API (OfflineTtsZipvoiceModelConfig). The
5
+ * Kotlin TTS API does not expose Zipvoice config, so this native layer is used for Zipvoice-only flows.
6
+ */
7
+ #include <jni.h>
8
+ #include <cstring>
9
+ #include <android/log.h>
10
+
11
+ #include "sherpa-onnx/c-api/c-api.h"
12
+
13
+ #define LOG_TAG "ZipvoiceTtsJni"
14
+ #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
15
+ #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
16
+
17
+ namespace {
18
+
19
+ // Helper: get a non-null C string from a jstring (returns "" for null).
20
+ struct JStringGuard {
21
+ JNIEnv* env;
22
+ jstring jstr;
23
+ const char* cstr;
24
+
25
+ JStringGuard(JNIEnv* e, jstring s) : env(e), jstr(s), cstr(nullptr) {
26
+ if (s) cstr = env->GetStringUTFChars(s, nullptr);
27
+ }
28
+ ~JStringGuard() {
29
+ if (cstr) env->ReleaseStringUTFChars(jstr, cstr);
30
+ }
31
+ const char* get() const { return cstr ? cstr : ""; }
32
+ };
33
+
34
+ // Build a Java float[] + int pair as Object[] { float[], Integer } for returning generated audio.
35
+ jobjectArray buildAudioResult(JNIEnv* env, const float* samples, int32_t n, int32_t sampleRate) {
36
+ jclass objClass = env->FindClass("java/lang/Object");
37
+ if (!objClass) return nullptr;
38
+
39
+ jobjectArray result = env->NewObjectArray(2, objClass, nullptr);
40
+ if (!result) {
41
+ env->DeleteLocalRef(objClass);
42
+ return nullptr;
43
+ }
44
+
45
+ // Element 0: float[] samples
46
+ jfloatArray jsamples = env->NewFloatArray(n);
47
+ if (jsamples && n > 0) {
48
+ env->SetFloatArrayRegion(jsamples, 0, n, samples);
49
+ }
50
+ env->SetObjectArrayElement(result, 0, jsamples);
51
+ if (jsamples) env->DeleteLocalRef(jsamples);
52
+
53
+ // Element 1: Integer sampleRate
54
+ jclass intClass = env->FindClass("java/lang/Integer");
55
+ jmethodID intValueOf = env->GetStaticMethodID(intClass, "valueOf", "(I)Ljava/lang/Integer;");
56
+ jobject jrate = env->CallStaticObjectMethod(intClass, intValueOf, sampleRate);
57
+ env->SetObjectArrayElement(result, 1, jrate);
58
+ env->DeleteLocalRef(intClass);
59
+ if (jrate) env->DeleteLocalRef(jrate);
60
+
61
+ env->DeleteLocalRef(objClass);
62
+ return result;
63
+ }
64
+
65
+ } // namespace
66
+
67
+ extern "C" {
68
+
69
+ // Create a Zipvoice TTS instance via C-API. Returns the pointer as a jlong (0 on failure).
70
+ JNIEXPORT jlong JNICALL
71
+ Java_com_sherpaonnx_ZipvoiceTtsWrapper_nativeCreate(
72
+ JNIEnv* env, jobject /* this */,
73
+ jstring j_tokens, jstring j_encoder, jstring j_decoder, jstring j_vocoder,
74
+ jstring j_data_dir, jstring j_lexicon,
75
+ jfloat feat_scale, jfloat t_shift, jfloat target_rms, jfloat guidance_scale,
76
+ jint num_threads, jboolean debug,
77
+ jstring j_rule_fsts, jstring j_rule_fars, jint max_num_sentences, jfloat silence_scale,
78
+ jstring j_provider) {
79
+ JStringGuard tokens(env, j_tokens);
80
+ JStringGuard encoder(env, j_encoder);
81
+ JStringGuard decoder(env, j_decoder);
82
+ JStringGuard vocoder(env, j_vocoder);
83
+ JStringGuard dataDir(env, j_data_dir);
84
+ JStringGuard lexicon(env, j_lexicon);
85
+ JStringGuard ruleFsts(env, j_rule_fsts);
86
+ JStringGuard ruleFars(env, j_rule_fars);
87
+ JStringGuard provider(env, j_provider);
88
+
89
+ LOGI("nativeCreate: tokens=%s, encoder=%s, decoder=%s, vocoder=%s, dataDir=%s, lexicon=%s",
90
+ tokens.get(), encoder.get(), decoder.get(), vocoder.get(), dataDir.get(), lexicon.get());
91
+ LOGI("nativeCreate: featScale=%.3f, tShift=%.3f, targetRms=%.3f, guidanceScale=%.3f, threads=%d, debug=%d",
92
+ feat_scale, t_shift, target_rms, guidance_scale, num_threads, debug);
93
+ LOGI("nativeCreate: ruleFsts=%s, ruleFars=%s, maxNumSentences=%d, silenceScale=%.3f, provider=%s",
94
+ ruleFsts.get(), ruleFars.get(), max_num_sentences, silence_scale, provider.get());
95
+
96
+ SherpaOnnxOfflineTtsConfig config;
97
+ memset(&config, 0, sizeof(config));
98
+
99
+ config.model.zipvoice.tokens = tokens.get();
100
+ config.model.zipvoice.encoder = encoder.get();
101
+ config.model.zipvoice.decoder = decoder.get();
102
+ config.model.zipvoice.vocoder = vocoder.get();
103
+ config.model.zipvoice.data_dir = dataDir.get();
104
+ config.model.zipvoice.lexicon = lexicon.get();
105
+ config.model.zipvoice.feat_scale = feat_scale;
106
+ config.model.zipvoice.t_shift = t_shift;
107
+ config.model.zipvoice.target_rms = target_rms;
108
+ config.model.zipvoice.guidance_scale = guidance_scale;
109
+
110
+ config.model.num_threads = num_threads;
111
+ config.model.debug = debug ? 1 : 0;
112
+ config.model.provider = (provider.get() && *provider.get()) ? provider.get() : "cpu";
113
+
114
+ config.rule_fsts = ruleFsts.get();
115
+ config.rule_fars = ruleFars.get();
116
+ config.max_num_sentences = max_num_sentences;
117
+ config.silence_scale = silence_scale;
118
+
119
+ const SherpaOnnxOfflineTts* tts = SherpaOnnxCreateOfflineTts(&config);
120
+ if (!tts) {
121
+ LOGE("nativeCreate: SherpaOnnxCreateOfflineTts returned null");
122
+ return 0;
123
+ }
124
+
125
+ LOGI("nativeCreate: success, sampleRate=%d, numSpeakers=%d",
126
+ SherpaOnnxOfflineTtsSampleRate(tts), SherpaOnnxOfflineTtsNumSpeakers(tts));
127
+
128
+ return reinterpret_cast<jlong>(tts);
129
+ }
130
+
131
+ // Destroy a Zipvoice TTS instance.
132
+ JNIEXPORT void JNICALL
133
+ Java_com_sherpaonnx_ZipvoiceTtsWrapper_nativeDestroy(
134
+ JNIEnv* /* env */, jobject /* this */, jlong ptr) {
135
+ auto* tts = reinterpret_cast<const SherpaOnnxOfflineTts*>(ptr);
136
+ if (tts) {
137
+ SherpaOnnxDestroyOfflineTts(tts);
138
+ LOGI("nativeDestroy: released");
139
+ }
140
+ }
141
+
142
+ // Get the sample rate of the Zipvoice TTS model.
143
+ JNIEXPORT jint JNICALL
144
+ Java_com_sherpaonnx_ZipvoiceTtsWrapper_nativeGetSampleRate(
145
+ JNIEnv* /* env */, jobject /* this */, jlong ptr) {
146
+ auto* tts = reinterpret_cast<const SherpaOnnxOfflineTts*>(ptr);
147
+ return tts ? SherpaOnnxOfflineTtsSampleRate(tts) : 0;
148
+ }
149
+
150
+ // Get the number of speakers of the Zipvoice TTS model.
151
+ JNIEXPORT jint JNICALL
152
+ Java_com_sherpaonnx_ZipvoiceTtsWrapper_nativeGetNumSpeakers(
153
+ JNIEnv* /* env */, jobject /* this */, jlong ptr) {
154
+ auto* tts = reinterpret_cast<const SherpaOnnxOfflineTts*>(ptr);
155
+ return tts ? SherpaOnnxOfflineTtsNumSpeakers(tts) : 0;
156
+ }
157
+
158
+ // Generate audio (non-zero-shot). Returns Object[] { float[], Integer }.
159
+ JNIEXPORT jobjectArray JNICALL
160
+ Java_com_sherpaonnx_ZipvoiceTtsWrapper_nativeGenerate(
161
+ JNIEnv* env, jobject /* this */,
162
+ jlong ptr, jstring j_text, jint sid, jfloat speed) {
163
+ auto* tts = reinterpret_cast<const SherpaOnnxOfflineTts*>(ptr);
164
+ if (!tts) {
165
+ LOGE("nativeGenerate: tts pointer is null");
166
+ return nullptr;
167
+ }
168
+
169
+ JStringGuard text(env, j_text);
170
+ LOGI("nativeGenerate: text=%s, sid=%d, speed=%.2f", text.get(), sid, speed);
171
+
172
+ const SherpaOnnxGeneratedAudio* audio =
173
+ SherpaOnnxOfflineTtsGenerate(tts, text.get(), sid, speed);
174
+ if (!audio) {
175
+ LOGE("nativeGenerate: SherpaOnnxOfflineTtsGenerate returned null");
176
+ return nullptr;
177
+ }
178
+
179
+ LOGI("nativeGenerate: got %d samples at %d Hz", audio->n, audio->sample_rate);
180
+ jobjectArray result = buildAudioResult(env, audio->samples, audio->n, audio->sample_rate);
181
+
182
+ SherpaOnnxDestroyOfflineTtsGeneratedAudio(audio);
183
+ return result;
184
+ }
185
+
186
+ // Generate audio with callback for streaming. Returns Object[] { float[], Integer } for the
187
+ // final concatenated audio. The callback is invoked per chunk.
188
+ JNIEXPORT jobjectArray JNICALL
189
+ Java_com_sherpaonnx_ZipvoiceTtsWrapper_nativeGenerateWithCallback(
190
+ JNIEnv* env, jobject thiz,
191
+ jlong ptr, jstring j_text, jint sid, jfloat speed) {
192
+ auto* tts = reinterpret_cast<const SherpaOnnxOfflineTts*>(ptr);
193
+ if (!tts) {
194
+ LOGE("nativeGenerateWithCallback: tts pointer is null");
195
+ return nullptr;
196
+ }
197
+
198
+ JStringGuard text(env, j_text);
199
+
200
+ // We use the progress callback variant to get chunks.
201
+ // The JNI environment and `thiz` are stored in a struct passed through void* arg.
202
+ struct CallbackCtx {
203
+ JNIEnv* env;
204
+ jobject thiz;
205
+ jmethodID onChunkId;
206
+ bool cancelled;
207
+ };
208
+
209
+ jclass cls = env->GetObjectClass(thiz);
210
+ jmethodID onChunkId = env->GetMethodID(cls, "onNativeChunk", "([FI)Z");
211
+ env->DeleteLocalRef(cls);
212
+ if (!onChunkId) {
213
+ LOGE("nativeGenerateWithCallback: onNativeChunk method not found");
214
+ return nullptr;
215
+ }
216
+
217
+ CallbackCtx ctx{env, thiz, onChunkId, false};
218
+
219
+ auto callback = [](const float* samples, int32_t n, float /* progress */, void* arg) -> int32_t {
220
+ auto* c = static_cast<CallbackCtx*>(arg);
221
+ if (c->cancelled) return 0;
222
+
223
+ jfloatArray chunk = c->env->NewFloatArray(n);
224
+ if (chunk && n > 0) {
225
+ c->env->SetFloatArrayRegion(chunk, 0, n, samples);
226
+ }
227
+
228
+ // Call Java: boolean onNativeChunk(float[] samples, int n)
229
+ jboolean cont = c->env->CallBooleanMethod(c->thiz, c->onChunkId, chunk, n);
230
+ if (chunk) c->env->DeleteLocalRef(chunk);
231
+
232
+ if (!cont) {
233
+ c->cancelled = true;
234
+ return 0;
235
+ }
236
+ return 1;
237
+ };
238
+
239
+ const SherpaOnnxGeneratedAudio* audio =
240
+ SherpaOnnxOfflineTtsGenerateWithProgressCallbackWithArg(
241
+ tts, text.get(), sid, speed, callback, &ctx);
242
+
243
+ if (!audio) {
244
+ LOGE("nativeGenerateWithCallback: generate returned null");
245
+ return nullptr;
246
+ }
247
+
248
+ jobjectArray result = buildAudioResult(env, audio->samples, audio->n, audio->sample_rate);
249
+ SherpaOnnxDestroyOfflineTtsGeneratedAudio(audio);
250
+ return result;
251
+ }
252
+
253
+ // Zero-shot voice cloning with Zipvoice. Returns Object[] { float[], Integer }.
254
+ JNIEXPORT jobjectArray JNICALL
255
+ Java_com_sherpaonnx_ZipvoiceTtsWrapper_nativeGenerateWithZipvoice(
256
+ JNIEnv* env, jobject /* this */,
257
+ jlong ptr, jstring j_text, jstring j_prompt_text,
258
+ jfloatArray j_prompt_samples, jint prompt_sr,
259
+ jfloat speed, jint num_steps) {
260
+ auto* tts = reinterpret_cast<const SherpaOnnxOfflineTts*>(ptr);
261
+ if (!tts) {
262
+ LOGE("nativeGenerateWithZipvoice: tts pointer is null");
263
+ return nullptr;
264
+ }
265
+
266
+ JStringGuard text(env, j_text);
267
+ JStringGuard promptText(env, j_prompt_text);
268
+
269
+ jfloat* promptSamples = nullptr;
270
+ jint nPrompt = 0;
271
+ if (j_prompt_samples) {
272
+ nPrompt = env->GetArrayLength(j_prompt_samples);
273
+ promptSamples = env->GetFloatArrayElements(j_prompt_samples, nullptr);
274
+ }
275
+
276
+ LOGI("nativeGenerateWithZipvoice: text=%s, promptLen=%d, promptSr=%d, speed=%.2f, steps=%d",
277
+ text.get(), nPrompt, prompt_sr, speed, num_steps);
278
+
279
+ const SherpaOnnxGeneratedAudio* audio =
280
+ SherpaOnnxOfflineTtsGenerateWithZipvoice(
281
+ tts, text.get(), promptText.get(),
282
+ promptSamples, nPrompt, prompt_sr,
283
+ speed, num_steps);
284
+
285
+ if (promptSamples) {
286
+ env->ReleaseFloatArrayElements(j_prompt_samples, promptSamples, JNI_ABORT);
287
+ }
288
+
289
+ if (!audio) {
290
+ LOGE("nativeGenerateWithZipvoice: returned null");
291
+ return nullptr;
292
+ }
293
+
294
+ LOGI("nativeGenerateWithZipvoice: got %d samples at %d Hz", audio->n, audio->sample_rate);
295
+ jobjectArray result = buildAudioResult(env, audio->samples, audio->n, audio->sample_rate);
296
+
297
+ SherpaOnnxDestroyOfflineTtsGeneratedAudio(audio);
298
+ return result;
299
+ }
300
+
301
+ } // extern "C"
@@ -0,0 +1,94 @@
1
+ package com.sherpaonnx
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.Promise
5
+ import java.util.concurrent.ExecutorService
6
+ import java.util.concurrent.Executors
7
+ import java.util.concurrent.atomic.AtomicBoolean
8
+
9
+ /**
10
+ * Archive extraction helper using native libarchive for fast .tar.bz2 extraction.
11
+ * This class delegates to C++ native implementation via JNI.
12
+ */
13
+ class SherpaOnnxArchiveHelper {
14
+ private val cancelRequested = AtomicBoolean(false)
15
+
16
+ companion object {
17
+ /** Single-thread executor so extractions run off the React Native bridge thread and do not block listDownloadedModelsByCategory / RNFS. */
18
+ private val extractExecutor: ExecutorService = Executors.newSingleThreadExecutor()
19
+
20
+ init {
21
+ try {
22
+ System.loadLibrary("sherpaonnx")
23
+ } catch (e: UnsatisfiedLinkError) {
24
+ throw RuntimeException("Failed to load sherpaonnx library: ${e.message}")
25
+ }
26
+ }
27
+ }
28
+
29
+ fun cancelExtractTarBz2() {
30
+ cancelRequested.set(true)
31
+ nativeCancelExtract()
32
+ }
33
+
34
+ fun extractTarBz2(
35
+ sourcePath: String,
36
+ targetPath: String,
37
+ force: Boolean,
38
+ promise: Promise,
39
+ onProgress: (bytes: Long, totalBytes: Long, percent: Double) -> Unit
40
+ ) {
41
+ val promiseSettled = AtomicBoolean(false)
42
+ fun resolveOnce(success: Boolean, reason: String? = null) {
43
+ if (!promiseSettled.compareAndSet(false, true)) return
44
+ val result = Arguments.createMap()
45
+ result.putBoolean("success", success)
46
+ if (reason != null) result.putString("reason", reason)
47
+ promise.resolve(result)
48
+ }
49
+
50
+ try {
51
+ cancelRequested.set(false)
52
+
53
+ // Create a progress callback object that JNI can call
54
+ val progressCallback = object : Any() {
55
+ fun invoke(bytesExtracted: Long, totalBytes: Long, percent: Double) {
56
+ onProgress(bytesExtracted, totalBytes, percent)
57
+ }
58
+ }
59
+
60
+ // Run extraction on a background thread so the React Native bridge thread is not blocked.
61
+ // Otherwise listDownloadedModelsByCategory (RNFS) and other native calls would wait until extraction finishes.
62
+ extractExecutor.execute {
63
+ try {
64
+ nativeExtractTarBz2(sourcePath, targetPath, force, progressCallback, promise)
65
+ } catch (e: Exception) {
66
+ resolveOnce(false, "Archive extraction error: ${e.message}")
67
+ }
68
+ }
69
+ } catch (e: Exception) {
70
+ resolveOnce(false, "Archive extraction error: ${e.message}")
71
+ }
72
+ }
73
+
74
+ fun computeFileSha256(filePath: String, promise: Promise) {
75
+ nativeComputeFileSha256(filePath, promise)
76
+ }
77
+
78
+ // Native JNI methods
79
+ private external fun nativeExtractTarBz2(
80
+ sourcePath: String,
81
+ targetPath: String,
82
+ force: Boolean,
83
+ progressCallback: Any?,
84
+ promise: Promise
85
+ )
86
+
87
+ private external fun nativeCancelExtract()
88
+
89
+ private external fun nativeComputeFileSha256(
90
+ filePath: String,
91
+ promise: Promise
92
+ )
93
+ }
94
+