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.
Files changed (232) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +90 -21
  3. package/SherpaOnnx.podspec +3 -0
  4. package/THIRD_PARTY_LICENSES/README.md +62 -0
  5. package/THIRD_PARTY_LICENSES/ffmpeg.txt +502 -0
  6. package/THIRD_PARTY_LICENSES/libarchive.txt +65 -0
  7. package/THIRD_PARTY_LICENSES/nvidia_omla.txt +181 -0
  8. package/THIRD_PARTY_LICENSES/onnxruntime.txt +21 -0
  9. package/THIRD_PARTY_LICENSES/opus.txt +44 -0
  10. package/THIRD_PARTY_LICENSES/sherpa-onnx.txt +201 -0
  11. package/THIRD_PARTY_LICENSES/shine.txt +482 -0
  12. package/THIRD_PARTY_LICENSES/zstd.txt +30 -0
  13. package/android/build.gradle +7 -3
  14. package/android/prebuilt-download.gradle +345 -153
  15. package/android/prebuilt-versions.gradle +2 -2
  16. package/android/src/main/assets/model_licenses/asr-models-license-status.csv +409 -0
  17. package/android/src/main/assets/model_licenses/qnn-asr-models-license-status.csv +695 -0
  18. package/android/src/main/assets/model_licenses/tts-models-license-status.csv +596 -0
  19. package/android/src/main/cpp/CMakeLists.txt +28 -10
  20. package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.cpp +306 -6
  21. package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-helper.h +33 -4
  22. package/android/src/main/cpp/jni/archive/sherpa-onnx-archive-jni.cpp +266 -7
  23. package/android/src/main/cpp/jni/audio/sherpa-onnx-audio-convert-jni.cpp +268 -2
  24. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-tts.cpp +6 -2
  25. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-tts.cpp +4 -2
  26. package/android/src/main/java/com/sherpaonnx/SherpaOnnxArchiveHelper.kt +137 -7
  27. package/android/src/main/java/com/sherpaonnx/SherpaOnnxAssetHelper.kt +51 -6
  28. package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +159 -0
  29. package/android/src/main/java/com/sherpaonnx/SherpaOnnxOnlineSttHelper.kt +4 -1
  30. package/android/src/main/java/com/sherpaonnx/SherpaOnnxTtsHelper.kt +112 -97
  31. package/ios/Resources/model_licenses/asr-models-license-status.csv +409 -0
  32. package/ios/Resources/model_licenses/qnn-asr-models-license-status.csv +695 -0
  33. package/ios/Resources/model_licenses/tts-models-license-status.csv +596 -0
  34. package/ios/SherpaOnnx+OnlineSTT.mm +2 -0
  35. package/ios/SherpaOnnx+PcmLiveStream.mm +2 -29
  36. package/ios/SherpaOnnx+TTS.mm +178 -20
  37. package/ios/SherpaOnnx.mm +108 -1
  38. package/ios/SherpaOnnxAudioConvert.h +10 -0
  39. package/ios/SherpaOnnxAudioConvert.mm +257 -1
  40. package/ios/archive/sherpa-onnx-archive-helper.h +10 -0
  41. package/ios/archive/sherpa-onnx-archive-helper.mm +56 -5
  42. package/ios/model_detect/sherpa-onnx-model-detect-tts.mm +13 -2
  43. package/ios/model_detect/sherpa-onnx-validate-tts.mm +4 -2
  44. package/ios/online_stt/sherpa-onnx-online-stt-wrapper.h +1 -0
  45. package/ios/online_stt/sherpa-onnx-online-stt-wrapper.mm +4 -0
  46. package/ios/tts/sherpa-onnx-tts-wrapper.h +37 -0
  47. package/ios/tts/sherpa-onnx-tts-wrapper.mm +149 -3
  48. package/lib/module/NativeSherpaOnnx.js.map +1 -1
  49. package/lib/module/audio/index.js +8 -0
  50. package/lib/module/audio/index.js.map +1 -1
  51. package/lib/module/download/ModelDownloadManager.js +10 -929
  52. package/lib/module/download/ModelDownloadManager.js.map +1 -1
  53. package/lib/module/download/activeModelOperations.js +26 -0
  54. package/lib/module/download/activeModelOperations.js.map +1 -0
  55. package/lib/module/download/background-downloader.d.js +2 -0
  56. package/lib/module/download/background-downloader.d.js.map +1 -0
  57. package/lib/module/download/bulkPurge.js +72 -0
  58. package/lib/module/download/bulkPurge.js.map +1 -0
  59. package/lib/module/download/checksumPrompt.js +19 -0
  60. package/lib/module/download/checksumPrompt.js.map +1 -0
  61. package/lib/module/download/constants.js +7 -0
  62. package/lib/module/download/constants.js.map +1 -0
  63. package/lib/module/download/downloadEvents.js +35 -0
  64. package/lib/module/download/downloadEvents.js.map +1 -0
  65. package/lib/module/download/downloadTask.js +385 -0
  66. package/lib/module/download/downloadTask.js.map +1 -0
  67. package/lib/module/download/ensureModel.js +89 -0
  68. package/lib/module/download/ensureModel.js.map +1 -0
  69. package/lib/module/download/index.js +4 -3
  70. package/lib/module/download/index.js.map +1 -1
  71. package/lib/module/download/localModels.js +151 -0
  72. package/lib/module/download/localModels.js.map +1 -0
  73. package/lib/module/download/modelExtraction.js +174 -0
  74. package/lib/module/download/modelExtraction.js.map +1 -0
  75. package/lib/module/download/paths.js +98 -0
  76. package/lib/module/download/paths.js.map +1 -0
  77. package/lib/module/download/postDownloadProcessing.js +206 -0
  78. package/lib/module/download/postDownloadProcessing.js.map +1 -0
  79. package/lib/module/download/protectedModelKeys.js +31 -0
  80. package/lib/module/download/protectedModelKeys.js.map +1 -0
  81. package/lib/module/download/registry.js +267 -0
  82. package/lib/module/download/registry.js.map +1 -0
  83. package/lib/module/download/retry.js +59 -0
  84. package/lib/module/download/retry.js.map +1 -0
  85. package/lib/module/download/types.js +17 -0
  86. package/lib/module/download/types.js.map +1 -0
  87. package/lib/module/download/validation.js +101 -5
  88. package/lib/module/download/validation.js.map +1 -1
  89. package/lib/module/{download → extraction}/extractTarBz2.js +3 -1
  90. package/lib/module/extraction/extractTarBz2.js.map +1 -0
  91. package/lib/module/extraction/extractTarZst.js +54 -0
  92. package/lib/module/extraction/extractTarZst.js.map +1 -0
  93. package/lib/module/extraction/index.js +190 -0
  94. package/lib/module/extraction/index.js.map +1 -0
  95. package/lib/module/extraction/types.js +2 -0
  96. package/lib/module/extraction/types.js.map +1 -0
  97. package/lib/module/index.js +2 -1
  98. package/lib/module/index.js.map +1 -1
  99. package/lib/module/licenses.js +63 -0
  100. package/lib/module/licenses.js.map +1 -0
  101. package/lib/module/stt/index.js +16 -2
  102. package/lib/module/stt/index.js.map +1 -1
  103. package/lib/module/stt/streaming.js +2 -0
  104. package/lib/module/stt/streaming.js.map +1 -1
  105. package/lib/module/stt/streamingTypes.js.map +1 -1
  106. package/lib/module/stt/types.js.map +1 -1
  107. package/lib/module/tts/index.js +20 -2
  108. package/lib/module/tts/index.js.map +1 -1
  109. package/lib/module/tts/streaming.js +4 -0
  110. package/lib/module/tts/streaming.js.map +1 -1
  111. package/lib/module/tts/types.js.map +1 -1
  112. package/lib/module/utils.js +16 -1
  113. package/lib/module/utils.js.map +1 -1
  114. package/lib/typescript/src/NativeSherpaOnnx.d.ts +72 -5
  115. package/lib/typescript/src/NativeSherpaOnnx.d.ts.map +1 -1
  116. package/lib/typescript/src/audio/index.d.ts +10 -0
  117. package/lib/typescript/src/audio/index.d.ts.map +1 -1
  118. package/lib/typescript/src/download/ModelDownloadManager.d.ts +10 -108
  119. package/lib/typescript/src/download/ModelDownloadManager.d.ts.map +1 -1
  120. package/lib/typescript/src/download/activeModelOperations.d.ts +6 -0
  121. package/lib/typescript/src/download/activeModelOperations.d.ts.map +1 -0
  122. package/lib/typescript/src/download/bulkPurge.d.ts +14 -0
  123. package/lib/typescript/src/download/bulkPurge.d.ts.map +1 -0
  124. package/lib/typescript/src/download/checksumPrompt.d.ts +3 -0
  125. package/lib/typescript/src/download/checksumPrompt.d.ts.map +1 -0
  126. package/lib/typescript/src/download/constants.d.ts +5 -0
  127. package/lib/typescript/src/download/constants.d.ts.map +1 -0
  128. package/lib/typescript/src/download/downloadEvents.d.ts +6 -0
  129. package/lib/typescript/src/download/downloadEvents.d.ts.map +1 -0
  130. package/lib/typescript/src/download/downloadTask.d.ts +20 -0
  131. package/lib/typescript/src/download/downloadTask.d.ts.map +1 -0
  132. package/lib/typescript/src/download/ensureModel.d.ts +26 -0
  133. package/lib/typescript/src/download/ensureModel.d.ts.map +1 -0
  134. package/lib/typescript/src/download/index.d.ts +7 -5
  135. package/lib/typescript/src/download/index.d.ts.map +1 -1
  136. package/lib/typescript/src/download/localModels.d.ts +15 -0
  137. package/lib/typescript/src/download/localModels.d.ts.map +1 -0
  138. package/lib/typescript/src/download/modelExtraction.d.ts +36 -0
  139. package/lib/typescript/src/download/modelExtraction.d.ts.map +1 -0
  140. package/lib/typescript/src/download/paths.d.ts +28 -0
  141. package/lib/typescript/src/download/paths.d.ts.map +1 -0
  142. package/lib/typescript/src/download/postDownloadProcessing.d.ts +19 -0
  143. package/lib/typescript/src/download/postDownloadProcessing.d.ts.map +1 -0
  144. package/lib/typescript/src/download/protectedModelKeys.d.ts +6 -0
  145. package/lib/typescript/src/download/protectedModelKeys.d.ts.map +1 -0
  146. package/lib/typescript/src/download/registry.d.ts +14 -0
  147. package/lib/typescript/src/download/registry.d.ts.map +1 -0
  148. package/lib/typescript/src/download/retry.d.ts +15 -0
  149. package/lib/typescript/src/download/retry.d.ts.map +1 -0
  150. package/lib/typescript/src/download/types.d.ts +96 -0
  151. package/lib/typescript/src/download/types.d.ts.map +1 -0
  152. package/lib/typescript/src/download/validation.d.ts +19 -0
  153. package/lib/typescript/src/download/validation.d.ts.map +1 -1
  154. package/lib/typescript/src/extraction/extractTarBz2.d.ts.map +1 -0
  155. package/lib/typescript/src/extraction/extractTarZst.d.ts +14 -0
  156. package/lib/typescript/src/extraction/extractTarZst.d.ts.map +1 -0
  157. package/lib/typescript/src/extraction/index.d.ts +50 -0
  158. package/lib/typescript/src/extraction/index.d.ts.map +1 -0
  159. package/lib/typescript/src/extraction/types.d.ts +60 -0
  160. package/lib/typescript/src/extraction/types.d.ts.map +1 -0
  161. package/lib/typescript/src/index.d.ts +1 -0
  162. package/lib/typescript/src/index.d.ts.map +1 -1
  163. package/lib/typescript/src/licenses.d.ts +10 -0
  164. package/lib/typescript/src/licenses.d.ts.map +1 -0
  165. package/lib/typescript/src/stt/index.d.ts +4 -1
  166. package/lib/typescript/src/stt/index.d.ts.map +1 -1
  167. package/lib/typescript/src/stt/streaming.d.ts.map +1 -1
  168. package/lib/typescript/src/stt/streamingTypes.d.ts +5 -0
  169. package/lib/typescript/src/stt/streamingTypes.d.ts.map +1 -1
  170. package/lib/typescript/src/stt/types.d.ts +3 -1
  171. package/lib/typescript/src/stt/types.d.ts.map +1 -1
  172. package/lib/typescript/src/tts/index.d.ts +3 -1
  173. package/lib/typescript/src/tts/index.d.ts.map +1 -1
  174. package/lib/typescript/src/tts/streaming.d.ts.map +1 -1
  175. package/lib/typescript/src/tts/types.d.ts +6 -5
  176. package/lib/typescript/src/tts/types.d.ts.map +1 -1
  177. package/lib/typescript/src/utils.d.ts +5 -0
  178. package/lib/typescript/src/utils.d.ts.map +1 -1
  179. package/package.json +11 -1
  180. package/scripts/{check-model-csvs.sh → ci/check-model-csvs.sh} +9 -2
  181. package/scripts/ci/collect_all_sherpa_model_streams.sh +101 -0
  182. package/scripts/ci/collect_one_sherpa_release_stream.sh +189 -0
  183. package/scripts/ci/sherpa_asr_model_release_streams.json +21 -0
  184. package/scripts/ci/sherpa_tts_model_release_streams.json +13 -0
  185. package/scripts/ci/update_model_license_csv.sh +765 -0
  186. package/scripts/setup-ios-framework.sh +14 -11
  187. package/scripts/update_commercial_use.js +73 -0
  188. package/src/NativeSherpaOnnx.ts +92 -5
  189. package/src/audio/index.ts +20 -0
  190. package/src/download/ModelDownloadManager.ts +55 -1343
  191. package/src/download/activeModelOperations.ts +38 -0
  192. package/src/download/background-downloader.d.ts +43 -0
  193. package/src/download/bulkPurge.ts +102 -0
  194. package/src/download/checksumPrompt.ts +25 -0
  195. package/src/download/constants.ts +5 -0
  196. package/src/download/downloadEvents.ts +55 -0
  197. package/src/download/downloadTask.ts +497 -0
  198. package/src/download/ensureModel.ts +124 -0
  199. package/src/download/index.ts +19 -2
  200. package/src/download/localModels.ts +234 -0
  201. package/src/download/modelExtraction.ts +244 -0
  202. package/src/download/paths.ts +134 -0
  203. package/src/download/postDownloadProcessing.ts +292 -0
  204. package/src/download/protectedModelKeys.ts +30 -0
  205. package/src/download/registry.ts +404 -0
  206. package/src/download/retry.ts +76 -0
  207. package/src/download/types.ts +120 -0
  208. package/src/download/validation.ts +114 -8
  209. package/src/{download → extraction}/extractTarBz2.ts +3 -1
  210. package/src/extraction/extractTarZst.ts +79 -0
  211. package/src/extraction/index.ts +269 -0
  212. package/src/extraction/types.ts +63 -0
  213. package/src/index.tsx +2 -0
  214. package/src/licenses.ts +100 -0
  215. package/src/stt/index.ts +20 -2
  216. package/src/stt/streaming.ts +3 -0
  217. package/src/stt/streamingTypes.ts +5 -0
  218. package/src/stt/types.ts +3 -1
  219. package/src/tts/index.ts +30 -2
  220. package/src/tts/streaming.ts +10 -0
  221. package/src/tts/types.ts +6 -5
  222. package/src/utils.ts +22 -1
  223. package/third_party/libarchive_prebuilt/ANDROID_RELEASE_TAG +1 -1
  224. package/third_party/libarchive_prebuilt/IOS_RELEASE_TAG +1 -1
  225. package/third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG +1 -1
  226. package/third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG +1 -1
  227. package/android/src/main/cpp/jni/tts/sherpa-onnx-tts-zipvoice-jni.cpp +0 -301
  228. package/android/src/main/java/com/sherpaonnx/ZipvoiceTtsWrapper.kt +0 -187
  229. package/lib/module/download/extractTarBz2.js.map +0 -1
  230. package/lib/typescript/src/download/extractTarBz2.d.ts.map +0 -1
  231. package/scripts/check-qnn-support.sh +0 -78
  232. /package/lib/typescript/src/{download → extraction}/extractTarBz2.d.ts +0 -0
