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.
- package/README.md +232 -236
- package/SherpaOnnx.podspec +68 -64
- package/android/build.gradle +182 -192
- package/android/codegen.gradle +57 -0
- package/android/prebuilt-download.gradle +428 -0
- package/android/prebuilt-versions.gradle +43 -0
- package/android/proguard-rules.pro +10 -0
- package/android/src/main/assets/testModels/add_mul_add.onnx +28 -0
- package/android/src/main/assets/testModels/nnapi_internal_uint8_support.onnx +0 -0
- package/android/src/main/assets/testModels/qnn_multi_ctx_embed.onnx +0 -0
- package/android/src/main/cpp/CMakeLists.txt +166 -129
- package/android/src/main/cpp/CMakePresets.json +54 -0
- package/android/src/main/cpp/crypto/sha256.cpp +174 -0
- package/android/src/main/cpp/crypto/sha256.h +16 -0
- package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.cpp +404 -0
- package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.h +56 -0
- package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-jni.cpp +181 -0
- package/android/src/main/cpp/jni/audio/sherpa-onnx-audio-convert-jni.cpp +888 -0
- package/{ios → android/src/main/cpp/jni/model_detect}/sherpa-onnx-common.h +18 -18
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-detect-jni-common.cpp +86 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-detect-jni-common.h +20 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-helper.cpp +423 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-helper.h +55 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-stt.cpp +399 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-tts.cpp +238 -0
- package/{ios → android/src/main/cpp/jni/model_detect}/sherpa-onnx-model-detect.h +122 -89
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-stt-wrapper.cpp +99 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-stt-wrapper.h +16 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-tts-wrapper.cpp +78 -0
- package/android/src/main/cpp/jni/model_detect/sherpa-onnx-tts-wrapper.h +16 -0
- package/android/src/main/cpp/jni/module/sherpa-onnx-module-jni.cpp +190 -0
- package/android/src/main/cpp/jni/tts/sherpa-onnx-tts-zipvoice-jni.cpp +301 -0
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxArchiveHelper.kt +94 -0
- package/android/src/main/java/com/sherpaonnx/{SherpaOnnxCoreHelper.kt → SherpaOnnxAssetHelper.kt} +350 -236
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +791 -483
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxSttHelper.kt +699 -109
- package/android/src/main/java/com/sherpaonnx/SherpaOnnxTtsHelper.kt +1123 -668
- package/android/src/main/java/com/sherpaonnx/ZipvoiceTtsWrapper.kt +187 -0
- package/ios/SherpaOnnx+Assets.h +11 -0
- package/ios/SherpaOnnx+Assets.mm +325 -0
- package/ios/SherpaOnnx+STT.mm +455 -118
- package/ios/SherpaOnnx+TTS.mm +1101 -712
- package/ios/SherpaOnnx.h +17 -6
- package/ios/SherpaOnnx.mm +206 -311
- package/ios/SherpaOnnx.xcconfig +19 -19
- package/ios/SherpaOnnxCoreMLHelper.swift +24 -0
- package/ios/archive/sherpa-onnx-archive-helper.h +21 -0
- package/ios/archive/sherpa-onnx-archive-helper.mm +296 -0
- package/ios/libarchive_darwin_config.h +153 -0
- package/{android/src/main/cpp/jni → ios/model_detect}/sherpa-onnx-common.h +18 -18
- package/ios/model_detect/sherpa-onnx-model-detect-helper.h +49 -0
- package/ios/model_detect/sherpa-onnx-model-detect-helper.mm +210 -0
- package/ios/model_detect/sherpa-onnx-model-detect-stt.mm +344 -0
- package/ios/model_detect/sherpa-onnx-model-detect-tts.mm +201 -0
- package/{android/src/main/cpp/jni → ios/model_detect}/sherpa-onnx-model-detect.h +117 -89
- package/ios/scripts/patch-libarchive-includes.sh +61 -0
- package/ios/scripts/setup-ios-libarchive.sh +98 -0
- package/ios/stt/sherpa-onnx-stt-wrapper.h +129 -0
- package/ios/stt/sherpa-onnx-stt-wrapper.mm +523 -0
- package/ios/{sherpa-onnx-tts-wrapper.h → tts/sherpa-onnx-tts-wrapper.h} +90 -85
- package/ios/{sherpa-onnx-tts-wrapper.mm → tts/sherpa-onnx-tts-wrapper.mm} +376 -345
- package/lib/module/NativeSherpaOnnx.js +3 -0
- package/lib/module/NativeSherpaOnnx.js.map +1 -1
- package/lib/module/audio/index.js +22 -0
- package/lib/module/audio/index.js.map +1 -0
- package/lib/module/diarization/index.js +1 -1
- package/lib/module/diarization/index.js.map +1 -1
- package/lib/module/download/ModelDownloadManager.js +918 -0
- package/lib/module/download/ModelDownloadManager.js.map +1 -0
- package/lib/module/download/extractTarBz2.js +53 -0
- package/lib/module/download/extractTarBz2.js.map +1 -0
- package/lib/module/download/index.js +6 -0
- package/lib/module/download/index.js.map +1 -0
- package/lib/module/download/validation.js +178 -0
- package/lib/module/download/validation.js.map +1 -0
- package/lib/module/enhancement/index.js +1 -1
- package/lib/module/enhancement/index.js.map +1 -1
- package/lib/module/index.js +41 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/separation/index.js +1 -1
- package/lib/module/separation/index.js.map +1 -1
- package/lib/module/stt/index.js +127 -60
- package/lib/module/stt/index.js.map +1 -1
- package/lib/module/stt/sttModelLanguages.js +512 -0
- package/lib/module/stt/sttModelLanguages.js.map +1 -0
- package/lib/module/stt/types.js +53 -1
- package/lib/module/stt/types.js.map +1 -1
- package/lib/module/tts/index.js +216 -289
- package/lib/module/tts/index.js.map +1 -1
- package/lib/module/tts/types.js +86 -1
- package/lib/module/tts/types.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils.js +86 -73
- package/lib/module/utils.js.map +1 -1
- package/lib/module/vad/index.js +1 -1
- package/lib/module/vad/index.js.map +1 -1
- package/lib/typescript/src/NativeSherpaOnnx.d.ts +192 -38
- package/lib/typescript/src/NativeSherpaOnnx.d.ts.map +1 -1
- package/lib/typescript/src/audio/index.d.ts +13 -0
- package/lib/typescript/src/audio/index.d.ts.map +1 -0
- package/lib/typescript/src/diarization/index.d.ts +3 -2
- package/lib/typescript/src/diarization/index.d.ts.map +1 -1
- package/lib/typescript/src/download/ModelDownloadManager.d.ts +108 -0
- package/lib/typescript/src/download/ModelDownloadManager.d.ts.map +1 -0
- package/lib/typescript/src/download/extractTarBz2.d.ts +14 -0
- package/lib/typescript/src/download/extractTarBz2.d.ts.map +1 -0
- package/lib/typescript/src/download/index.d.ts +7 -0
- package/lib/typescript/src/download/index.d.ts.map +1 -0
- package/lib/typescript/src/download/validation.d.ts +57 -0
- package/lib/typescript/src/download/validation.d.ts.map +1 -0
- package/lib/typescript/src/enhancement/index.d.ts +3 -2
- package/lib/typescript/src/enhancement/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +26 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/separation/index.d.ts +3 -2
- package/lib/typescript/src/separation/index.d.ts.map +1 -1
- package/lib/typescript/src/stt/index.d.ts +31 -43
- package/lib/typescript/src/stt/index.d.ts.map +1 -1
- package/lib/typescript/src/stt/sttModelLanguages.d.ts +52 -0
- package/lib/typescript/src/stt/sttModelLanguages.d.ts.map +1 -0
- package/lib/typescript/src/stt/types.d.ts +196 -9
- package/lib/typescript/src/stt/types.d.ts.map +1 -1
- package/lib/typescript/src/tts/index.d.ts +25 -211
- package/lib/typescript/src/tts/index.d.ts.map +1 -1
- package/lib/typescript/src/tts/types.d.ts +148 -25
- package/lib/typescript/src/tts/types.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +0 -32
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils.d.ts +28 -13
- package/lib/typescript/src/utils.d.ts.map +1 -1
- package/lib/typescript/src/vad/index.d.ts +3 -2
- package/lib/typescript/src/vad/index.d.ts.map +1 -1
- package/package.json +250 -222
- package/scripts/check-qnn-support.sh +78 -0
- package/scripts/setup-ios-framework.sh +379 -282
- package/src/NativeSherpaOnnx.ts +474 -251
- package/src/audio/index.ts +32 -0
- package/src/diarization/index.ts +4 -2
- package/src/download/ModelDownloadManager.ts +1325 -0
- package/src/download/extractTarBz2.ts +78 -0
- package/src/download/index.ts +43 -0
- package/src/download/validation.ts +279 -0
- package/src/enhancement/index.ts +4 -2
- package/src/index.tsx +78 -27
- package/src/separation/index.ts +4 -2
- package/src/stt/index.ts +249 -89
- package/src/stt/sttModelLanguages.ts +237 -0
- package/src/stt/types.ts +263 -9
- package/src/tts/index.ts +470 -458
- package/src/tts/types.ts +373 -218
- package/src/types.ts +0 -44
- package/src/utils.ts +145 -131
- package/src/vad/index.ts +4 -2
- package/third_party/ffmpeg_prebuilt/ANDROID_RELEASE_TAG +1 -0
- package/third_party/libarchive_prebuilt/ANDROID_RELEASE_TAG +1 -0
- package/third_party/libarchive_prebuilt/IOS_RELEASE_TAG +1 -0
- package/third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG +1 -0
- package/third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG +1 -0
- package/android/src/main/cpp/include/sherpa-onnx/c-api/c-api.h +0 -1918
- package/android/src/main/cpp/include/sherpa-onnx/c-api/cxx-api.h +0 -841
- package/android/src/main/cpp/jni/sherpa-onnx-model-detect.cpp +0 -541
- package/android/src/main/cpp/jni/sherpa-onnx-stt-jni.cpp +0 -336
- package/android/src/main/cpp/jni/sherpa-onnx-stt-wrapper.cpp +0 -222
- package/android/src/main/cpp/jni/sherpa-onnx-stt-wrapper.h +0 -68
- package/android/src/main/cpp/jni/sherpa-onnx-tts-jni.cpp +0 -823
- package/android/src/main/cpp/jni/sherpa-onnx-tts-wrapper.cpp +0 -387
- package/android/src/main/cpp/jni/sherpa-onnx-tts-wrapper.h +0 -147
- package/ios/Frameworks/sherpa_onnx.xcframework.zip +0 -0
- package/ios/include/sherpa-onnx/c-api/c-api.h +0 -1918
- package/ios/include/sherpa-onnx/c-api/cxx-api.h +0 -841
- package/ios/sherpa-onnx-model-detect.mm +0 -441
- package/ios/sherpa-onnx-stt-wrapper.h +0 -48
- package/ios/sherpa-onnx-stt-wrapper.mm +0 -201
- package/scripts/copy-headers.js +0 -184
- package/scripts/setup-assets.js +0 -323
|
@@ -1,823 +0,0 @@
|
|
|
1
|
-
// Include standard library headers first to avoid conflicts with jni.h
|
|
2
|
-
#include <atomic>
|
|
3
|
-
#include <cmath>
|
|
4
|
-
#include <memory>
|
|
5
|
-
#include <sstream>
|
|
6
|
-
#include <string>
|
|
7
|
-
#include <vector>
|
|
8
|
-
|
|
9
|
-
// Then include JNI headers
|
|
10
|
-
#include <android/log.h>
|
|
11
|
-
#include <jni.h>
|
|
12
|
-
|
|
13
|
-
// TTS wrapper
|
|
14
|
-
#include "sherpa-onnx-tts-wrapper.h"
|
|
15
|
-
|
|
16
|
-
#define LOG_TAG "SherpaOnnxJNI"
|
|
17
|
-
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
|
18
|
-
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
|
19
|
-
|
|
20
|
-
using namespace sherpaonnx;
|
|
21
|
-
|
|
22
|
-
namespace {
|
|
23
|
-
std::vector<std::string> SplitTtsTokens(const std::string &text) {
|
|
24
|
-
std::vector<std::string> tokens;
|
|
25
|
-
std::istringstream iss(text);
|
|
26
|
-
std::string token;
|
|
27
|
-
while (iss >> token) {
|
|
28
|
-
tokens.push_back(token);
|
|
29
|
-
}
|
|
30
|
-
if (tokens.empty() && !text.empty()) {
|
|
31
|
-
tokens.push_back(text);
|
|
32
|
-
}
|
|
33
|
-
return tokens;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Global TTS wrapper instance
|
|
38
|
-
static std::unique_ptr<TtsWrapper> g_tts_wrapper = nullptr;
|
|
39
|
-
static std::atomic<bool> g_tts_stream_cancelled{false};
|
|
40
|
-
static std::atomic<uint64_t> g_tts_active_stream_id{0};
|
|
41
|
-
|
|
42
|
-
extern "C" {
|
|
43
|
-
|
|
44
|
-
JNIEXPORT jobject JNICALL
|
|
45
|
-
Java_com_sherpaonnx_SherpaOnnxModule_nativeTtsInitialize(
|
|
46
|
-
JNIEnv *env,
|
|
47
|
-
jobject /* this */,
|
|
48
|
-
jstring modelDir,
|
|
49
|
-
jstring modelType,
|
|
50
|
-
jint numThreads,
|
|
51
|
-
jboolean debug,
|
|
52
|
-
jdouble noiseScale,
|
|
53
|
-
jdouble noiseScaleW,
|
|
54
|
-
jdouble lengthScale) {
|
|
55
|
-
try {
|
|
56
|
-
if (g_tts_wrapper == nullptr) {
|
|
57
|
-
g_tts_wrapper = std::make_unique<TtsWrapper>();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const char *modelDirStr = env->GetStringUTFChars(modelDir, nullptr);
|
|
61
|
-
if (modelDirStr == nullptr) {
|
|
62
|
-
LOGE("TTS JNI: Failed to get modelDir string from JNI");
|
|
63
|
-
return nullptr;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const char *modelTypeStr = env->GetStringUTFChars(modelType, nullptr);
|
|
67
|
-
if (modelTypeStr == nullptr) {
|
|
68
|
-
LOGE("TTS JNI: Failed to get modelType string from JNI");
|
|
69
|
-
env->ReleaseStringUTFChars(modelDir, modelDirStr);
|
|
70
|
-
return nullptr;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
std::string modelDirPath(modelDirStr);
|
|
74
|
-
std::string modelTypePath(modelTypeStr);
|
|
75
|
-
|
|
76
|
-
std::optional<float> noiseScaleOpt = std::nullopt;
|
|
77
|
-
std::optional<float> noiseScaleWOpt = std::nullopt;
|
|
78
|
-
std::optional<float> lengthScaleOpt = std::nullopt;
|
|
79
|
-
if (!std::isnan(noiseScale)) {
|
|
80
|
-
noiseScaleOpt = static_cast<float>(noiseScale);
|
|
81
|
-
}
|
|
82
|
-
if (!std::isnan(noiseScaleW)) {
|
|
83
|
-
noiseScaleWOpt = static_cast<float>(noiseScaleW);
|
|
84
|
-
}
|
|
85
|
-
if (!std::isnan(lengthScale)) {
|
|
86
|
-
lengthScaleOpt = static_cast<float>(lengthScale);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
TtsInitializeResult result = g_tts_wrapper->initialize(
|
|
90
|
-
modelDirPath,
|
|
91
|
-
modelTypePath,
|
|
92
|
-
static_cast<int32_t>(numThreads),
|
|
93
|
-
debug == JNI_TRUE,
|
|
94
|
-
noiseScaleOpt,
|
|
95
|
-
noiseScaleWOpt,
|
|
96
|
-
lengthScaleOpt
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
env->ReleaseStringUTFChars(modelDir, modelDirStr);
|
|
100
|
-
env->ReleaseStringUTFChars(modelType, modelTypeStr);
|
|
101
|
-
|
|
102
|
-
LOGI("TTS JNI: Initialization result: success=%d, detected models=%zu", result.success, result.detectedModels.size());
|
|
103
|
-
if (!result.success) {
|
|
104
|
-
LOGE("TTS JNI: Native initialization failed for: %s", modelDirPath.c_str());
|
|
105
|
-
} else {
|
|
106
|
-
LOGI("TTS JNI: Successfully initialized model at: %s", modelDirPath.c_str());
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Create HashMap to return (same structure as STT)
|
|
110
|
-
LOGI("TTS JNI: Creating HashMap for result");
|
|
111
|
-
jclass hashMapClass = env->FindClass("java/util/HashMap");
|
|
112
|
-
if (hashMapClass == nullptr || env->ExceptionCheck()) {
|
|
113
|
-
LOGE("TTS JNI: Failed to find HashMap class");
|
|
114
|
-
if (env->ExceptionCheck()) {
|
|
115
|
-
env->ExceptionDescribe();
|
|
116
|
-
env->ExceptionClear();
|
|
117
|
-
}
|
|
118
|
-
return nullptr;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
jmethodID hashMapConstructor = env->GetMethodID(hashMapClass, "<init>", "()V");
|
|
122
|
-
if (hashMapConstructor == nullptr || env->ExceptionCheck()) {
|
|
123
|
-
LOGE("TTS JNI: Failed to get HashMap constructor");
|
|
124
|
-
if (env->ExceptionCheck()) {
|
|
125
|
-
env->ExceptionDescribe();
|
|
126
|
-
env->ExceptionClear();
|
|
127
|
-
}
|
|
128
|
-
env->DeleteLocalRef(hashMapClass);
|
|
129
|
-
return nullptr;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
jmethodID putMethod = env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
|
133
|
-
if (putMethod == nullptr || env->ExceptionCheck()) {
|
|
134
|
-
LOGE("TTS JNI: Failed to get HashMap put method");
|
|
135
|
-
if (env->ExceptionCheck()) {
|
|
136
|
-
env->ExceptionDescribe();
|
|
137
|
-
env->ExceptionClear();
|
|
138
|
-
}
|
|
139
|
-
env->DeleteLocalRef(hashMapClass);
|
|
140
|
-
return nullptr;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
jobject hashMap = env->NewObject(hashMapClass, hashMapConstructor);
|
|
144
|
-
if (hashMap == nullptr || env->ExceptionCheck()) {
|
|
145
|
-
LOGE("TTS JNI: Failed to create HashMap object");
|
|
146
|
-
if (env->ExceptionCheck()) {
|
|
147
|
-
env->ExceptionDescribe();
|
|
148
|
-
env->ExceptionClear();
|
|
149
|
-
}
|
|
150
|
-
env->DeleteLocalRef(hashMapClass);
|
|
151
|
-
return nullptr;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Put success boolean
|
|
155
|
-
LOGI("TTS JNI: Adding success field to HashMap");
|
|
156
|
-
jclass booleanClass = env->FindClass("java/lang/Boolean");
|
|
157
|
-
if (booleanClass == nullptr || env->ExceptionCheck()) {
|
|
158
|
-
LOGE("TTS JNI: Failed to find Boolean class");
|
|
159
|
-
if (env->ExceptionCheck()) {
|
|
160
|
-
env->ExceptionDescribe();
|
|
161
|
-
env->ExceptionClear();
|
|
162
|
-
}
|
|
163
|
-
env->DeleteLocalRef(hashMap);
|
|
164
|
-
env->DeleteLocalRef(hashMapClass);
|
|
165
|
-
return nullptr;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
jmethodID booleanConstructor = env->GetMethodID(booleanClass, "<init>", "(Z)V");
|
|
169
|
-
if (booleanConstructor == nullptr || env->ExceptionCheck()) {
|
|
170
|
-
LOGE("TTS JNI: Failed to get Boolean constructor");
|
|
171
|
-
if (env->ExceptionCheck()) {
|
|
172
|
-
env->ExceptionDescribe();
|
|
173
|
-
env->ExceptionClear();
|
|
174
|
-
}
|
|
175
|
-
env->DeleteLocalRef(booleanClass);
|
|
176
|
-
env->DeleteLocalRef(hashMap);
|
|
177
|
-
env->DeleteLocalRef(hashMapClass);
|
|
178
|
-
return nullptr;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
jobject successObj = env->NewObject(booleanClass, booleanConstructor, result.success ? JNI_TRUE : JNI_FALSE);
|
|
182
|
-
jstring successKey = env->NewStringUTF("success");
|
|
183
|
-
env->CallObjectMethod(hashMap, putMethod, successKey, successObj);
|
|
184
|
-
if (env->ExceptionCheck()) {
|
|
185
|
-
LOGE("TTS JNI: Exception while putting success field");
|
|
186
|
-
env->ExceptionDescribe();
|
|
187
|
-
env->ExceptionClear();
|
|
188
|
-
env->DeleteLocalRef(successKey);
|
|
189
|
-
env->DeleteLocalRef(successObj);
|
|
190
|
-
env->DeleteLocalRef(booleanClass);
|
|
191
|
-
env->DeleteLocalRef(hashMap);
|
|
192
|
-
env->DeleteLocalRef(hashMapClass);
|
|
193
|
-
return nullptr;
|
|
194
|
-
}
|
|
195
|
-
env->DeleteLocalRef(successKey);
|
|
196
|
-
env->DeleteLocalRef(successObj);
|
|
197
|
-
env->DeleteLocalRef(booleanClass);
|
|
198
|
-
|
|
199
|
-
// Put detectedModels array
|
|
200
|
-
LOGI("TTS JNI: Adding detectedModels array (%zu models)", result.detectedModels.size());
|
|
201
|
-
jclass arrayListClass = env->FindClass("java/util/ArrayList");
|
|
202
|
-
if (arrayListClass == nullptr || env->ExceptionCheck()) {
|
|
203
|
-
LOGE("TTS JNI: Failed to find ArrayList class");
|
|
204
|
-
if (env->ExceptionCheck()) {
|
|
205
|
-
env->ExceptionDescribe();
|
|
206
|
-
env->ExceptionClear();
|
|
207
|
-
}
|
|
208
|
-
env->DeleteLocalRef(hashMap);
|
|
209
|
-
env->DeleteLocalRef(hashMapClass);
|
|
210
|
-
return nullptr;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
jmethodID arrayListConstructor = env->GetMethodID(arrayListClass, "<init>", "()V");
|
|
214
|
-
if (arrayListConstructor == nullptr || env->ExceptionCheck()) {
|
|
215
|
-
LOGE("TTS JNI: Failed to get ArrayList constructor");
|
|
216
|
-
if (env->ExceptionCheck()) {
|
|
217
|
-
env->ExceptionDescribe();
|
|
218
|
-
env->ExceptionClear();
|
|
219
|
-
}
|
|
220
|
-
env->DeleteLocalRef(arrayListClass);
|
|
221
|
-
env->DeleteLocalRef(hashMap);
|
|
222
|
-
env->DeleteLocalRef(hashMapClass);
|
|
223
|
-
return nullptr;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
jmethodID addMethod = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
|
|
227
|
-
if (addMethod == nullptr || env->ExceptionCheck()) {
|
|
228
|
-
LOGE("TTS JNI: Failed to get ArrayList add method");
|
|
229
|
-
if (env->ExceptionCheck()) {
|
|
230
|
-
env->ExceptionDescribe();
|
|
231
|
-
env->ExceptionClear();
|
|
232
|
-
}
|
|
233
|
-
env->DeleteLocalRef(arrayListClass);
|
|
234
|
-
env->DeleteLocalRef(hashMap);
|
|
235
|
-
env->DeleteLocalRef(hashMapClass);
|
|
236
|
-
return nullptr;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
jobject detectedModelsList = env->NewObject(arrayListClass, arrayListConstructor);
|
|
240
|
-
if (detectedModelsList == nullptr || env->ExceptionCheck()) {
|
|
241
|
-
LOGE("TTS JNI: Failed to create ArrayList object");
|
|
242
|
-
if (env->ExceptionCheck()) {
|
|
243
|
-
env->ExceptionDescribe();
|
|
244
|
-
env->ExceptionClear();
|
|
245
|
-
}
|
|
246
|
-
env->DeleteLocalRef(arrayListClass);
|
|
247
|
-
env->DeleteLocalRef(hashMap);
|
|
248
|
-
env->DeleteLocalRef(hashMapClass);
|
|
249
|
-
return nullptr;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
for (const auto& model : result.detectedModels) {
|
|
253
|
-
// Create HashMap for each model with type and modelDir
|
|
254
|
-
jobject modelMap = env->NewObject(hashMapClass, hashMapConstructor);
|
|
255
|
-
if (modelMap == nullptr || env->ExceptionCheck()) {
|
|
256
|
-
LOGE("TTS JNI: Failed to create model HashMap");
|
|
257
|
-
if (env->ExceptionCheck()) {
|
|
258
|
-
env->ExceptionDescribe();
|
|
259
|
-
env->ExceptionClear();
|
|
260
|
-
}
|
|
261
|
-
env->DeleteLocalRef(detectedModelsList);
|
|
262
|
-
env->DeleteLocalRef(arrayListClass);
|
|
263
|
-
env->DeleteLocalRef(hashMap);
|
|
264
|
-
env->DeleteLocalRef(hashMapClass);
|
|
265
|
-
return nullptr;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
jstring typeKey = env->NewStringUTF("type");
|
|
269
|
-
jstring typeValue = env->NewStringUTF(model.type.c_str());
|
|
270
|
-
env->CallObjectMethod(modelMap, putMethod, typeKey, typeValue);
|
|
271
|
-
env->DeleteLocalRef(typeKey);
|
|
272
|
-
env->DeleteLocalRef(typeValue);
|
|
273
|
-
|
|
274
|
-
jstring dirKey = env->NewStringUTF("modelDir");
|
|
275
|
-
jstring dirValue = env->NewStringUTF(model.modelDir.c_str());
|
|
276
|
-
env->CallObjectMethod(modelMap, putMethod, dirKey, dirValue);
|
|
277
|
-
env->DeleteLocalRef(dirKey);
|
|
278
|
-
env->DeleteLocalRef(dirValue);
|
|
279
|
-
|
|
280
|
-
env->CallBooleanMethod(detectedModelsList, addMethod, modelMap);
|
|
281
|
-
env->DeleteLocalRef(modelMap);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
jstring detectedModelsKey = env->NewStringUTF("detectedModels");
|
|
285
|
-
env->CallObjectMethod(hashMap, putMethod, detectedModelsKey, detectedModelsList);
|
|
286
|
-
if (env->ExceptionCheck()) {
|
|
287
|
-
LOGE("TTS JNI: Exception while putting detectedModels field");
|
|
288
|
-
env->ExceptionDescribe();
|
|
289
|
-
env->ExceptionClear();
|
|
290
|
-
env->DeleteLocalRef(detectedModelsKey);
|
|
291
|
-
env->DeleteLocalRef(detectedModelsList);
|
|
292
|
-
env->DeleteLocalRef(arrayListClass);
|
|
293
|
-
env->DeleteLocalRef(hashMap);
|
|
294
|
-
env->DeleteLocalRef(hashMapClass);
|
|
295
|
-
return nullptr;
|
|
296
|
-
}
|
|
297
|
-
env->DeleteLocalRef(detectedModelsKey);
|
|
298
|
-
env->DeleteLocalRef(detectedModelsList);
|
|
299
|
-
env->DeleteLocalRef(arrayListClass);
|
|
300
|
-
env->DeleteLocalRef(hashMapClass);
|
|
301
|
-
|
|
302
|
-
LOGI("TTS JNI: Successfully created result HashMap, returning to Java");
|
|
303
|
-
return hashMap;
|
|
304
|
-
} catch (const std::exception &e) {
|
|
305
|
-
LOGE("TTS JNI: Exception in nativeInitializeTts: %s", e.what());
|
|
306
|
-
if (env->ExceptionCheck()) {
|
|
307
|
-
env->ExceptionDescribe();
|
|
308
|
-
env->ExceptionClear();
|
|
309
|
-
}
|
|
310
|
-
return nullptr;
|
|
311
|
-
} catch (...) {
|
|
312
|
-
LOGE("TTS JNI: Unknown exception in nativeInitializeTts");
|
|
313
|
-
if (env->ExceptionCheck()) {
|
|
314
|
-
env->ExceptionDescribe();
|
|
315
|
-
env->ExceptionClear();
|
|
316
|
-
}
|
|
317
|
-
return nullptr;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
JNIEXPORT jobject JNICALL
|
|
322
|
-
Java_com_sherpaonnx_SherpaOnnxModule_nativeTtsGenerate(
|
|
323
|
-
JNIEnv *env,
|
|
324
|
-
jobject /* this */,
|
|
325
|
-
jstring text,
|
|
326
|
-
jint sid,
|
|
327
|
-
jfloat speed) {
|
|
328
|
-
try {
|
|
329
|
-
if (g_tts_wrapper == nullptr || !g_tts_wrapper->isInitialized()) {
|
|
330
|
-
LOGE("TTS JNI: Not initialized. Call initialize() first.");
|
|
331
|
-
return nullptr;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
const char *textStr = env->GetStringUTFChars(text, nullptr);
|
|
335
|
-
if (textStr == nullptr) {
|
|
336
|
-
LOGE("TTS JNI: Failed to get text string");
|
|
337
|
-
return nullptr;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
auto result = g_tts_wrapper->generate(
|
|
341
|
-
std::string(textStr),
|
|
342
|
-
static_cast<int32_t>(sid),
|
|
343
|
-
static_cast<float>(speed)
|
|
344
|
-
);
|
|
345
|
-
|
|
346
|
-
env->ReleaseStringUTFChars(text, textStr);
|
|
347
|
-
|
|
348
|
-
if (result.samples.empty() || result.sampleRate == 0) {
|
|
349
|
-
LOGE("TTS JNI: Generation returned empty result");
|
|
350
|
-
return nullptr;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// Create Java HashMap for result
|
|
354
|
-
jclass hashMapClass = env->FindClass("java/util/HashMap");
|
|
355
|
-
if (hashMapClass == nullptr) {
|
|
356
|
-
LOGE("TTS JNI: Failed to find HashMap class");
|
|
357
|
-
return nullptr;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
jmethodID hashMapInit = env->GetMethodID(hashMapClass, "<init>", "()V");
|
|
361
|
-
jmethodID hashMapPut = env->GetMethodID(hashMapClass, "put",
|
|
362
|
-
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
|
363
|
-
|
|
364
|
-
if (hashMapInit == nullptr || hashMapPut == nullptr) {
|
|
365
|
-
LOGE("TTS JNI: Failed to get HashMap methods");
|
|
366
|
-
return nullptr;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
jobject hashMap = env->NewObject(hashMapClass, hashMapInit);
|
|
370
|
-
if (hashMap == nullptr) {
|
|
371
|
-
LOGE("TTS JNI: Failed to create HashMap object");
|
|
372
|
-
return nullptr;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// Convert samples to Java float array
|
|
376
|
-
jfloatArray samplesArray = env->NewFloatArray(result.samples.size());
|
|
377
|
-
if (samplesArray == nullptr) {
|
|
378
|
-
LOGE("TTS JNI: Failed to create float array");
|
|
379
|
-
return nullptr;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
env->SetFloatArrayRegion(samplesArray, 0, result.samples.size(), result.samples.data());
|
|
383
|
-
|
|
384
|
-
// Put samples in map
|
|
385
|
-
jstring samplesKey = env->NewStringUTF("samples");
|
|
386
|
-
env->CallObjectMethod(hashMap, hashMapPut, samplesKey, samplesArray);
|
|
387
|
-
env->DeleteLocalRef(samplesKey);
|
|
388
|
-
env->DeleteLocalRef(samplesArray);
|
|
389
|
-
|
|
390
|
-
// Put sampleRate in map
|
|
391
|
-
jclass integerClass = env->FindClass("java/lang/Integer");
|
|
392
|
-
jmethodID integerInit = env->GetMethodID(integerClass, "<init>", "(I)V");
|
|
393
|
-
jobject sampleRateObj = env->NewObject(integerClass, integerInit, result.sampleRate);
|
|
394
|
-
|
|
395
|
-
jstring sampleRateKey = env->NewStringUTF("sampleRate");
|
|
396
|
-
env->CallObjectMethod(hashMap, hashMapPut, sampleRateKey, sampleRateObj);
|
|
397
|
-
env->DeleteLocalRef(sampleRateKey);
|
|
398
|
-
env->DeleteLocalRef(sampleRateObj);
|
|
399
|
-
|
|
400
|
-
// Clean up local class refs
|
|
401
|
-
env->DeleteLocalRef(integerClass);
|
|
402
|
-
|
|
403
|
-
return hashMap;
|
|
404
|
-
} catch (const std::exception &e) {
|
|
405
|
-
LOGE("TTS JNI: Exception in nativeGenerateTts: %s", e.what());
|
|
406
|
-
return nullptr;
|
|
407
|
-
} catch (...) {
|
|
408
|
-
LOGE("TTS JNI: Unknown exception in nativeGenerateTts");
|
|
409
|
-
return nullptr;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
JNIEXPORT jobject JNICALL
|
|
414
|
-
Java_com_sherpaonnx_SherpaOnnxModule_nativeTtsGenerateWithTimestamps(
|
|
415
|
-
JNIEnv *env,
|
|
416
|
-
jobject /* this */,
|
|
417
|
-
jstring text,
|
|
418
|
-
jint sid,
|
|
419
|
-
jfloat speed) {
|
|
420
|
-
try {
|
|
421
|
-
if (g_tts_wrapper == nullptr || !g_tts_wrapper->isInitialized()) {
|
|
422
|
-
LOGE("TTS JNI: Not initialized. Call initialize() first.");
|
|
423
|
-
return nullptr;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
const char *textStr = env->GetStringUTFChars(text, nullptr);
|
|
427
|
-
if (textStr == nullptr) {
|
|
428
|
-
LOGE("TTS JNI: Failed to get text string");
|
|
429
|
-
return nullptr;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
std::string textValue(textStr);
|
|
433
|
-
auto result = g_tts_wrapper->generate(
|
|
434
|
-
textValue,
|
|
435
|
-
static_cast<int32_t>(sid),
|
|
436
|
-
static_cast<float>(speed)
|
|
437
|
-
);
|
|
438
|
-
|
|
439
|
-
env->ReleaseStringUTFChars(text, textStr);
|
|
440
|
-
|
|
441
|
-
if (result.samples.empty() || result.sampleRate == 0) {
|
|
442
|
-
LOGE("TTS JNI: Generation returned empty result");
|
|
443
|
-
return nullptr;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
jclass hashMapClass = env->FindClass("java/util/HashMap");
|
|
447
|
-
if (hashMapClass == nullptr) {
|
|
448
|
-
LOGE("TTS JNI: Failed to find HashMap class");
|
|
449
|
-
return nullptr;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
jmethodID hashMapInit = env->GetMethodID(hashMapClass, "<init>", "()V");
|
|
453
|
-
jmethodID hashMapPut = env->GetMethodID(
|
|
454
|
-
hashMapClass,
|
|
455
|
-
"put",
|
|
456
|
-
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"
|
|
457
|
-
);
|
|
458
|
-
if (hashMapInit == nullptr || hashMapPut == nullptr) {
|
|
459
|
-
LOGE("TTS JNI: Failed to get HashMap methods");
|
|
460
|
-
return nullptr;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
jobject hashMap = env->NewObject(hashMapClass, hashMapInit);
|
|
464
|
-
if (hashMap == nullptr) {
|
|
465
|
-
LOGE("TTS JNI: Failed to create HashMap object");
|
|
466
|
-
return nullptr;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
jfloatArray samplesArray = env->NewFloatArray(result.samples.size());
|
|
470
|
-
if (samplesArray == nullptr) {
|
|
471
|
-
LOGE("TTS JNI: Failed to create float array");
|
|
472
|
-
return nullptr;
|
|
473
|
-
}
|
|
474
|
-
env->SetFloatArrayRegion(samplesArray, 0, result.samples.size(), result.samples.data());
|
|
475
|
-
|
|
476
|
-
jstring samplesKey = env->NewStringUTF("samples");
|
|
477
|
-
env->CallObjectMethod(hashMap, hashMapPut, samplesKey, samplesArray);
|
|
478
|
-
env->DeleteLocalRef(samplesKey);
|
|
479
|
-
env->DeleteLocalRef(samplesArray);
|
|
480
|
-
|
|
481
|
-
jclass integerClass = env->FindClass("java/lang/Integer");
|
|
482
|
-
jmethodID integerInit = env->GetMethodID(integerClass, "<init>", "(I)V");
|
|
483
|
-
jobject sampleRateObj = env->NewObject(integerClass, integerInit, result.sampleRate);
|
|
484
|
-
|
|
485
|
-
jstring sampleRateKey = env->NewStringUTF("sampleRate");
|
|
486
|
-
env->CallObjectMethod(hashMap, hashMapPut, sampleRateKey, sampleRateObj);
|
|
487
|
-
env->DeleteLocalRef(sampleRateKey);
|
|
488
|
-
env->DeleteLocalRef(sampleRateObj);
|
|
489
|
-
|
|
490
|
-
jclass arrayListClass = env->FindClass("java/util/ArrayList");
|
|
491
|
-
jmethodID arrayListInit = env->GetMethodID(arrayListClass, "<init>", "()V");
|
|
492
|
-
jmethodID arrayListAdd = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
|
|
493
|
-
|
|
494
|
-
jobject subtitlesList = env->NewObject(arrayListClass, arrayListInit);
|
|
495
|
-
auto tokens = SplitTtsTokens(textValue);
|
|
496
|
-
jclass doubleClass = nullptr;
|
|
497
|
-
if (!tokens.empty()) {
|
|
498
|
-
const double totalSeconds = static_cast<double>(result.samples.size()) /
|
|
499
|
-
static_cast<double>(result.sampleRate);
|
|
500
|
-
const double perToken = totalSeconds / static_cast<double>(tokens.size());
|
|
501
|
-
|
|
502
|
-
doubleClass = env->FindClass("java/lang/Double");
|
|
503
|
-
jmethodID doubleInit = env->GetMethodID(doubleClass, "<init>", "(D)V");
|
|
504
|
-
|
|
505
|
-
for (size_t i = 0; i < tokens.size(); ++i) {
|
|
506
|
-
double start = perToken * static_cast<double>(i);
|
|
507
|
-
double end = perToken * static_cast<double>(i + 1);
|
|
508
|
-
|
|
509
|
-
jobject subtitleMap = env->NewObject(hashMapClass, hashMapInit);
|
|
510
|
-
jstring textKey = env->NewStringUTF("text");
|
|
511
|
-
jstring textValueKey = env->NewStringUTF(tokens[i].c_str());
|
|
512
|
-
env->CallObjectMethod(subtitleMap, hashMapPut, textKey, textValueKey);
|
|
513
|
-
env->DeleteLocalRef(textKey);
|
|
514
|
-
env->DeleteLocalRef(textValueKey);
|
|
515
|
-
|
|
516
|
-
jstring startKey = env->NewStringUTF("start");
|
|
517
|
-
jobject startObj = env->NewObject(doubleClass, doubleInit, start);
|
|
518
|
-
env->CallObjectMethod(subtitleMap, hashMapPut, startKey, startObj);
|
|
519
|
-
env->DeleteLocalRef(startKey);
|
|
520
|
-
env->DeleteLocalRef(startObj);
|
|
521
|
-
|
|
522
|
-
jstring endKey = env->NewStringUTF("end");
|
|
523
|
-
jobject endObj = env->NewObject(doubleClass, doubleInit, end);
|
|
524
|
-
env->CallObjectMethod(subtitleMap, hashMapPut, endKey, endObj);
|
|
525
|
-
env->DeleteLocalRef(endKey);
|
|
526
|
-
env->DeleteLocalRef(endObj);
|
|
527
|
-
|
|
528
|
-
env->CallBooleanMethod(subtitlesList, arrayListAdd, subtitleMap);
|
|
529
|
-
env->DeleteLocalRef(subtitleMap);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
jstring subtitlesKey = env->NewStringUTF("subtitles");
|
|
534
|
-
env->CallObjectMethod(hashMap, hashMapPut, subtitlesKey, subtitlesList);
|
|
535
|
-
env->DeleteLocalRef(subtitlesKey);
|
|
536
|
-
env->DeleteLocalRef(subtitlesList);
|
|
537
|
-
|
|
538
|
-
jclass booleanClass = env->FindClass("java/lang/Boolean");
|
|
539
|
-
jmethodID booleanInit = env->GetMethodID(booleanClass, "<init>", "(Z)V");
|
|
540
|
-
jobject estimatedObj = env->NewObject(booleanClass, booleanInit, JNI_TRUE);
|
|
541
|
-
jstring estimatedKey = env->NewStringUTF("estimated");
|
|
542
|
-
env->CallObjectMethod(hashMap, hashMapPut, estimatedKey, estimatedObj);
|
|
543
|
-
env->DeleteLocalRef(estimatedKey);
|
|
544
|
-
env->DeleteLocalRef(estimatedObj);
|
|
545
|
-
|
|
546
|
-
// Clean up local class refs used above
|
|
547
|
-
env->DeleteLocalRef(booleanClass);
|
|
548
|
-
env->DeleteLocalRef(arrayListClass);
|
|
549
|
-
env->DeleteLocalRef(integerClass);
|
|
550
|
-
if (doubleClass) env->DeleteLocalRef(doubleClass);
|
|
551
|
-
env->DeleteLocalRef(hashMapClass);
|
|
552
|
-
|
|
553
|
-
return hashMap;
|
|
554
|
-
} catch (const std::exception &e) {
|
|
555
|
-
LOGE("TTS JNI: Exception in nativeGenerateTtsWithTimestamps: %s", e.what());
|
|
556
|
-
return nullptr;
|
|
557
|
-
} catch (...) {
|
|
558
|
-
LOGE("TTS JNI: Unknown exception in nativeGenerateTtsWithTimestamps");
|
|
559
|
-
return nullptr;
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
JNIEXPORT jboolean JNICALL
|
|
564
|
-
Java_com_sherpaonnx_SherpaOnnxModule_nativeTtsGenerateStream(
|
|
565
|
-
JNIEnv *env,
|
|
566
|
-
jobject /* this */,
|
|
567
|
-
jstring text,
|
|
568
|
-
jint sid,
|
|
569
|
-
jfloat speed) {
|
|
570
|
-
try {
|
|
571
|
-
if (g_tts_wrapper == nullptr || !g_tts_wrapper->isInitialized()) {
|
|
572
|
-
LOGE("TTS JNI: Not initialized. Call initialize() first.");
|
|
573
|
-
return JNI_FALSE;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
const char *textStr = env->GetStringUTFChars(text, nullptr);
|
|
577
|
-
if (textStr == nullptr) {
|
|
578
|
-
LOGE("TTS JNI: Failed to get text string");
|
|
579
|
-
return JNI_FALSE;
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
g_tts_stream_cancelled.store(false);
|
|
583
|
-
|
|
584
|
-
jclass moduleClassLocal = env->FindClass("com/sherpaonnx/SherpaOnnxModule");
|
|
585
|
-
if (moduleClassLocal == nullptr) {
|
|
586
|
-
LOGE("TTS JNI: Failed to find SherpaOnnxModule class");
|
|
587
|
-
env->ReleaseStringUTFChars(text, textStr);
|
|
588
|
-
return JNI_FALSE;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
jmethodID onChunk = env->GetStaticMethodID(
|
|
592
|
-
moduleClassLocal,
|
|
593
|
-
"onTtsStreamChunk",
|
|
594
|
-
"([FIFZ)V"
|
|
595
|
-
);
|
|
596
|
-
jmethodID onError = env->GetStaticMethodID(
|
|
597
|
-
moduleClassLocal,
|
|
598
|
-
"onTtsStreamError",
|
|
599
|
-
"(Ljava/lang/String;)V"
|
|
600
|
-
);
|
|
601
|
-
|
|
602
|
-
if (onChunk == nullptr) {
|
|
603
|
-
LOGE("TTS JNI: Failed to get onTtsStreamChunk method");
|
|
604
|
-
env->ReleaseStringUTFChars(text, textStr);
|
|
605
|
-
env->DeleteLocalRef(moduleClassLocal);
|
|
606
|
-
return JNI_FALSE;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
// Make a global ref for the class to be safe if the callback runs on another thread
|
|
610
|
-
JavaVM *jvm = nullptr;
|
|
611
|
-
if (env->GetJavaVM(&jvm) != JNI_OK) {
|
|
612
|
-
LOGE("TTS JNI: Failed to get JavaVM");
|
|
613
|
-
env->ReleaseStringUTFChars(text, textStr);
|
|
614
|
-
env->DeleteLocalRef(moduleClassLocal);
|
|
615
|
-
return JNI_FALSE;
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
jclass moduleClass = reinterpret_cast<jclass>(env->NewGlobalRef(moduleClassLocal));
|
|
619
|
-
// we can drop the local ref now
|
|
620
|
-
env->DeleteLocalRef(moduleClassLocal);
|
|
621
|
-
|
|
622
|
-
const int32_t sampleRate = g_tts_wrapper->getSampleRate();
|
|
623
|
-
auto finalSent = std::make_shared<std::atomic<bool>>(false);
|
|
624
|
-
const uint64_t streamId = g_tts_active_stream_id.fetch_add(1) + 1;
|
|
625
|
-
g_tts_active_stream_id.store(streamId);
|
|
626
|
-
const bool ok = g_tts_wrapper->generateStream(
|
|
627
|
-
std::string(textStr),
|
|
628
|
-
static_cast<int32_t>(sid),
|
|
629
|
-
static_cast<float>(speed),
|
|
630
|
-
streamId,
|
|
631
|
-
[jvm, moduleClass, onChunk, sampleRate, finalSent, streamId](
|
|
632
|
-
const float *samples,
|
|
633
|
-
int32_t numSamples,
|
|
634
|
-
float progress
|
|
635
|
-
) -> int32_t {
|
|
636
|
-
if (g_tts_stream_cancelled.load()) {
|
|
637
|
-
return 0;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
JNIEnv *callbackEnv = nullptr;
|
|
641
|
-
bool attached = false;
|
|
642
|
-
if (jvm->GetEnv(reinterpret_cast<void **>(&callbackEnv), JNI_VERSION_1_6) != JNI_OK) {
|
|
643
|
-
if (jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&callbackEnv), nullptr) != 0) {
|
|
644
|
-
// Failed to attach
|
|
645
|
-
return 0;
|
|
646
|
-
}
|
|
647
|
-
attached = true;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
jfloatArray floatArray = callbackEnv->NewFloatArray(numSamples);
|
|
651
|
-
if (floatArray == nullptr) {
|
|
652
|
-
if (attached) jvm->DetachCurrentThread();
|
|
653
|
-
return 0;
|
|
654
|
-
}
|
|
655
|
-
callbackEnv->SetFloatArrayRegion(floatArray, 0, numSamples, samples);
|
|
656
|
-
|
|
657
|
-
const bool isFinal = progress >= 0.999f;
|
|
658
|
-
callbackEnv->CallStaticVoidMethod(
|
|
659
|
-
moduleClass,
|
|
660
|
-
onChunk,
|
|
661
|
-
floatArray,
|
|
662
|
-
sampleRate,
|
|
663
|
-
progress,
|
|
664
|
-
isFinal ? JNI_TRUE : JNI_FALSE
|
|
665
|
-
);
|
|
666
|
-
callbackEnv->DeleteLocalRef(floatArray);
|
|
667
|
-
|
|
668
|
-
if (isFinal && !finalSent->exchange(true)) {
|
|
669
|
-
if (g_tts_wrapper) {
|
|
670
|
-
g_tts_wrapper->endStream(streamId);
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
if (attached) jvm->DetachCurrentThread();
|
|
675
|
-
return 1;
|
|
676
|
-
}
|
|
677
|
-
);
|
|
678
|
-
|
|
679
|
-
env->ReleaseStringUTFChars(text, textStr);
|
|
680
|
-
|
|
681
|
-
if (!ok && !g_tts_stream_cancelled.load()) {
|
|
682
|
-
// Ensure we have a JNIEnv for calling the error callback
|
|
683
|
-
JNIEnv *errEnv = nullptr;
|
|
684
|
-
bool errAttached = false;
|
|
685
|
-
if (jvm->GetEnv(reinterpret_cast<void **>(&errEnv), JNI_VERSION_1_6) != JNI_OK) {
|
|
686
|
-
if (jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&errEnv), nullptr) == 0) {
|
|
687
|
-
errAttached = true;
|
|
688
|
-
} else {
|
|
689
|
-
errEnv = nullptr;
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
if (errEnv != nullptr && onError != nullptr) {
|
|
694
|
-
jstring errorMsg = errEnv->NewStringUTF("TTS: Streaming generation failed");
|
|
695
|
-
errEnv->CallStaticVoidMethod(moduleClass, onError, errorMsg);
|
|
696
|
-
errEnv->DeleteLocalRef(errorMsg);
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
if (errAttached) jvm->DetachCurrentThread();
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
if (!ok && g_tts_wrapper) {
|
|
703
|
-
g_tts_wrapper->endStream(streamId);
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
// cleanup global ref
|
|
707
|
-
env->DeleteGlobalRef(moduleClass);
|
|
708
|
-
return ok ? JNI_TRUE : JNI_FALSE;
|
|
709
|
-
} catch (const std::exception &e) {
|
|
710
|
-
LOGE("TTS JNI: Exception in nativeTtsGenerateStream: %s", e.what());
|
|
711
|
-
return JNI_FALSE;
|
|
712
|
-
} catch (...) {
|
|
713
|
-
LOGE("TTS JNI: Unknown exception in nativeTtsGenerateStream");
|
|
714
|
-
return JNI_FALSE;
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
JNIEXPORT void JNICALL
|
|
719
|
-
Java_com_sherpaonnx_SherpaOnnxModule_nativeTtsCancelStream(
|
|
720
|
-
JNIEnv * /* env */,
|
|
721
|
-
jobject /* this */) {
|
|
722
|
-
g_tts_stream_cancelled.store(true);
|
|
723
|
-
if (g_tts_wrapper) {
|
|
724
|
-
g_tts_wrapper->cancelStream(g_tts_active_stream_id.load());
|
|
725
|
-
}
|
|
726
|
-
g_tts_active_stream_id.store(0);
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
JNIEXPORT jint JNICALL
|
|
730
|
-
Java_com_sherpaonnx_SherpaOnnxModule_nativeTtsGetSampleRate(
|
|
731
|
-
JNIEnv * /* env */,
|
|
732
|
-
jobject /* this */) {
|
|
733
|
-
try {
|
|
734
|
-
if (g_tts_wrapper == nullptr || !g_tts_wrapper->isInitialized()) {
|
|
735
|
-
LOGE("TTS JNI: Not initialized. Call initialize() first.");
|
|
736
|
-
return 0;
|
|
737
|
-
}
|
|
738
|
-
return g_tts_wrapper->getSampleRate();
|
|
739
|
-
} catch (const std::exception &e) {
|
|
740
|
-
LOGE("TTS JNI: Exception in nativeGetTtsSampleRate: %s", e.what());
|
|
741
|
-
return 0;
|
|
742
|
-
} catch (...) {
|
|
743
|
-
LOGE("TTS JNI: Unknown exception in nativeGetTtsSampleRate");
|
|
744
|
-
return 0;
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
JNIEXPORT jint JNICALL
|
|
749
|
-
Java_com_sherpaonnx_SherpaOnnxModule_nativeTtsGetNumSpeakers(
|
|
750
|
-
JNIEnv * /* env */,
|
|
751
|
-
jobject /* this */) {
|
|
752
|
-
try {
|
|
753
|
-
if (g_tts_wrapper == nullptr || !g_tts_wrapper->isInitialized()) {
|
|
754
|
-
LOGE("TTS JNI: Not initialized. Call initialize() first.");
|
|
755
|
-
return 0;
|
|
756
|
-
}
|
|
757
|
-
return g_tts_wrapper->getNumSpeakers();
|
|
758
|
-
} catch (const std::exception &e) {
|
|
759
|
-
LOGE("TTS JNI: Exception in nativeGetTtsNumSpeakers: %s", e.what());
|
|
760
|
-
return 0;
|
|
761
|
-
} catch (...) {
|
|
762
|
-
LOGE("TTS JNI: Unknown exception in nativeGetTtsNumSpeakers");
|
|
763
|
-
return 0;
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
JNIEXPORT void JNICALL
|
|
768
|
-
Java_com_sherpaonnx_SherpaOnnxModule_nativeTtsRelease(
|
|
769
|
-
JNIEnv * /* env */,
|
|
770
|
-
jobject /* this */) {
|
|
771
|
-
try {
|
|
772
|
-
if (g_tts_wrapper != nullptr) {
|
|
773
|
-
g_tts_wrapper->release();
|
|
774
|
-
g_tts_wrapper.reset();
|
|
775
|
-
}
|
|
776
|
-
} catch (const std::exception &e) {
|
|
777
|
-
LOGE("TTS JNI: Exception in nativeReleaseTts: %s", e.what());
|
|
778
|
-
} catch (...) {
|
|
779
|
-
LOGE("TTS JNI: Unknown exception in nativeReleaseTts");
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
JNIEXPORT jboolean JNICALL
|
|
784
|
-
Java_com_sherpaonnx_SherpaOnnxModule_nativeTtsSaveToWavFile(
|
|
785
|
-
JNIEnv *env,
|
|
786
|
-
jobject /* this */,
|
|
787
|
-
jfloatArray samples,
|
|
788
|
-
jint sampleRate,
|
|
789
|
-
jstring filePath) {
|
|
790
|
-
try {
|
|
791
|
-
if (samples == nullptr || filePath == nullptr) {
|
|
792
|
-
LOGE("TTS JNI: samples or filePath is null");
|
|
793
|
-
return JNI_FALSE;
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
// Convert jfloatArray to std::vector<float>
|
|
797
|
-
jsize len = env->GetArrayLength(samples);
|
|
798
|
-
std::vector<float> samplesVec(len);
|
|
799
|
-
env->GetFloatArrayRegion(samples, 0, len, samplesVec.data());
|
|
800
|
-
|
|
801
|
-
// Convert jstring to std::string
|
|
802
|
-
const char *filePathCStr = env->GetStringUTFChars(filePath, nullptr);
|
|
803
|
-
std::string filePathStr(filePathCStr);
|
|
804
|
-
env->ReleaseStringUTFChars(filePath, filePathCStr);
|
|
805
|
-
|
|
806
|
-
// Call the static method
|
|
807
|
-
bool success = sherpaonnx::TtsWrapper::saveToWavFile(
|
|
808
|
-
samplesVec,
|
|
809
|
-
static_cast<int32_t>(sampleRate),
|
|
810
|
-
filePathStr
|
|
811
|
-
);
|
|
812
|
-
|
|
813
|
-
return success ? JNI_TRUE : JNI_FALSE;
|
|
814
|
-
} catch (const std::exception &e) {
|
|
815
|
-
LOGE("TTS JNI: Exception in nativeTtsSaveToWavFile: %s", e.what());
|
|
816
|
-
return JNI_FALSE;
|
|
817
|
-
} catch (...) {
|
|
818
|
-
LOGE("TTS JNI: Unknown exception in nativeTtsSaveToWavFile");
|
|
819
|
-
return JNI_FALSE;
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
} // extern "C"
|