react-native-sherpa-onnx 0.3.5 → 0.3.7
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/LICENSE +1 -0
- package/README.md +90 -21
- package/SherpaOnnx.podspec +3 -0
- package/THIRD_PARTY_LICENSES/README.md +62 -0
- package/THIRD_PARTY_LICENSES/ffmpeg.txt +502 -0
- package/THIRD_PARTY_LICENSES/libarchive.txt +65 -0
- package/THIRD_PARTY_LICENSES/nvidia_omla.txt +181 -0
- package/THIRD_PARTY_LICENSES/onnxruntime.txt +21 -0
- package/THIRD_PARTY_LICENSES/opus.txt +44 -0
- package/THIRD_PARTY_LICENSES/sherpa-onnx.txt +201 -0
- package/THIRD_PARTY_LICENSES/shine.txt +482 -0
- package/THIRD_PARTY_LICENSES/zstd.txt +30 -0
- package/android/build.gradle +7 -3
- package/android/prebuilt-download.gradle +345 -153
- package/android/prebuilt-versions.gradle +2 -2
- package/android/src/main/assets/model_licenses/asr-models-license-status.csv +409 -0
- package/android/src/main/assets/model_licenses/qnn-asr-models-license-status.csv +695 -0
- package/android/src/main/assets/model_licenses/tts-models-license-status.csv +596 -0
- package/android/src/main/cpp/CMakeLists.txt +28 -10
- 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/cpp/jni/audio/sherpa-onnx-audio-convert-jni.cpp +268 -2
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-tts.cpp +6 -2
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-tts.cpp +4 -2
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxArchiveHelper.kt +137 -7
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxAssetHelper.kt +51 -6
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +159 -0
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxOnlineSttHelper.kt +4 -1
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxTtsHelper.kt +112 -97
- package/ios/Resources/model_licenses/asr-models-license-status.csv +409 -0
- package/ios/Resources/model_licenses/qnn-asr-models-license-status.csv +695 -0
- package/ios/Resources/model_licenses/tts-models-license-status.csv +596 -0
- package/ios/SherpaOnnx+OnlineSTT.mm +2 -0
- package/ios/SherpaOnnx+PcmLiveStream.mm +2 -29
- package/ios/SherpaOnnx+TTS.mm +178 -20
- package/ios/SherpaOnnx.mm +108 -1
- package/ios/SherpaOnnxAudioConvert.h +10 -0
- package/ios/SherpaOnnxAudioConvert.mm +257 -1
- package/ios/archive/sherpa-onnx-archive-helper.h +10 -0
- package/ios/archive/sherpa-onnx-archive-helper.mm +56 -5
- package/ios/model_detect/sherpa-onnx-model-detect-tts.mm +13 -2
- package/ios/model_detect/sherpa-onnx-validate-tts.mm +4 -2
- package/ios/online_stt/sherpa-onnx-online-stt-wrapper.h +1 -0
- package/ios/online_stt/sherpa-onnx-online-stt-wrapper.mm +4 -0
- package/ios/tts/sherpa-onnx-tts-wrapper.h +37 -0
- package/ios/tts/sherpa-onnx-tts-wrapper.mm +149 -3
- package/lib/module/NativeSherpaOnnx.js.map +1 -1
- package/lib/module/audio/index.js +8 -0
- package/lib/module/audio/index.js.map +1 -1
- package/lib/module/download/ModelDownloadManager.js +10 -929
- package/lib/module/download/ModelDownloadManager.js.map +1 -1
- package/lib/module/download/activeModelOperations.js +26 -0
- package/lib/module/download/activeModelOperations.js.map +1 -0
- package/lib/module/download/background-downloader.d.js +2 -0
- package/lib/module/download/background-downloader.d.js.map +1 -0
- package/lib/module/download/bulkPurge.js +72 -0
- package/lib/module/download/bulkPurge.js.map +1 -0
- package/lib/module/download/checksumPrompt.js +19 -0
- package/lib/module/download/checksumPrompt.js.map +1 -0
- package/lib/module/download/constants.js +7 -0
- package/lib/module/download/constants.js.map +1 -0
- package/lib/module/download/downloadEvents.js +35 -0
- package/lib/module/download/downloadEvents.js.map +1 -0
- package/lib/module/download/downloadTask.js +385 -0
- package/lib/module/download/downloadTask.js.map +1 -0
- package/lib/module/download/ensureModel.js +89 -0
- package/lib/module/download/ensureModel.js.map +1 -0
- package/lib/module/download/index.js +4 -3
- package/lib/module/download/index.js.map +1 -1
- package/lib/module/download/localModels.js +151 -0
- package/lib/module/download/localModels.js.map +1 -0
- package/lib/module/download/modelExtraction.js +174 -0
- package/lib/module/download/modelExtraction.js.map +1 -0
- package/lib/module/download/paths.js +98 -0
- package/lib/module/download/paths.js.map +1 -0
- package/lib/module/download/postDownloadProcessing.js +206 -0
- package/lib/module/download/postDownloadProcessing.js.map +1 -0
- package/lib/module/download/protectedModelKeys.js +31 -0
- package/lib/module/download/protectedModelKeys.js.map +1 -0
- package/lib/module/download/registry.js +267 -0
- package/lib/module/download/registry.js.map +1 -0
- package/lib/module/download/retry.js +59 -0
- package/lib/module/download/retry.js.map +1 -0
- package/lib/module/download/types.js +17 -0
- package/lib/module/download/types.js.map +1 -0
- package/lib/module/download/validation.js +101 -5
- package/lib/module/download/validation.js.map +1 -1
- package/lib/module/{download → extraction}/extractTarBz2.js +3 -1
- package/lib/module/extraction/extractTarBz2.js.map +1 -0
- package/lib/module/extraction/extractTarZst.js +54 -0
- package/lib/module/extraction/extractTarZst.js.map +1 -0
- package/lib/module/extraction/index.js +190 -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 +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/licenses.js +63 -0
- package/lib/module/licenses.js.map +1 -0
- package/lib/module/stt/index.js +16 -2
- package/lib/module/stt/index.js.map +1 -1
- package/lib/module/stt/streaming.js +2 -0
- package/lib/module/stt/streaming.js.map +1 -1
- package/lib/module/stt/streamingTypes.js.map +1 -1
- package/lib/module/stt/types.js.map +1 -1
- package/lib/module/tts/index.js +20 -2
- package/lib/module/tts/index.js.map +1 -1
- package/lib/module/tts/streaming.js +4 -0
- package/lib/module/tts/streaming.js.map +1 -1
- package/lib/module/tts/types.js.map +1 -1
- package/lib/module/utils.js +16 -1
- package/lib/module/utils.js.map +1 -1
- package/lib/typescript/src/NativeSherpaOnnx.d.ts +72 -5
- package/lib/typescript/src/NativeSherpaOnnx.d.ts.map +1 -1
- package/lib/typescript/src/audio/index.d.ts +10 -0
- package/lib/typescript/src/audio/index.d.ts.map +1 -1
- package/lib/typescript/src/download/ModelDownloadManager.d.ts +10 -108
- package/lib/typescript/src/download/ModelDownloadManager.d.ts.map +1 -1
- package/lib/typescript/src/download/activeModelOperations.d.ts +6 -0
- package/lib/typescript/src/download/activeModelOperations.d.ts.map +1 -0
- package/lib/typescript/src/download/bulkPurge.d.ts +14 -0
- package/lib/typescript/src/download/bulkPurge.d.ts.map +1 -0
- package/lib/typescript/src/download/checksumPrompt.d.ts +3 -0
- package/lib/typescript/src/download/checksumPrompt.d.ts.map +1 -0
- package/lib/typescript/src/download/constants.d.ts +5 -0
- package/lib/typescript/src/download/constants.d.ts.map +1 -0
- package/lib/typescript/src/download/downloadEvents.d.ts +6 -0
- package/lib/typescript/src/download/downloadEvents.d.ts.map +1 -0
- package/lib/typescript/src/download/downloadTask.d.ts +20 -0
- package/lib/typescript/src/download/downloadTask.d.ts.map +1 -0
- package/lib/typescript/src/download/ensureModel.d.ts +26 -0
- package/lib/typescript/src/download/ensureModel.d.ts.map +1 -0
- package/lib/typescript/src/download/index.d.ts +7 -5
- package/lib/typescript/src/download/index.d.ts.map +1 -1
- package/lib/typescript/src/download/localModels.d.ts +15 -0
- package/lib/typescript/src/download/localModels.d.ts.map +1 -0
- package/lib/typescript/src/download/modelExtraction.d.ts +36 -0
- package/lib/typescript/src/download/modelExtraction.d.ts.map +1 -0
- package/lib/typescript/src/download/paths.d.ts +28 -0
- package/lib/typescript/src/download/paths.d.ts.map +1 -0
- package/lib/typescript/src/download/postDownloadProcessing.d.ts +19 -0
- package/lib/typescript/src/download/postDownloadProcessing.d.ts.map +1 -0
- package/lib/typescript/src/download/protectedModelKeys.d.ts +6 -0
- package/lib/typescript/src/download/protectedModelKeys.d.ts.map +1 -0
- package/lib/typescript/src/download/registry.d.ts +14 -0
- package/lib/typescript/src/download/registry.d.ts.map +1 -0
- package/lib/typescript/src/download/retry.d.ts +15 -0
- package/lib/typescript/src/download/retry.d.ts.map +1 -0
- package/lib/typescript/src/download/types.d.ts +96 -0
- package/lib/typescript/src/download/types.d.ts.map +1 -0
- package/lib/typescript/src/download/validation.d.ts +19 -0
- package/lib/typescript/src/download/validation.d.ts.map +1 -1
- package/lib/typescript/src/extraction/extractTarBz2.d.ts.map +1 -0
- package/lib/typescript/src/extraction/extractTarZst.d.ts +14 -0
- package/lib/typescript/src/extraction/extractTarZst.d.ts.map +1 -0
- 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 +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/licenses.d.ts +10 -0
- package/lib/typescript/src/licenses.d.ts.map +1 -0
- package/lib/typescript/src/stt/index.d.ts +4 -1
- package/lib/typescript/src/stt/index.d.ts.map +1 -1
- package/lib/typescript/src/stt/streaming.d.ts.map +1 -1
- package/lib/typescript/src/stt/streamingTypes.d.ts +5 -0
- package/lib/typescript/src/stt/streamingTypes.d.ts.map +1 -1
- package/lib/typescript/src/stt/types.d.ts +3 -1
- package/lib/typescript/src/stt/types.d.ts.map +1 -1
- package/lib/typescript/src/tts/index.d.ts +3 -1
- package/lib/typescript/src/tts/index.d.ts.map +1 -1
- package/lib/typescript/src/tts/streaming.d.ts.map +1 -1
- package/lib/typescript/src/tts/types.d.ts +6 -5
- package/lib/typescript/src/tts/types.d.ts.map +1 -1
- package/lib/typescript/src/utils.d.ts +5 -0
- package/lib/typescript/src/utils.d.ts.map +1 -1
- package/package.json +11 -1
- package/scripts/{check-model-csvs.sh → ci/check-model-csvs.sh} +9 -2
- package/scripts/ci/collect_all_sherpa_model_streams.sh +101 -0
- package/scripts/ci/collect_one_sherpa_release_stream.sh +189 -0
- package/scripts/ci/sherpa_asr_model_release_streams.json +21 -0
- package/scripts/ci/sherpa_tts_model_release_streams.json +13 -0
- package/scripts/ci/update_model_license_csv.sh +765 -0
- package/scripts/setup-ios-framework.sh +14 -11
- package/scripts/update_commercial_use.js +73 -0
- package/src/NativeSherpaOnnx.ts +92 -5
- package/src/audio/index.ts +20 -0
- package/src/download/ModelDownloadManager.ts +55 -1343
- package/src/download/activeModelOperations.ts +38 -0
- package/src/download/background-downloader.d.ts +43 -0
- package/src/download/bulkPurge.ts +102 -0
- package/src/download/checksumPrompt.ts +25 -0
- package/src/download/constants.ts +5 -0
- package/src/download/downloadEvents.ts +55 -0
- package/src/download/downloadTask.ts +497 -0
- package/src/download/ensureModel.ts +124 -0
- package/src/download/index.ts +19 -2
- package/src/download/localModels.ts +234 -0
- package/src/download/modelExtraction.ts +244 -0
- package/src/download/paths.ts +134 -0
- package/src/download/postDownloadProcessing.ts +292 -0
- package/src/download/protectedModelKeys.ts +30 -0
- package/src/download/registry.ts +404 -0
- package/src/download/retry.ts +76 -0
- package/src/download/types.ts +120 -0
- package/src/download/validation.ts +114 -8
- package/src/{download → extraction}/extractTarBz2.ts +3 -1
- package/src/extraction/extractTarZst.ts +79 -0
- package/src/extraction/index.ts +269 -0
- package/src/extraction/types.ts +63 -0
- package/src/index.tsx +2 -0
- package/src/licenses.ts +100 -0
- package/src/stt/index.ts +20 -2
- package/src/stt/streaming.ts +3 -0
- package/src/stt/streamingTypes.ts +5 -0
- package/src/stt/types.ts +3 -1
- package/src/tts/index.ts +30 -2
- package/src/tts/streaming.ts +10 -0
- package/src/tts/types.ts +6 -5
- package/src/utils.ts +22 -1
- package/third_party/libarchive_prebuilt/ANDROID_RELEASE_TAG +1 -1
- package/third_party/libarchive_prebuilt/IOS_RELEASE_TAG +1 -1
- package/third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG +1 -1
- package/third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG +1 -1
- package/android/src/main/cpp/jni/tts/sherpa-onnx-tts-zipvoice-jni.cpp +0 -301
- package/android/src/main/java/com/sherpaonnx/ZipvoiceTtsWrapper.kt +0 -187
- package/lib/module/download/extractTarBz2.js.map +0 -1
- package/lib/typescript/src/download/extractTarBz2.d.ts.map +0 -1
- package/scripts/check-qnn-support.sh +0 -78
- /package/lib/typescript/src/{download → extraction}/extractTarBz2.d.ts +0 -0
|
@@ -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();
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
#include <jni.h>
|
|
10
10
|
#include <string>
|
|
11
11
|
#include <sys/stat.h>
|
|
12
|
+
#include <vector>
|
|
12
13
|
|
|
13
14
|
#define LOG_TAG "AudioConvertJNI"
|
|
14
15
|
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
|
@@ -24,11 +25,14 @@ extern "C" {
|
|
|
24
25
|
#include <libswresample/swresample.h>
|
|
25
26
|
}
|
|
26
27
|
#include <cstdio>
|
|
27
|
-
#include <vector>
|
|
28
28
|
#endif
|
|
29
29
|
|
|
30
30
|
// Forward declaration — convertToFormat handles all formats including WAV (16 kHz mono).
|
|
31
31
|
static std::string convertToFormat(const char* inputPath, const char* outputPath, const char* formatHint, int outputSampleRateHz);
|
|
32
|
+
static std::string decodeAudioFileToFloatMono(const char* inputPath,
|
|
33
|
+
int targetSampleRateHz,
|
|
34
|
+
std::vector<float>* outSamples,
|
|
35
|
+
int* outSampleRate);
|
|
32
36
|
|
|
33
37
|
// Convenience: convert any audio to 16 kHz mono WAV via the main convertToFormat pipeline.
|
|
34
38
|
static std::string convertToWav16kMono(const char* inputPath, const char* outputPath) {
|
|
@@ -614,7 +618,8 @@ static std::string convertToFormat(const char* inputPath, const char* outputPath
|
|
|
614
618
|
av_packet_unref(pkt);
|
|
615
619
|
continue;
|
|
616
620
|
}
|
|
617
|
-
|
|
621
|
+
const uint8_t* const* in_data = frame->extended_data ? frame->extended_data : frame->data;
|
|
622
|
+
int converted = swr_convert(swr, outData, (int)out_nb_samples, in_data, frame->nb_samples);
|
|
618
623
|
if (converted <= 0) {
|
|
619
624
|
av_freep(&outData[0]);
|
|
620
625
|
av_freep(&outData);
|
|
@@ -701,6 +706,204 @@ static std::string convertToFormat(const char* inputPath, const char* outputPath
|
|
|
701
706
|
#endif
|
|
702
707
|
}
|
|
703
708
|
|
|
709
|
+
// Decode any FFmpeg-supported audio to mono float PCM in [-1,1] (clipping not applied) at outSampleRate.
|
|
710
|
+
static std::string decodeAudioFileToFloatMono(const char* inputPath,
|
|
711
|
+
int targetSampleRateHz,
|
|
712
|
+
std::vector<float>* outSamples,
|
|
713
|
+
int* outSampleRate) {
|
|
714
|
+
outSamples->clear();
|
|
715
|
+
*outSampleRate = 0;
|
|
716
|
+
#ifndef HAVE_FFMPEG
|
|
717
|
+
(void)inputPath;
|
|
718
|
+
(void)targetSampleRateHz;
|
|
719
|
+
return std::string("FFmpeg not available. Build prebuilts with third_party/ffmpeg_prebuilt/build_ffmpeg.ps1 or build_ffmpeg.sh.");
|
|
720
|
+
#else
|
|
721
|
+
if (!inputPath) {
|
|
722
|
+
return std::string("inputPath is null");
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
AVFormatContext* inFmt = nullptr;
|
|
726
|
+
if (avformat_open_input(&inFmt, inputPath, nullptr, nullptr) < 0) {
|
|
727
|
+
LOGE("decodeAudioFileToFloatMono: failed to open inputPath=%s", inputPath);
|
|
728
|
+
return std::string("Failed to open input file");
|
|
729
|
+
}
|
|
730
|
+
if (avformat_find_stream_info(inFmt, nullptr) < 0) {
|
|
731
|
+
avformat_close_input(&inFmt);
|
|
732
|
+
return std::string("Failed to find stream info");
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
int audioStreamIndex = -1;
|
|
736
|
+
for (unsigned i = 0; i < inFmt->nb_streams; ++i) {
|
|
737
|
+
if (inFmt->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
|
|
738
|
+
audioStreamIndex = (int)i;
|
|
739
|
+
break;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
if (audioStreamIndex < 0) {
|
|
743
|
+
avformat_close_input(&inFmt);
|
|
744
|
+
return std::string("No audio stream found in input");
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
AVStream* inStream = inFmt->streams[audioStreamIndex];
|
|
748
|
+
const AVCodec* decoder = avcodec_find_decoder(inStream->codecpar->codec_id);
|
|
749
|
+
if (!decoder) {
|
|
750
|
+
avformat_close_input(&inFmt);
|
|
751
|
+
return std::string("Unsupported input codec");
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
AVCodecContext* decCtx = avcodec_alloc_context3(decoder);
|
|
755
|
+
if (!decCtx) {
|
|
756
|
+
avformat_close_input(&inFmt);
|
|
757
|
+
return std::string("Failed to allocate decoder context");
|
|
758
|
+
}
|
|
759
|
+
if (avcodec_parameters_to_context(decCtx, inStream->codecpar) < 0) {
|
|
760
|
+
avcodec_free_context(&decCtx);
|
|
761
|
+
avformat_close_input(&inFmt);
|
|
762
|
+
return std::string("Failed to copy codec parameters");
|
|
763
|
+
}
|
|
764
|
+
if (avcodec_open2(decCtx, decoder, nullptr) < 0) {
|
|
765
|
+
avcodec_free_context(&decCtx);
|
|
766
|
+
avformat_close_input(&inFmt);
|
|
767
|
+
return std::string("Failed to open decoder");
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
int in_sr = decCtx->sample_rate;
|
|
771
|
+
if (inStream->codecpar->sample_rate > 0) {
|
|
772
|
+
in_sr = inStream->codecpar->sample_rate;
|
|
773
|
+
}
|
|
774
|
+
if (in_sr <= 0) {
|
|
775
|
+
avcodec_free_context(&decCtx);
|
|
776
|
+
avformat_close_input(&inFmt);
|
|
777
|
+
return std::string("Invalid input sample rate");
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
int out_sr = (targetSampleRateHz > 0) ? targetSampleRateHz : in_sr;
|
|
781
|
+
if (out_sr <= 0) {
|
|
782
|
+
avcodec_free_context(&decCtx);
|
|
783
|
+
avformat_close_input(&inFmt);
|
|
784
|
+
return std::string("Invalid output sample rate");
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
AVChannelLayout in_layout{};
|
|
788
|
+
if (inStream->codecpar->ch_layout.nb_channels > 0) {
|
|
789
|
+
if (av_channel_layout_copy(&in_layout, &inStream->codecpar->ch_layout) < 0) {
|
|
790
|
+
avcodec_free_context(&decCtx);
|
|
791
|
+
avformat_close_input(&inFmt);
|
|
792
|
+
return std::string("Failed to copy input channel layout");
|
|
793
|
+
}
|
|
794
|
+
} else {
|
|
795
|
+
if (av_channel_layout_copy(&in_layout, &decCtx->ch_layout) < 0) {
|
|
796
|
+
avcodec_free_context(&decCtx);
|
|
797
|
+
avformat_close_input(&inFmt);
|
|
798
|
+
return std::string("Failed to get decoder channel layout");
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
AVChannelLayout out_layout = AV_CHANNEL_LAYOUT_MONO;
|
|
803
|
+
SwrContext* swr = nullptr;
|
|
804
|
+
if (swr_alloc_set_opts2(&swr,
|
|
805
|
+
&out_layout,
|
|
806
|
+
AV_SAMPLE_FMT_FLT,
|
|
807
|
+
out_sr,
|
|
808
|
+
&in_layout,
|
|
809
|
+
decCtx->sample_fmt,
|
|
810
|
+
in_sr,
|
|
811
|
+
0,
|
|
812
|
+
nullptr) < 0 ||
|
|
813
|
+
!swr) {
|
|
814
|
+
av_channel_layout_uninit(&in_layout);
|
|
815
|
+
avcodec_free_context(&decCtx);
|
|
816
|
+
avformat_close_input(&inFmt);
|
|
817
|
+
return std::string("Failed to initialize resampler");
|
|
818
|
+
}
|
|
819
|
+
if (swr_init(swr) < 0) {
|
|
820
|
+
av_channel_layout_uninit(&in_layout);
|
|
821
|
+
swr_free(&swr);
|
|
822
|
+
avcodec_free_context(&decCtx);
|
|
823
|
+
avformat_close_input(&inFmt);
|
|
824
|
+
return std::string("Failed to initialize resampler (swr_init)");
|
|
825
|
+
}
|
|
826
|
+
av_channel_layout_uninit(&in_layout);
|
|
827
|
+
|
|
828
|
+
AVPacket* pkt = av_packet_alloc();
|
|
829
|
+
AVFrame* frame = av_frame_alloc();
|
|
830
|
+
if (!pkt || !frame) {
|
|
831
|
+
if (pkt) av_packet_free(&pkt);
|
|
832
|
+
if (frame) av_frame_free(&frame);
|
|
833
|
+
swr_free(&swr);
|
|
834
|
+
avcodec_free_context(&decCtx);
|
|
835
|
+
avformat_close_input(&inFmt);
|
|
836
|
+
return std::string("Out of memory");
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
auto appendConverted = [&](uint8_t* buf, int nbFloats) {
|
|
840
|
+
if (!buf || nbFloats <= 0) return;
|
|
841
|
+
const float* f = reinterpret_cast<const float*>(buf);
|
|
842
|
+
outSamples->insert(outSamples->end(), f, f + nbFloats);
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
auto convertOneFrame = [&](AVFrame* fr) {
|
|
846
|
+
const uint8_t* const* in_data = fr->extended_data ? fr->extended_data : fr->data;
|
|
847
|
+
int in_sr2 = inStream->codecpar->sample_rate ? inStream->codecpar->sample_rate : decCtx->sample_rate;
|
|
848
|
+
int64_t max_out =
|
|
849
|
+
av_rescale_rnd(swr_get_delay(swr, in_sr2) + (int64_t)fr->nb_samples, out_sr, in_sr2, AV_ROUND_UP);
|
|
850
|
+
if (max_out < 1) max_out = 1;
|
|
851
|
+
uint8_t* out_buf = nullptr;
|
|
852
|
+
if (av_samples_alloc(&out_buf, nullptr, 1, (int)max_out, AV_SAMPLE_FMT_FLT, 0) < 0) {
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
int converted = swr_convert(swr, &out_buf, (int)max_out, in_data, fr->nb_samples);
|
|
856
|
+
if (converted > 0) {
|
|
857
|
+
appendConverted(out_buf, converted);
|
|
858
|
+
}
|
|
859
|
+
av_freep(&out_buf);
|
|
860
|
+
};
|
|
861
|
+
|
|
862
|
+
while (av_read_frame(inFmt, pkt) >= 0) {
|
|
863
|
+
if (pkt->stream_index == audioStreamIndex) {
|
|
864
|
+
if (avcodec_send_packet(decCtx, pkt) == 0) {
|
|
865
|
+
while (avcodec_receive_frame(decCtx, frame) == 0) {
|
|
866
|
+
convertOneFrame(frame);
|
|
867
|
+
av_frame_unref(frame);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
av_packet_unref(pkt);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
if (avcodec_send_packet(decCtx, nullptr) == 0) {
|
|
875
|
+
while (avcodec_receive_frame(decCtx, frame) == 0) {
|
|
876
|
+
convertOneFrame(frame);
|
|
877
|
+
av_frame_unref(frame);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
{
|
|
882
|
+
int in_sr2 = inStream->codecpar->sample_rate ? inStream->codecpar->sample_rate : decCtx->sample_rate;
|
|
883
|
+
int tailCap = (int)swr_get_delay(swr, in_sr2) + 4096;
|
|
884
|
+
if (tailCap < 16) tailCap = 16;
|
|
885
|
+
uint8_t* tailData = nullptr;
|
|
886
|
+
if (av_samples_alloc(&tailData, nullptr, 1, tailCap, AV_SAMPLE_FMT_FLT, 0) >= 0) {
|
|
887
|
+
int tailConverted = swr_convert(swr, &tailData, tailCap, nullptr, 0);
|
|
888
|
+
if (tailConverted > 0) {
|
|
889
|
+
appendConverted(tailData, tailConverted);
|
|
890
|
+
}
|
|
891
|
+
av_freep(&tailData);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
av_packet_free(&pkt);
|
|
896
|
+
av_frame_free(&frame);
|
|
897
|
+
swr_free(&swr);
|
|
898
|
+
avcodec_free_context(&decCtx);
|
|
899
|
+
avformat_close_input(&inFmt);
|
|
900
|
+
|
|
901
|
+
*outSampleRate = out_sr;
|
|
902
|
+
LOGI("decodeAudioFileToFloatMono: samples=%zu sampleRate=%d", outSamples->size(), out_sr);
|
|
903
|
+
return std::string("");
|
|
904
|
+
#endif
|
|
905
|
+
}
|
|
906
|
+
|
|
704
907
|
extern "C" {
|
|
705
908
|
|
|
706
909
|
// Called from Kotlin: SherpaOnnxModule.nativeConvertAudioToWav16k(inputPath, outputPath) -> Boolean
|
|
@@ -759,4 +962,67 @@ Java_com_sherpaonnx_SherpaOnnxModule_nativeConvertAudioToFormat(
|
|
|
759
962
|
return env->NewStringUTF(err.c_str());
|
|
760
963
|
}
|
|
761
964
|
|
|
965
|
+
// Returns Object[]: on error [String message]; on success [float[] samples, Integer sampleRate].
|
|
966
|
+
JNIEXPORT jobjectArray JNICALL
|
|
967
|
+
Java_com_sherpaonnx_SherpaOnnxModule_nativeDecodeAudioFileToFloatSamples(JNIEnv* env,
|
|
968
|
+
jobject /* this */,
|
|
969
|
+
jstring inputPath,
|
|
970
|
+
jint targetSampleRateHz) {
|
|
971
|
+
jclass objectClass = env->FindClass("java/lang/Object");
|
|
972
|
+
if (!objectClass) {
|
|
973
|
+
return nullptr;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
auto makeError = [&](const char* msg) -> jobjectArray {
|
|
977
|
+
jobjectArray ret = env->NewObjectArray(1, objectClass, nullptr);
|
|
978
|
+
if (!ret) return nullptr;
|
|
979
|
+
jstring jmsg = env->NewStringUTF(msg);
|
|
980
|
+
env->SetObjectArrayElement(ret, 0, jmsg);
|
|
981
|
+
env->DeleteLocalRef(jmsg);
|
|
982
|
+
return ret;
|
|
983
|
+
};
|
|
984
|
+
|
|
985
|
+
if (inputPath == nullptr) {
|
|
986
|
+
return makeError("inputPath must be non-null");
|
|
987
|
+
}
|
|
988
|
+
const char* input = env->GetStringUTFChars(inputPath, nullptr);
|
|
989
|
+
if (input == nullptr) {
|
|
990
|
+
return makeError("Failed to get path string");
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
std::vector<float> samples;
|
|
994
|
+
int sampleRate = 0;
|
|
995
|
+
std::string err = decodeAudioFileToFloatMono(input, (int)targetSampleRateHz, &samples, &sampleRate);
|
|
996
|
+
env->ReleaseStringUTFChars(inputPath, input);
|
|
997
|
+
|
|
998
|
+
if (!err.empty()) {
|
|
999
|
+
return makeError(err.c_str());
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
jfloatArray jfloats = env->NewFloatArray((jsize)samples.size());
|
|
1003
|
+
if (!jfloats) {
|
|
1004
|
+
return makeError("Failed to allocate float array");
|
|
1005
|
+
}
|
|
1006
|
+
if (!samples.empty()) {
|
|
1007
|
+
env->SetFloatArrayRegion(jfloats, 0, (jsize)samples.size(), samples.data());
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
jobjectArray ret = env->NewObjectArray(2, objectClass, nullptr);
|
|
1011
|
+
if (!ret) {
|
|
1012
|
+
env->DeleteLocalRef(jfloats);
|
|
1013
|
+
return makeError("Failed to allocate result array");
|
|
1014
|
+
}
|
|
1015
|
+
env->SetObjectArrayElement(ret, 0, jfloats);
|
|
1016
|
+
|
|
1017
|
+
jclass intCls = env->FindClass("java/lang/Integer");
|
|
1018
|
+
jmethodID intCtor = env->GetMethodID(intCls, "<init>", "(I)V");
|
|
1019
|
+
jobject jrate = env->NewObject(intCls, intCtor, sampleRate);
|
|
1020
|
+
env->SetObjectArrayElement(ret, 1, jrate);
|
|
1021
|
+
|
|
1022
|
+
env->DeleteLocalRef(jfloats);
|
|
1023
|
+
env->DeleteLocalRef(jrate);
|
|
1024
|
+
env->DeleteLocalRef(intCls);
|
|
1025
|
+
return ret;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
762
1028
|
} // extern "C"
|
|
@@ -60,8 +60,8 @@ TtsModelKind ParseTtsModelType(const std::string& modelType) {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
/** Returns true if the given kind is supported by the current paths and hints (required files present).
|
|
63
|
-
* data_dir (espeak-ng-data) is required
|
|
64
|
-
* VITS
|
|
63
|
+
* data_dir (espeak-ng-data) is required for Kitten, Kokoro, and Zipvoice (Zipvoice uses MatchaTtsLexicon + espeak).
|
|
64
|
+
* VITS and Matcha use dataDir optionally in this detector; Pocket does not use it. */
|
|
65
65
|
static bool CapabilitySupportsTtsKind(
|
|
66
66
|
TtsModelKind kind,
|
|
67
67
|
bool hasVits,
|
|
@@ -128,6 +128,10 @@ static TtsDetectResult DetectTtsModelFromFiles(
|
|
|
128
128
|
std::string tokensFile = FindFileByName(files, "tokens.txt");
|
|
129
129
|
std::vector<LexiconCandidate> lexiconCandidates = FindLexiconCandidates(files, modelDir);
|
|
130
130
|
std::string dataDirPath = FindDirectoryUnderRoot(files, modelDir, "espeak-ng-data");
|
|
131
|
+
LOGI("DetectTtsModel: modelDir=%s espeak-ng dataDir=%s (empty=%d)",
|
|
132
|
+
modelDir.c_str(),
|
|
133
|
+
dataDirPath.empty() ? "(empty)" : dataDirPath.c_str(),
|
|
134
|
+
(int)dataDirPath.empty());
|
|
131
135
|
std::string voicesFile = FindFileByName(files, "voices.bin");
|
|
132
136
|
|
|
133
137
|
std::string acousticModel = FindOnnxByAnyToken(files, {"acoustic_model", "acoustic-model"}, std::nullopt);
|
|
@@ -55,8 +55,8 @@ static const TtsFieldRequirement kZipvoiceReqs[] = {
|
|
|
55
55
|
{"decoder", &TtsModelPaths::decoder, true},
|
|
56
56
|
{"vocoder", &TtsModelPaths::vocoder, true},
|
|
57
57
|
{"tokens", &TtsModelPaths::tokens, true},
|
|
58
|
-
{"dataDir", &TtsModelPaths::dataDir,
|
|
59
|
-
{"lexicon", &TtsModelPaths::lexicon,
|
|
58
|
+
{"dataDir", &TtsModelPaths::dataDir, true},
|
|
59
|
+
{"lexicon", &TtsModelPaths::lexicon, true},
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
// ============================================================
|
|
@@ -102,6 +102,8 @@ static const char* GetFieldHint(const char* fieldName) {
|
|
|
102
102
|
return "Copy espeak-ng-data into the model directory.";
|
|
103
103
|
if (std::strcmp(fieldName, "tokens") == 0)
|
|
104
104
|
return "Ensure tokens.txt is present in the model directory.";
|
|
105
|
+
if (std::strcmp(fieldName, "lexicon") == 0)
|
|
106
|
+
return "Add lexicon.txt (or lexicon-<lang>.txt) from the official sherpa-onnx Zipvoice/Matcha release; without it the native engine aborts.";
|
|
105
107
|
return nullptr;
|
|
106
108
|
}
|
|
107
109
|
|