@@ -29,7 +29,7 @@ get_filename_component(PROJECT_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../.." ABSOL
29
29
  set(USE_FFMPEG ON)
30
30
  if(SHERPA_ONNX_DISABLE_FFMPEG)
31
31
  set(USE_FFMPEG OFF)
32
- message(STATUS "FFmpeg disabled (SHERPA_ONNX_DISABLE_FFMPEG=ON). convertAudioToWav16k/convertAudioToFormat will return an error at runtime.")
32
+ message(STATUS "FFmpeg disabled (SHERPA_ONNX_DISABLE_FFMPEG=ON). convertAudioToWav16k/convertAudioToFormat and decode (non-WAV) will return an error at runtime.")
33
33
  endif()
34
34
 
35
35
  if(USE_FFMPEG)
@@ -39,25 +39,32 @@ set(FFMPEG_PREBUILT_BASE "${PROJECT_ROOT}/../third_party/ffmpeg_prebuilt/android
39
39
  set(FFMPEG_PREBUILT_LIB "${FFMPEG_PREBUILT_BASE}/${ANDROID_ABI}/lib")
40
40
  set(FFMPEG_JNILIBS "${PROJECT_ROOT}/src/main/jniLibs/${ANDROID_ABI}")
41
41
  set(FFMPEG_INCLUDE_CPP "${PROJECT_ROOT}/src/main/cpp/include/ffmpeg")
42
- if(EXISTS "${FFMPEG_PREBUILT_BASE}/include")
42
+ # Require a real header — an empty third_party/.../include/ dir must not win over Gradle-populated cpp/include/ffmpeg.
43
+ if(EXISTS "${FFMPEG_PREBUILT_BASE}/include/libavcodec/avcodec.h")
43
44
  set(FFMPEG_INCLUDE_DIR "${FFMPEG_PREBUILT_BASE}/include")
44
45
  message(STATUS "FFmpeg headers: prebuilts ${FFMPEG_INCLUDE_DIR}")
45
- elseif(EXISTS "${FFMPEG_INCLUDE_CPP}")
46
+ elseif(EXISTS "${FFMPEG_INCLUDE_CPP}/libavcodec/avcodec.h")
46
47
  set(FFMPEG_INCLUDE_DIR "${FFMPEG_INCLUDE_CPP}")
47
- message(STATUS "FFmpeg headers: jniLibs/release ${FFMPEG_INCLUDE_DIR}")
48
+ message(STATUS "FFmpeg headers: module tree ${FFMPEG_INCLUDE_DIR}")
48
49
  else()
49
50
  message(FATAL_ERROR "FFmpeg headers missing. Either:\n"
50
51
  " - Build: cd third_party/ffmpeg_prebuilt && ./build_ffmpeg.sh (creates android/include)\n"
51
52
  " - Or use a release that includes include/ (Gradle extracts to ${FFMPEG_INCLUDE_CPP})")
52
53
  endif()
54
+ # Prebuilts may be either legacy layout android/<abi>/lib/ (build_ffmpeg.sh) or
55
+ # android/jni/<abi>/ (same as Gradle THIRD_PARTY in docs/PREBUILT_RESOLUTION.md).
56
+ set(FFMPEG_PREBUILT_JNI_ABI "${FFMPEG_PREBUILT_BASE}/jni/${ANDROID_ABI}")
53
57
  if(EXISTS "${FFMPEG_PREBUILT_LIB}/libavcodec.so")
54
58
  set(FFMPEG_LIB_DIR "${FFMPEG_PREBUILT_LIB}")
55
59
  message(STATUS "FFmpeg libs: prebuilts ${FFMPEG_LIB_DIR}")
60
+ elseif(EXISTS "${FFMPEG_PREBUILT_JNI_ABI}/libavcodec.so")
61
+ set(FFMPEG_LIB_DIR "${FFMPEG_PREBUILT_JNI_ABI}")
62
+ message(STATUS "FFmpeg libs: prebuilts (jni/<abi>) ${FFMPEG_LIB_DIR}")
56
63
  elseif(EXISTS "${FFMPEG_JNILIBS}/libavcodec.so")
57
64
  set(FFMPEG_LIB_DIR "${FFMPEG_JNILIBS}")
58
65
  message(STATUS "FFmpeg libs: jniLibs ${FFMPEG_LIB_DIR}")
59
66
  else()
60
- message(FATAL_ERROR "FFmpeg libs missing for ABI ${ANDROID_ABI}. Run third_party/ffmpeg_prebuilt/copy_prebuilts_to_sdk.js or ensure ANDROID_RELEASE_TAG release is downloaded.")
67
+ message(FATAL_ERROR "FFmpeg libs missing for ABI ${ANDROID_ABI}. Run a Gradle Android build so prebuilts populate jniLibs, or add local .so under jniLibs / ffmpeg prebuilts paths.")
61
68
  endif()
62
69
  endif(USE_FFMPEG)
63
70
 
@@ -82,7 +89,6 @@ set(SOURCES
82
89
  jni/model_detect/sherpa-onnx-stt-wrapper.cpp
83
90
  jni/model_detect/sherpa-onnx-tts-wrapper.cpp
84
91
  jni/audio/sherpa-onnx-audio-convert-jni.cpp
85
- jni/tts/sherpa-onnx-tts-zipvoice-jni.cpp
86
92
  crypto/sha256.cpp
87
93
  )
88
94
 
@@ -93,10 +99,19 @@ set(LIBARCHIVE_PREBUILT_LIB "${LIBARCHIVE_PREBUILT_BASE}/${ANDROID_ABI}/lib")
93
99
  set(LIBARCHIVE_JNILIBS "${PROJECT_ROOT}/src/main/jniLibs/${ANDROID_ABI}")
94
100
  set(LIBARCHIVE_INCLUDE_CPP "${PROJECT_ROOT}/src/main/cpp/include/libarchive")
95
101
  set(USE_LIBARCHIVE_PREBUILT OFF)
102
+ set(LIBARCHIVE_PREBUILT_JNI_ABI "${LIBARCHIVE_PREBUILT_BASE}/jni/${ANDROID_ABI}")
96
103
  if(EXISTS "${LIBARCHIVE_PREBUILT_LIB}/libarchive.so")
97
104
  set(USE_LIBARCHIVE_PREBUILT ON)
98
105
  set(LIBARCHIVE_LIB_DIR "${LIBARCHIVE_PREBUILT_LIB}")
99
- if(EXISTS "${LIBARCHIVE_PREBUILT_BASE}/include")
106
+ if(EXISTS "${LIBARCHIVE_PREBUILT_BASE}/include/archive.h")
107
+ set(LIBARCHIVE_INCLUDE_DIR "${LIBARCHIVE_PREBUILT_BASE}/include")
108
+ elseif(EXISTS "${LIBARCHIVE_INCLUDE_CPP}/archive.h")
109
+ set(LIBARCHIVE_INCLUDE_DIR "${LIBARCHIVE_INCLUDE_CPP}")
110
+ endif()
111
+ elseif(EXISTS "${LIBARCHIVE_PREBUILT_JNI_ABI}/libarchive.so")
112
+ set(USE_LIBARCHIVE_PREBUILT ON)
113
+ set(LIBARCHIVE_LIB_DIR "${LIBARCHIVE_PREBUILT_JNI_ABI}")
114
+ if(EXISTS "${LIBARCHIVE_PREBUILT_BASE}/include/archive.h")
100
115
  set(LIBARCHIVE_INCLUDE_DIR "${LIBARCHIVE_PREBUILT_BASE}/include")
101
116
  elseif(EXISTS "${LIBARCHIVE_INCLUDE_CPP}/archive.h")
102
117
  set(LIBARCHIVE_INCLUDE_DIR "${LIBARCHIVE_INCLUDE_CPP}")
@@ -128,15 +143,19 @@ add_library(sherpaonnx SHARED
128
143
  # If we used IMPORTED here, AGP would also copy .so from CMake --> duplicate in mergeNativeLibs.
129
144
  set(SHERPA_ONNX_PREBUILT_BASE "${PROJECT_ROOT}/../third_party/sherpa-onnx-prebuilt/android")
130
145
  set(SHERPA_ONNX_ABI_LIB "${SHERPA_ONNX_PREBUILT_BASE}/${ANDROID_ABI}/lib")
146
+ set(SHERPA_ONNX_JNI_ABI "${SHERPA_ONNX_PREBUILT_BASE}/jni/${ANDROID_ABI}")
131
147
  set(SHERPA_C_API_LIB_DIR "")
132
148
  if(EXISTS "${SHERPA_ONNX_ABI_LIB}/libsherpa-onnx-c-api.so")
133
149
  set(SHERPA_C_API_LIB_DIR "${SHERPA_ONNX_ABI_LIB}")
134
150
  message(STATUS "sherpa-onnx C-API (link only): ${SHERPA_C_API_LIB_DIR}")
151
+ elseif(EXISTS "${SHERPA_ONNX_JNI_ABI}/libsherpa-onnx-c-api.so")
152
+ set(SHERPA_C_API_LIB_DIR "${SHERPA_ONNX_JNI_ABI}")
153
+ message(STATUS "sherpa-onnx C-API (link only, third_party jni/<abi>): ${SHERPA_C_API_LIB_DIR}")
135
154
  elseif(EXISTS "${PROJECT_ROOT}/src/main/jniLibs/${ANDROID_ABI}/libsherpa-onnx-c-api.so")
136
155
  set(SHERPA_C_API_LIB_DIR "${PROJECT_ROOT}/src/main/jniLibs/${ANDROID_ABI}")
137
156
  message(STATUS "sherpa-onnx C-API (link only, jniLibs): ${SHERPA_C_API_LIB_DIR}")
138
157
  else()
139
- message(WARNING "sherpa-onnx C-API not found. Zipvoice TTS will not be available. "
158
+ message(WARNING "sherpa-onnx C-API not found. Prebuilt sherpa native libs may be incomplete. "
140
159
  "Build prebuilts: cd third_party/sherpa-onnx-prebuilt && ./build_sherpa_onnx.sh")
141
160
  endif()
142
161
 
@@ -148,7 +167,6 @@ target_include_directories(sherpaonnx PRIVATE
148
167
  ${CMAKE_CURRENT_SOURCE_DIR}/jni/archive
149
168
  ${CMAKE_CURRENT_SOURCE_DIR}/jni/model_detect
150
169
  ${CMAKE_CURRENT_SOURCE_DIR}/jni/audio
151
- ${CMAKE_CURRENT_SOURCE_DIR}/jni/tts
152
170
  ${CMAKE_CURRENT_SOURCE_DIR}/include
153
171
  )
154
172
  if(USE_FFMPEG)
@@ -167,7 +185,7 @@ if(USE_LIBARCHIVE)
167
185
  target_compile_definitions(sherpaonnx PRIVATE HAVE_LIBARCHIVE=1)
168
186
  endif()
169
187
 
170
- # Link libraries (Kotlin API from AAR handles STT/TTS; C-API only for Zipvoice)
188
+ # Link libraries (Kotlin API from AAR handles STT/TTS incl. Zipvoice)
171
189
  if(USE_FFMPEG)
172
190
  target_link_directories(sherpaonnx PRIVATE ${FFMPEG_LIB_DIR})
173
191
  endif()
@@ -75,6 +75,38 @@ static void DrainRemainingAndClose(ArchiveReadContext* ctx) {
75
75
  fclose(ctx->file);
76
76
  ctx->file = nullptr;
77
77
  }
78
+
79
+ struct StreamReadContext {
80
+ std::array<unsigned char, 64 * 1024> buffer{};
81
+ Sha256Context sha_ctx{};
82
+ long long bytes_read = 0;
83
+ ArchiveHelper::StreamReadCallback read_cb = nullptr;
84
+ void* user_data = nullptr;
85
+ };
86
+
87
+ static la_ssize_t ArchiveStreamReadCallback(struct archive* archive, void* client_data, const void** buff) {
88
+ auto* ctx = static_cast<StreamReadContext*>(client_data);
89
+ if (!ctx || !ctx->read_cb) {
90
+ archive_set_error(archive, EINVAL, "Invalid stream read context");
91
+ return -1;
92
+ }
93
+ std::ptrdiff_t n = ctx->read_cb(ctx->buffer.data(), ctx->buffer.size(), ctx->user_data);
94
+ if (n > 0) {
95
+ sha256_update(&ctx->sha_ctx, ctx->buffer.data(), static_cast<size_t>(n));
96
+ ctx->bytes_read += static_cast<long long>(n);
97
+ *buff = ctx->buffer.data();
98
+ return static_cast<la_ssize_t>(n);
99
+ }
100
+ if (n == 0) return 0;
101
+ archive_set_error(archive, EINVAL, "Stream read error");
102
+ return -1;
103
+ }
104
+
105
+ // No-op close callback for stream mode: the stream lifetime is managed by the
106
+ // caller (e.g. a JNI InputStream), so libarchive must not close it.
107
+ static int ArchiveStreamCloseCallback(struct archive* /* archive */, void* /* client_data */) {
108
+ return ARCHIVE_OK;
109
+ }
78
110
  #endif // HAVE_LIBARCHIVE
79
111
 
80
112
  static std::string ToHex(const unsigned char* data, size_t size) {
@@ -122,13 +154,15 @@ bool ArchiveHelper::ExtractTarBz2(
122
154
  return false;
123
155
  }
124
156
 
125
- // Check target directory
157
+ // If target exists and is a directory, extract into it (merge). Otherwise require empty or force-remove.
126
158
  if (std::filesystem::exists(target_path)) {
127
- if (force) {
159
+ if (std::filesystem::is_directory(target_path)) {
160
+ // Merge: extract into existing directory (e.g. multiple archives --> same base path)
161
+ } else if (force) {
128
162
  std::error_code ec;
129
163
  std::filesystem::remove_all(target_path, ec);
130
164
  if (ec) {
131
- if (out_error) *out_error = "Failed to remove target directory: " + ec.message();
165
+ if (out_error) *out_error = "Failed to remove target path: " + ec.message();
132
166
  return false;
133
167
  }
134
168
  } else {
@@ -137,7 +171,6 @@ bool ArchiveHelper::ExtractTarBz2(
137
171
  }
138
172
  }
139
173
 
140
- // Create target directory
141
174
  std::error_code ec;
142
175
  std::filesystem::create_directories(target_path, ec);
143
176
  if (ec) {
@@ -167,11 +200,12 @@ bool ArchiveHelper::ExtractTarBz2(
167
200
  return false;
168
201
  }
169
202
 
170
- // Configure archive to support tar and bzip2
203
+ // Configure archive to support tar and common compression (bzip2, gzip, xz, zstd)
171
204
  archive_read_support_format_tar(archive);
172
205
  archive_read_support_filter_bzip2(archive);
173
206
  archive_read_support_filter_gzip(archive); // Also support gzip for compatibility
174
- archive_read_support_filter_xz(archive); // And xz
207
+ archive_read_support_filter_xz(archive); // And xz
208
+ archive_read_support_filter_zstd(archive); // And zstd (.tar.zst)
175
209
 
176
210
  ArchiveReadContext read_ctx;
177
211
  read_ctx.file = fopen(source_path.c_str(), "rb");
@@ -354,6 +388,18 @@ bool ArchiveHelper::ExtractTarBz2(
354
388
  close_reader();
355
389
  return false;
356
390
  }
391
+
392
+ result = archive_write_finish_entry(disk);
393
+ if (result != ARCHIVE_OK && result != ARCHIVE_WARN) {
394
+ const char* err = archive_error_string(disk);
395
+ if (out_error) {
396
+ *out_error = err ? std::string("Failed to finish entry: ") + err : "Failed to finish entry";
397
+ }
398
+ archive_read_free(archive);
399
+ archive_write_free(disk);
400
+ close_reader();
401
+ return false;
402
+ }
357
403
  }
358
404
 
359
405
  archive_read_free(archive);
@@ -376,6 +422,260 @@ bool ArchiveHelper::ExtractTarBz2(
376
422
  #endif // HAVE_LIBARCHIVE
377
423
  }
378
424
 
425
+ bool ArchiveHelper::ExtractTarZst(
426
+ const std::string& source_path,
427
+ const std::string& target_path,
428
+ bool force,
429
+ std::function<void(long long, long long, double)> on_progress,
430
+ std::string* out_error,
431
+ std::string* out_sha256) {
432
+ return ExtractTarBz2(source_path, target_path, force, on_progress, out_error, out_sha256);
433
+ }
434
+
435
+ bool ArchiveHelper::ExtractFromStream(
436
+ StreamReadCallback read_cb,
437
+ void* read_user_data,
438
+ const std::string& target_path,
439
+ bool force,
440
+ std::function<void(long long, long long, double)> on_progress,
441
+ std::string* out_error,
442
+ std::string* out_sha256) {
443
+ cancel_requested_.store(false);
444
+
445
+ #ifndef HAVE_LIBARCHIVE
446
+ (void)read_cb;
447
+ (void)read_user_data;
448
+ (void)target_path;
449
+ (void)force;
450
+ (void)on_progress;
451
+ (void)out_sha256;
452
+ if (out_error) *out_error = "libarchive not available. Build with libarchive or set sherpaOnnxDisableLibarchive=false in gradle.properties. See docs/disable-libarchive.md.";
453
+ return false;
454
+ #else
455
+ if (!read_cb) {
456
+ if (out_error) *out_error = "Stream read callback is null";
457
+ return false;
458
+ }
459
+
460
+ if (std::filesystem::exists(target_path)) {
461
+ if (std::filesystem::is_directory(target_path)) {
462
+ // Merge: extract into existing directory (e.g. multiple archives --> same base path)
463
+ } else if (force) {
464
+ std::error_code ec;
465
+ std::filesystem::remove_all(target_path, ec);
466
+ if (ec) {
467
+ if (out_error) *out_error = "Failed to remove target path: " + ec.message();
468
+ return false;
469
+ }
470
+ } else {
471
+ if (out_error) *out_error = "Target path already exists";
472
+ return false;
473
+ }
474
+ }
475
+
476
+ std::error_code ec;
477
+ std::filesystem::create_directories(target_path, ec);
478
+ if (ec) {
479
+ if (out_error) *out_error = "Failed to create target directory: " + ec.message();
480
+ return false;
481
+ }
482
+
483
+ #ifndef NDEBUG
484
+ __android_log_print(ANDROID_LOG_INFO, "SherpaOnnx",
485
+ "ExtractFromStream target_path=%s", target_path.c_str());
486
+ #endif
487
+
488
+ std::string canonical_target = std::filesystem::canonical(target_path).string();
489
+ if (canonical_target.back() != '/') canonical_target += '/';
490
+
491
+ const long long total_bytes = 0;
492
+
493
+ struct archive* archive = archive_read_new();
494
+ if (!archive) {
495
+ if (out_error) *out_error = "Failed to create archive reader";
496
+ return false;
497
+ }
498
+
499
+ archive_read_support_format_tar(archive);
500
+ archive_read_support_filter_bzip2(archive);
501
+ archive_read_support_filter_gzip(archive);
502
+ archive_read_support_filter_xz(archive);
503
+ archive_read_support_filter_zstd(archive);
504
+
505
+ StreamReadContext stream_ctx;
506
+ stream_ctx.read_cb = read_cb;
507
+ stream_ctx.user_data = read_user_data;
508
+ sha256_init(&stream_ctx.sha_ctx);
509
+
510
+ if (archive_read_open(archive, &stream_ctx, nullptr, ArchiveStreamReadCallback, ArchiveStreamCloseCallback) != ARCHIVE_OK) {
511
+ const char* err = archive_error_string(archive);
512
+ if (out_error) *out_error = err ? std::string("Failed to open archive: ") + err : "Failed to open archive";
513
+ archive_read_free(archive);
514
+ return false;
515
+ }
516
+
517
+ struct archive* disk = archive_write_disk_new();
518
+ if (!disk) {
519
+ if (out_error) *out_error = "Failed to create disk writer";
520
+ archive_read_free(archive);
521
+ return false;
522
+ }
523
+
524
+ archive_write_disk_set_options(disk,
525
+ ARCHIVE_EXTRACT_TIME |
526
+ ARCHIVE_EXTRACT_PERM |
527
+ ARCHIVE_EXTRACT_ACL |
528
+ ARCHIVE_EXTRACT_FFLAGS);
529
+ archive_write_disk_set_standard_lookup(disk);
530
+
531
+ struct archive_entry* entry = nullptr;
532
+ int result = ARCHIVE_OK;
533
+ long long extracted_bytes = 0;
534
+ int last_percent = -1;
535
+ long long last_emit_bytes = 0;
536
+ int entry_index = 0;
537
+
538
+ while ((result = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) {
539
+ if (cancel_requested_.load()) {
540
+ if (out_error) *out_error = "Extraction cancelled";
541
+ archive_read_free(archive);
542
+ archive_write_free(disk);
543
+ return false;
544
+ }
545
+
546
+ const char* current_path = archive_entry_pathname(entry);
547
+ if (!current_path) {
548
+ archive_read_free(archive);
549
+ archive_write_free(disk);
550
+ if (out_error) *out_error = "Invalid entry path";
551
+ return false;
552
+ }
553
+
554
+ std::string entry_path(current_path);
555
+ std::string full_path = target_path;
556
+ if (full_path.back() != '/') full_path += '/';
557
+ full_path += entry_path;
558
+
559
+ std::string canonical_entry;
560
+ try {
561
+ std::filesystem::path p(full_path);
562
+ std::filesystem::path parent = p.parent_path();
563
+ if (std::filesystem::exists(parent)) {
564
+ canonical_entry = std::filesystem::canonical(parent).string();
565
+ } else {
566
+ while (!std::filesystem::exists(parent) && parent != parent.parent_path()) {
567
+ parent = parent.parent_path();
568
+ }
569
+ if (std::filesystem::exists(parent)) {
570
+ canonical_entry = std::filesystem::canonical(parent).string();
571
+ } else {
572
+ canonical_entry = canonical_target;
573
+ }
574
+ }
575
+ canonical_entry += '/';
576
+ canonical_entry += p.filename().string();
577
+ } catch (const std::exception&) {
578
+ canonical_entry = full_path;
579
+ }
580
+
581
+ if (canonical_entry.find(canonical_target) != 0) {
582
+ archive_read_free(archive);
583
+ archive_write_free(disk);
584
+ if (out_error) *out_error = "Blocked path traversal: " + entry_path;
585
+ return false;
586
+ }
587
+
588
+ archive_entry_set_pathname(entry, full_path.c_str());
589
+
590
+ result = archive_write_header(disk, entry);
591
+ if (result != ARCHIVE_OK) {
592
+ const char* err = archive_error_string(disk);
593
+ if (out_error) *out_error = err ? std::string("Failed to write entry: ") + err : "Failed to write entry";
594
+ archive_read_free(archive);
595
+ archive_write_free(disk);
596
+ return false;
597
+ }
598
+
599
+ const void* buff = nullptr;
600
+ size_t size = 0;
601
+ la_int64_t offset = 0;
602
+
603
+ while ((result = archive_read_data_block(archive, &buff, &size, &offset)) == ARCHIVE_OK) {
604
+ if (cancel_requested_.load()) {
605
+ if (out_error) *out_error = "Extraction cancelled";
606
+ archive_read_free(archive);
607
+ archive_write_free(disk);
608
+ return false;
609
+ }
610
+
611
+ result = archive_write_data_block(disk, buff, size, offset);
612
+ if (result != ARCHIVE_OK) {
613
+ const char* err = archive_error_string(disk);
614
+ if (out_error) *out_error = err ? std::string("Failed to write data: ") + err : "Failed to write data";
615
+ archive_read_free(archive);
616
+ archive_write_free(disk);
617
+ return false;
618
+ }
619
+
620
+ extracted_bytes += static_cast<long long>(size);
621
+
622
+ if (on_progress) {
623
+ if (total_bytes > 0) {
624
+ long long compressed_bytes = archive_filter_bytes(archive, -1);
625
+ int percent = static_cast<int>(total_bytes > 0 ? (compressed_bytes * 100) / total_bytes : 0);
626
+ percent = (percent > 100) ? 100 : ((percent < 0) ? 0 : percent);
627
+ if (percent != last_percent) {
628
+ last_percent = percent;
629
+ on_progress(compressed_bytes, total_bytes, static_cast<double>(percent));
630
+ }
631
+ } else if (stream_ctx.bytes_read - last_emit_bytes >= 1024 * 1024) {
632
+ last_emit_bytes = stream_ctx.bytes_read;
633
+ on_progress(stream_ctx.bytes_read, 0, 0.0);
634
+ }
635
+ }
636
+ }
637
+
638
+ if (result != ARCHIVE_EOF && result != ARCHIVE_OK) {
639
+ const char* err = archive_error_string(archive);
640
+ if (out_error) *out_error = err ? std::string("Failed to read data: ") + err : "Failed to read data";
641
+ archive_read_free(archive);
642
+ archive_write_free(disk);
643
+ return false;
644
+ }
645
+
646
+ result = archive_write_finish_entry(disk);
647
+ if (result != ARCHIVE_OK && result != ARCHIVE_WARN) {
648
+ const char* err = archive_error_string(disk);
649
+ if (out_error) *out_error = err ? std::string("Failed to finish entry: ") + err : "Failed to finish entry";
650
+ archive_read_free(archive);
651
+ archive_write_free(disk);
652
+ return false;
653
+ }
654
+ entry_index++;
655
+ }
656
+
657
+ #ifndef NDEBUG
658
+ __android_log_print(ANDROID_LOG_INFO, "SherpaOnnx",
659
+ "ExtractFromStream done entries=%d", entry_index);
660
+ #endif
661
+
662
+ archive_read_free(archive);
663
+ archive_write_free(disk);
664
+
665
+ if (out_sha256) {
666
+ unsigned char digest[32];
667
+ sha256_final(&stream_ctx.sha_ctx, digest);
668
+ *out_sha256 = ToHex(digest, sizeof(digest));
669
+ }
670
+
671
+ if (on_progress) {
672
+ on_progress(stream_ctx.bytes_read, stream_ctx.bytes_read, 100.0);
673
+ }
674
+
675
+ return true;
676
+ #endif
677
+ }
678
+
379
679
  bool ArchiveHelper::ComputeFileSha256(
380
680
  const std::string& file_path,
381
681
  std::string* out_error,
@@ -1,5 +1,6 @@
1
1
  #pragma once
2
2
 
3
+ #include <cstddef>
3
4
  #include <string>
4
5
  #include <functional>
5
6
  #include <atomic>
@@ -10,14 +11,17 @@
10
11
  */
11
12
  class ArchiveHelper {
12
13
  public:
14
+ /** Callback to read bytes from a stream (e.g. Java InputStream via JNI). Returns bytes read, 0 on EOF, -1 on error. */
15
+ using StreamReadCallback = std::ptrdiff_t (*)(void* buf, size_t len, void* user_data);
16
+
13
17
  /**
14
- * Extract tar.bz2 file to target directory
18
+ * Extract tar.bz2 (or .tar.zst, .tar.gz, .tar.xz) file to target directory.
15
19
  *
16
- * @param sourcePath Path to the .tar.bz2 file
20
+ * @param sourcePath Path to the archive file
17
21
  * @param targetPath Destination directory path
18
22
  * @param force Whether to overwrite existing target directory
19
23
  * @param onProgress Callback for progress updates (bytesExtracted, totalBytes, percent)
20
- * @param outSha256 Optional output SHA-256 hex of the archive file
24
+ * @param outSha256 Optional output SHA-256 hex of the archive file
21
25
  * @return true if extraction succeeded, false otherwise
22
26
  */
23
27
  static bool ExtractTarBz2(
@@ -28,7 +32,32 @@ class ArchiveHelper {
28
32
  std::string* out_error = nullptr,
29
33
  std::string* out_sha256 = nullptr);
30
34
 
31
- /**
35
+ /**
36
+ * Extract .tar.zst (or other supported tar compression) file to target directory.
37
+ * Uses the same implementation as ExtractTarBz2 (libarchive supports zstd when built with ENABLE_ZSTD).
38
+ */
39
+ static bool ExtractTarZst(
40
+ const std::string& source_path,
41
+ const std::string& target_path,
42
+ bool force,
43
+ std::function<void(long long, long long, double)> on_progress = nullptr,
44
+ std::string* out_error = nullptr,
45
+ std::string* out_sha256 = nullptr);
46
+
47
+ /**
48
+ * Extract a tar archive (tar.zst or tar.bz2) from a stream via read_cb.
49
+ * Used for Android AssetManager streams; total_bytes can be 0 (progress then uses compressed bytes or periodic emit).
50
+ */
51
+ static bool ExtractFromStream(
52
+ StreamReadCallback read_cb,
53
+ void* read_user_data,
54
+ const std::string& target_path,
55
+ bool force,
56
+ std::function<void(long long, long long, double)> on_progress = nullptr,
57
+ std::string* out_error = nullptr,
58
+ std::string* out_sha256 = nullptr);
59
+
60
+ /**
32
61
  * Compute SHA-256 of a file.
33
62
  *
34
63
  * @param file_path Path to the file