react-native-sherpa-onnx 0.3.3 → 0.3.4

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 (68) hide show
  1. package/README.md +56 -62
  2. package/SherpaOnnx.podspec +69 -43
  3. package/android/build.gradle +8 -2
  4. package/android/prebuilt-download.gradle +53 -12
  5. package/android/prebuilt-versions.gradle +6 -2
  6. package/android/src/main/cpp/CMakeLists.txt +2 -0
  7. package/android/src/main/cpp/jni/audio/sherpa-onnx-audio-convert-jni.cpp +202 -328
  8. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-detect-jni-common.cpp +22 -0
  9. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-detect-jni-common.h +2 -0
  10. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-helper.cpp +53 -0
  11. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-helper.h +28 -0
  12. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-stt.cpp +85 -14
  13. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-tts.cpp +37 -46
  14. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect.h +2 -0
  15. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-tts-wrapper.cpp +14 -2
  16. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-stt.cpp +229 -0
  17. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-stt.h +38 -0
  18. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-tts.cpp +144 -0
  19. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-tts.h +38 -0
  20. package/android/src/main/cpp/jni/module/sherpa-onnx-module-jni.cpp +1 -1
  21. package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +87 -11
  22. package/android/src/main/java/com/sherpaonnx/SherpaOnnxSttHelper.kt +36 -5
  23. package/android/src/main/java/com/sherpaonnx/SherpaOnnxTtsHelper.kt +52 -1
  24. package/ios/SherpaOnnx+TTS.mm +17 -0
  25. package/ios/SherpaOnnx.mm +26 -2
  26. package/ios/SherpaOnnxAudioConvert.h +28 -0
  27. package/ios/SherpaOnnxAudioConvert.mm +698 -0
  28. package/ios/archive/sherpa-onnx-archive-helper.mm +12 -0
  29. package/ios/model_detect/sherpa-onnx-model-detect-helper.h +28 -0
  30. package/ios/model_detect/sherpa-onnx-model-detect-helper.mm +51 -0
  31. package/ios/model_detect/sherpa-onnx-model-detect-stt.mm +12 -3
  32. package/ios/model_detect/sherpa-onnx-model-detect-tts.mm +36 -47
  33. package/ios/model_detect/sherpa-onnx-model-detect.h +2 -0
  34. package/ios/model_detect/sherpa-onnx-validate-stt.h +38 -0
  35. package/ios/model_detect/sherpa-onnx-validate-stt.mm +229 -0
  36. package/ios/model_detect/sherpa-onnx-validate-tts.h +38 -0
  37. package/ios/model_detect/sherpa-onnx-validate-tts.mm +144 -0
  38. package/lib/module/NativeSherpaOnnx.js.map +1 -1
  39. package/lib/module/audio/index.js +3 -1
  40. package/lib/module/audio/index.js.map +1 -1
  41. package/lib/module/download/ModelDownloadManager.js +14 -0
  42. package/lib/module/download/ModelDownloadManager.js.map +1 -1
  43. package/lib/module/index.js +10 -0
  44. package/lib/module/index.js.map +1 -1
  45. package/lib/module/tts/index.js +13 -1
  46. package/lib/module/tts/index.js.map +1 -1
  47. package/lib/typescript/src/NativeSherpaOnnx.d.ts +16 -1
  48. package/lib/typescript/src/NativeSherpaOnnx.d.ts.map +1 -1
  49. package/lib/typescript/src/audio/index.d.ts +3 -1
  50. package/lib/typescript/src/audio/index.d.ts.map +1 -1
  51. package/lib/typescript/src/download/ModelDownloadManager.d.ts +2 -1
  52. package/lib/typescript/src/download/ModelDownloadManager.d.ts.map +1 -1
  53. package/lib/typescript/src/index.d.ts +10 -0
  54. package/lib/typescript/src/index.d.ts.map +1 -1
  55. package/lib/typescript/src/tts/index.d.ts +12 -1
  56. package/lib/typescript/src/tts/index.d.ts.map +1 -1
  57. package/package.json +1 -1
  58. package/scripts/setup-ios-framework.sh +267 -186
  59. package/src/NativeSherpaOnnx.ts +19 -1
  60. package/src/audio/index.ts +3 -1
  61. package/src/download/ModelDownloadManager.ts +19 -0
  62. package/src/index.tsx +15 -0
  63. package/src/tts/index.ts +25 -1
  64. package/third_party/ffmpeg_prebuilt/ANDROID_RELEASE_TAG +1 -1
  65. package/third_party/libarchive_prebuilt/ANDROID_RELEASE_TAG +1 -1
  66. package/third_party/libarchive_prebuilt/IOS_RELEASE_TAG +1 -1
  67. package/ios/scripts/patch-libarchive-includes.sh +0 -61
  68. package/ios/scripts/setup-ios-libarchive.sh +0 -98
package/README.md CHANGED
@@ -23,16 +23,57 @@ React Native SDK for sherpa-onnx – offline and streaming speech processing
23
23
 
24
24
  A React Native TurboModule that provides offline and streaming speech processing capabilities using [sherpa-onnx](https://github.com/k2-fsa/sherpa-onnx). The SDK aims to support all functionalities that sherpa-onnx offers, including offline and **online (streaming)** speech-to-text, text-to-speech (batch and streaming), speaker diarization, speech enhancement, source separation, and VAD (Voice Activity Detection).
25
25
 
26
+ ## Installation
27
+
28
+ ```sh
29
+ npm install react-native-sherpa-onnx
30
+ ```
31
+
32
+ If your project uses Yarn (v3+) or Plug'n'Play, configure Yarn to use the Node Modules linker to avoid postinstall issues:
33
+
34
+ ```yaml
35
+ # .yarnrc.yml
36
+ nodeLinker: node-modules
37
+ ```
38
+
39
+ Alternatively, set the environment variable during install:
40
+
41
+ ```sh
42
+ YARN_NODE_LINKER=node-modules yarn install
43
+ ```
44
+
45
+ ### Android
46
+
47
+ No additional setup required. The library automatically handles native dependencies via Gradle. For execution provider support (CPU, NNAPI, XNNPACK, QNN) and optional QNN setup, see [Execution provider support](./docs/execution-providers.md). For building Android native libs yourself, see [sherpa-onnx-prebuilt](third_party/sherpa-onnx-prebuilt/README.md).
48
+
49
+ ### iOS
50
+
51
+ The sherpa-onnx **XCFramework is not shipped in the repo or npm** (size ~80MB). It is **downloaded automatically** when you run `pod install`; no manual steps are required. The version used is pinned in `third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG` and the archive is fetched from [GitHub Releases](https://github.com/XDcobra/react-native-sherpa-onnx/releases?q=framework).
52
+
53
+ #### Setup
54
+
55
+ ```sh
56
+ cd your-app/ios
57
+ bundle install
58
+ bundle exec pod install
59
+ ```
60
+
61
+ The podspec runs `scripts/setup-ios-framework.sh`, which downloads the XCFramework (and, if needed, libarchive sources) so the Pod builds correctly. Libarchive is compiled from source as part of the Pod; its version is pinned in `third_party/libarchive_prebuilt/IOS_RELEASE_TAG`.
62
+
63
+ #### Building the iOS framework
64
+
65
+ To build the sherpa-onnx iOS XCFramework yourself (e.g. custom version or patches), see [third_party/sherpa-onnx-prebuilt/README.md](third_party/sherpa-onnx-prebuilt/README.md) and the [build-sherpa-onnx-ios-framework](.github/workflows/build-sherpa-onnx-ios-framework.yml) workflow.
66
+
26
67
  ## Table of contents
27
68
 
69
+ - [Installation](#installation)
70
+ - [Android](#android)
71
+ - [iOS](#ios)
28
72
  - [Feature Support](#feature-support)
29
73
  - [Platform Support Status](#platform-support-status)
30
74
  - [Supported Model Types](#supported-model-types)
31
75
  - [Speech-to-Text (STT) Models](#speech-to-text-stt-models)
32
76
  - [Text-to-Speech (TTS) Models](#text-to-speech-tts-models)
33
- - [Installation](#installation)
34
- - [Android](#android)
35
- - [iOS](#ios)
36
77
  - [Documentation](#documentation)
37
78
  - [Requirements](#requirements)
38
79
  - [Breaking changes (upgrading to 0.3.0)](#breaking-changes-upgrading-to-030)
@@ -50,12 +91,13 @@ A React Native TurboModule that provides offline and streaming speech processing
50
91
  | Feature | Status | Notes |
51
92
  |---------|--------|-------|
52
93
  | Offline Speech-to-Text | ✅ **Supported** | No internet required; multiple model types (Zipformer, Paraformer, Whisper, etc.). See [Supported Model Types](#supported-model-types) and [STT documentation](./docs/stt.md). |
53
- | Online (streaming) Speech-to-Text | ✅ **Supported** | Real-time recognition from microphone or stream; partial results, endpoint detection. Use streaming-capable models (e.g. transducer, paraformer). See [Streaming STT](./docs/stt_streaming.md). |
94
+ | Online (streaming) Speech-to-Text | ✅ **Supported** | Real-time recognition from microphone or stream; partial results, endpoint detection. Use streaming-capable models (e.g. transducer, paraformer). See [Streaming STT](./docs/stt-streaming.md). |
95
+ | Live capture API | ✅ **Supported** | Native microphone capture with resampling for live transcription (use with streaming STT). See [PCM Live Stream](./docs/pcm-live-stream.md). |
54
96
  | Text-to-Speech | ✅ **Supported** | Multiple model types (VITS, Matcha, Kokoro, etc.). See [Supported Model Types](#supported-model-types) and [TTS documentation](./docs/tts.md). |
55
- | Streaming Text-to-Speech | ✅ **Supported** | Incremental speech generation for low time-to-first-byte and playback while generating. See [Streaming TTS](./docs/tts_streaming.md). |
97
+ | Streaming Text-to-Speech | ✅ **Supported** | Incremental speech generation for low time-to-first-byte and playback while generating. See [Streaming TTS](./docs/tts-streaming.md). |
56
98
  | Execution providers (CPU, NNAPI, XNNPACK, Core ML, QNN) | ✅ **Supported** | See [Execution provider support](./docs/execution-providers.md). |
57
- | Play Asset Delivery (PAD) | ✅ **Supported** | Android only. See [Model Setup](./docs/MODEL_SETUP.md). |
58
- | Automatic Model type detection | ✅ **Supported** | `detectSttModel()` and `detectTtsModel()` for a path. See [Model Setup: Model type detection](./docs/MODEL_SETUP.md#model-type-detection-without-initialization). |
99
+ | Play Asset Delivery (PAD) | ✅ **Supported** | Android only. See [Model Setup](./docs/model-setup.md). |
100
+ | Automatic Model type detection | ✅ **Supported** | `detectSttModel()` and `detectTtsModel()` for a path. See [Model Setup: Model type detection](./docs/model-setup.md#model-detection). |
59
101
  | Model quantization | ✅ **Supported** | Automatic detection and preference for quantized (int8) models. |
60
102
  | Flexible model loading | ✅ **Supported** | Asset models, file system models, or auto-detection. |
61
103
  | TypeScript | ✅ **Supported** | Full type definitions included. |
@@ -95,7 +137,7 @@ A React Native TurboModule that provides offline and streaming speech processing
95
137
  | **Telespeech CTC** | `'telespeech_ctc'`| Telespeech CTC. Folder name should contain **telespeech**. | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/telespeech/index.html) |
96
138
  | **Tone CTC (t-one)** | `'tone_ctc'` | Lightweight streaming CTC (e.g. t-one). Folder name should contain **t-one**, **t_one**, or **tone** (as word). | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/online-ctc/index.html) |
97
139
 
98
- For **real-time (streaming) recognition** from a microphone or audio stream, use streaming-capable model types: `transducer`, `paraformer`, `zipformer2_ctc`, `nemo_ctc`, or `tone_ctc`. See [Streaming (Online) Speech-to-Text](./docs/stt_streaming.md).
140
+ For **real-time (streaming) recognition** from a microphone or audio stream, use streaming-capable model types: `transducer`, `paraformer`, `zipformer2_ctc`, `nemo_ctc`, or `tone_ctc`. See [Streaming (Online) Speech-to-Text](./docs/stt-streaming.md).
99
141
 
100
142
  ### Text-to-Speech (TTS) Models
101
143
 
@@ -108,74 +150,26 @@ For **real-time (streaming) recognition** from a microphone or audio stream, use
108
150
  | **Zipvoice** | `'zipvoice'` | Voice cloning (encoder + decoder + vocoder). Detected by file layout; folder token optional. | [Download](https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/zipvoice.html) |
109
151
  | **Pocket** | `'pocket'` | Flow-matching TTS. Detected by lm_flow, lm_main, text_conditioner, vocab/token_scores; no folder token required. | [Download](https://github.com/k2-fsa/sherpa-onnx/releases/tag/tts-models) |
110
152
 
111
- For **streaming TTS** (incremental generation, low latency), use `createStreamingTTS()` with supported model types. See [Streaming Text-to-Speech](./docs/tts_streaming.md).
112
-
113
- ## Installation
114
-
115
- ```sh
116
- npm install react-native-sherpa-onnx
117
- ```
118
-
119
- If your project uses Yarn (v3+) or Plug'n'Play, configure Yarn to use the Node Modules linker to avoid postinstall issues:
120
-
121
- ```yaml
122
- # .yarnrc.yml
123
- nodeLinker: node-modules
124
- ```
125
-
126
- Alternatively, set the environment variable during install:
127
-
128
- ```sh
129
- YARN_NODE_LINKER=node-modules yarn install
130
- ```
131
-
132
- ### Android
133
-
134
- No additional setup required. The library automatically handles native dependencies via Gradle. For execution provider support (CPU, NNAPI, XNNPACK, QNN) and optional QNN setup, see [Execution provider support](./docs/execution-providers.md). For building Android native libs yourself, see [sherpa-onnx-prebuilt](third_party/sherpa-onnx-prebuilt/README.md).
135
-
136
-
137
- ### iOS
138
-
139
- The sherpa-onnx **XCFramework is not shipped in the repo or npm** (size ~80MB). It is **downloaded automatically** when you run `pod install`; no manual steps are required. The version used is pinned in `third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG` and the archive is fetched from [GitHub Releases](https://github.com/XDcobra/react-native-sherpa-onnx/releases?q=framework).
140
-
141
- #### Setup
142
-
143
- ```sh
144
- cd your-app/ios
145
- bundle install
146
- bundle exec pod install
147
- ```
148
-
149
- The podspec runs `scripts/setup-ios-framework.sh`, which downloads the XCFramework (and, if needed, libarchive sources) so the Pod builds correctly. Libarchive is compiled from source as part of the Pod; its version is pinned in `third_party/libarchive_prebuilt/IOS_RELEASE_TAG`.
150
-
151
- #### For Advanced Users: Building the Framework Locally
152
- #### Advanced: Building the iOS framework yourself
153
-
154
- If you need a custom sherpa-onnx build (e.g. different version or patches), you can build the XCFramework and place it in `ios/Frameworks/` before running `pod install`. The repo does not include an iOS build script; use one of:
155
-
156
- - **This repo's CI:** The [build-sherpa-onnx-ios-framework](.github/workflows/build-sherpa-onnx-ios-framework.yml) workflow produces the XCFramework and publishes it as a GitHub Release. You can run equivalent steps locally or inspect the workflow for the exact build and merge steps (including `libsherpa-onnx-cxx-api.a` and libarchive).
157
- - **Version and layout:** Pinned version and release layout are documented in [third_party/sherpa-onnx-prebuilt](third_party/sherpa-onnx-prebuilt/README.md) (Android focus; for iOS, see `IOS_RELEASE_TAG` and the [iOS framework workflow](.github/workflows/build-sherpa-onnx-ios-framework.yml)).
158
-
159
- The XCFramework must include the C++ API (`libsherpa-onnx-cxx-api.a` merged or linked) so that the iOS Obj-C++ code can use `sherpa_onnx::cxx::*`. The workflow's build script ensures this; if you use upstream `build-ios.sh` from sherpa-onnx, you may need to merge the C++ API into the static library yourself.
153
+ For **streaming TTS** (incremental generation, low latency), use `createStreamingTTS()` with supported model types. See [Streaming Text-to-Speech](./docs/tts-streaming.md).
160
154
 
161
155
  ## Documentation
162
156
 
163
157
  - [Speech-to-Text (STT)](./docs/stt.md) – Offline transcription (file or samples)
164
- - [Streaming (Online) Speech-to-Text](./docs/stt_streaming.md) – Real-time recognition, partial results, endpoint detection
165
- - [PCM Live Stream](./docs/pcm_live_stream.md) – Native microphone capture with resampling for live transcription (use with streaming STT)
158
+ - [Streaming (Online) Speech-to-Text](./docs/stt-streaming.md) – Real-time recognition, partial results, endpoint detection
159
+ - [PCM Live Stream](./docs/pcm-live-stream.md) – Native microphone capture with resampling for live transcription (use with streaming STT)
166
160
  - [Text-to-Speech (TTS)](./docs/tts.md) – Offline and streaming generation
167
- - [Streaming Text-to-Speech](./docs/tts_streaming.md) – Incremental TTS (createStreamingTTS)
161
+ - [Streaming Text-to-Speech](./docs/tts-streaming.md) – Incremental TTS (createStreamingTTS)
168
162
  - [Execution provider support (QNN, NNAPI, XNNPACK, Core ML)](./docs/execution-providers.md) – Checking and using acceleration backends
169
163
  - [Voice Activity Detection (VAD)](./docs/vad.md)
170
164
  - [Speaker Diarization](./docs/diarization.md)
171
165
  - [Speech Enhancement](./docs/enhancement.md)
172
166
  - [Source Separation](./docs/separation.md)
173
- - [Model Setup](./docs/MODEL_SETUP.md) – Bundled assets, Play Asset Delivery (PAD), model discovery APIs, and troubleshooting
167
+ - [Model Setup](./docs/model-setup.md) – Bundled assets, Play Asset Delivery (PAD), model discovery APIs, and troubleshooting
174
168
  - [Model Download Manager](./docs/download-manager.md)
175
169
  - [Disable FFMPEG](./docs/disable-ffmpeg.md)
176
170
  - [Disable LIBARCHIVE](./docs/disable-libarchive.md)
177
171
 
178
- Note: For when to use `listAssetModels()` vs `listModelsAtPath()` and how to combine bundled and PAD/file-based models, see [Model Setup](./docs/MODEL_SETUP.md).
172
+ Note: For when to use `listAssetModels()` vs `listModelsAtPath()` and how to combine bundled and PAD/file-based models, see [Model Setup](./docs/model-setup.md).
179
173
 
180
174
  ## Requirements
181
175
 
@@ -2,40 +2,6 @@ require "json"
2
2
 
3
3
  package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
4
  pod_root = __dir__
5
- # Prefer libarchive_prebuilt layout (output of third_party/libarchive_prebuilt/build_libarchive_ios.sh).
6
- # Fallback: download via setup-ios-libarchive.sh to ios/Downloads/libarchive (e.g. when using SDK from npm).
7
- libarchive_prebuilt = File.join(pod_root, "third_party", "libarchive_prebuilt", "libarchive-ios-layout")
8
- libarchive_downloads = File.join(pod_root, "ios", "Downloads", "libarchive")
9
- unless File.directory?(libarchive_prebuilt) && Dir.glob(File.join(libarchive_prebuilt, "*.c")).any?
10
- libarchive_script = File.join(pod_root, "ios", "scripts", "setup-ios-libarchive.sh")
11
- if File.exist?(libarchive_script)
12
- unless system("bash", libarchive_script)
13
- abort("[SherpaOnnx] setup-ios-libarchive.sh failed. Check that third_party/libarchive_prebuilt/IOS_RELEASE_TAG exists and the release is available (network). Run the script manually: bash #{libarchive_script}")
14
- end
15
- end
16
- end
17
- libarchive_dir = (File.directory?(libarchive_prebuilt) && Dir.glob(File.join(libarchive_prebuilt, "*.c")).any?) ? libarchive_prebuilt : libarchive_downloads
18
- # Patch libarchive .c files (copy to ios/patched_libarchive with stdio.h/unistd.h added) so we don't modify the submodule.
19
- patched_dir = File.join(pod_root, "ios", "patched_libarchive")
20
- patch_script = File.join(pod_root, "ios", "scripts", "patch-libarchive-includes.sh")
21
- if File.directory?(libarchive_dir) && File.exist?(patch_script)
22
- unless system("bash", patch_script, libarchive_dir)
23
- abort("[SherpaOnnx] patch-libarchive-includes.sh failed. Check that #{libarchive_dir} contains libarchive .c/.h files.")
24
- end
25
- end
26
- # Libarchive C sources: use patched copies (same exclude as before: test, windows, linux, sunos, freebsd).
27
- libarchive_sources = if File.directory?(patched_dir)
28
- Dir.glob(File.join(patched_dir, "*.c")).reject { |f|
29
- base = File.basename(f, ".c")
30
- File.basename(f) =~ /^test\./ || base.include?("windows") || base.include?("linux") || base.include?("sunos") || base.include?("freebsd")
31
- }.map { |f| Pathname.new(f).relative_path_from(Pathname.new(pod_root)).to_s.gsub("\\", "/") }
32
- else
33
- []
34
- end
35
-
36
- if libarchive_sources.empty?
37
- abort("[SherpaOnnx] Libarchive sources missing. Ensure third_party/libarchive_prebuilt/libarchive-ios-layout exists (run third_party/libarchive_prebuilt/build_libarchive_ios.sh) or ios/scripts/setup-ios-libarchive.sh has run, and that ios/scripts/patch-libarchive-includes.sh succeeds. Check pod install logs for patch script errors.")
38
- end
39
5
 
40
6
  # Run iOS framework setup when podspec is loaded (works for :path pods).
41
7
  setup_script = File.join(pod_root, "scripts", "setup-ios-framework.sh")
@@ -44,7 +10,7 @@ if File.exist?(setup_script)
44
10
  ENV["SHERPA_ONNX_PROJECT_ROOT"] = pod_root
45
11
  unless system("bash", setup_script)
46
12
  ENV["SHERPA_ONNX_PROJECT_ROOT"] = prev
47
- abort("[SherpaOnnx] setup-ios-framework.sh failed. Check third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG and network. Run manually: bash #{setup_script}")
13
+ abort("[SherpaOnnx] setup-ios-framework.sh failed. Check IOS_RELEASE_TAG files (sherpa-onnx-prebuilt, ffmpeg_prebuilt, libarchive_prebuilt) and network. Run manually: bash #{setup_script}")
48
14
  end
49
15
  ENV["SHERPA_ONNX_PROJECT_ROOT"] = prev
50
16
  end
@@ -60,11 +26,31 @@ Pod::Spec.new do |s|
60
26
  s.platforms = { :ios => min_ios_version_supported }
61
27
  s.source = { :git => "https://github.com/XDcobra/react-native-sherpa-onnx.git", :tag => "#{s.version}" }
62
28
 
63
- s.source_files = ["ios/**/*.{h,m,mm,swift,cpp}", *libarchive_sources]
29
+ s.source_files = ["ios/**/*.{h,m,mm,swift,cpp}"]
64
30
  s.private_header_files = "ios/**/*.h"
65
31
 
66
32
  s.frameworks = "Foundation", "Accelerate", "CoreML", "AVFoundation", "AudioToolbox"
67
- s.vendored_frameworks = "ios/Frameworks/sherpa_onnx.xcframework"
33
+
34
+ ffmpeg_xcframework = File.join(pod_root, "ios", "Frameworks", "FFmpeg.xcframework")
35
+ libarchive_xcframework = File.join(pod_root, "ios", "Frameworks", "libarchive.xcframework")
36
+
37
+ has_ffmpeg = false
38
+ disable_ffmpeg = ENV['SHERPA_ONNX_DISABLE_FFMPEG']
39
+ if (!disable_ffmpeg || disable_ffmpeg == '0' || disable_ffmpeg == 'false') && File.exist?(ffmpeg_xcframework)
40
+ has_ffmpeg = true
41
+ end
42
+
43
+ has_libarchive = false
44
+ disable_libarchive = ENV['SHERPA_ONNX_DISABLE_LIBARCHIVE']
45
+ if (!disable_libarchive || disable_libarchive == '0' || disable_libarchive == 'false') && File.exist?(libarchive_xcframework)
46
+ has_libarchive = true
47
+ end
48
+
49
+ vendored = ["ios/Frameworks/sherpa_onnx.xcframework"]
50
+ vendored << "ios/Frameworks/FFmpeg.xcframework" if has_ffmpeg
51
+ vendored << "ios/Frameworks/libarchive.xcframework" if has_libarchive
52
+
53
+ s.vendored_frameworks = vendored
68
54
  # Absolute paths so headers are found regardless of PODS_TARGET_SRCROOT (e.g. when building via React Native CLI).
69
55
  xcframework_root = File.join(pod_root, "ios", "Frameworks", "sherpa_onnx.xcframework")
70
56
  simulator_headers = File.join(xcframework_root, "ios-arm64_x86_64-simulator", "Headers")
@@ -72,14 +58,54 @@ Pod::Spec.new do |s|
72
58
  simulator_slice = File.join(xcframework_root, "ios-arm64_x86_64-simulator")
73
59
  device_slice = File.join(xcframework_root, "ios-arm64")
74
60
 
61
+ libarchive_xcframework_root = File.join(pod_root, "ios", "Frameworks", "libarchive.xcframework")
62
+ libarchive_simulator_headers = File.join(libarchive_xcframework_root, "ios-arm64_x86_64-simulator", "Headers")
63
+ libarchive_device_headers = File.join(libarchive_xcframework_root, "ios-arm64", "Headers")
64
+
65
+ ffmpeg_simulator_headers = File.join(ffmpeg_xcframework, "ios-arm64_x86_64-simulator", "Headers")
66
+ ffmpeg_device_headers = File.join(ffmpeg_xcframework, "ios-arm64", "Headers")
67
+
68
+ gcc_defs = '$(inherited) PLATFORM_CONFIG_H=\\"libarchive_darwin_config.h\\"'
69
+ gcc_defs += ' HAVE_FFMPEG=1' if has_ffmpeg
70
+ gcc_defs += ' HAVE_LIBARCHIVE=1' if has_libarchive
71
+
72
+ ld_flags = '$(inherited) -lsherpa-onnx'
73
+ if has_ffmpeg
74
+ ld_flags += ' -lffmpeg -liconv -lbz2'
75
+ end
76
+ if has_libarchive
77
+ ld_flags += ' -larchive'
78
+ end
79
+
80
+ header_search_paths = [
81
+ "$(inherited)",
82
+ "\"#{pod_root}/ios\"",
83
+ "\"#{pod_root}/ios/archive\"",
84
+ "\"#{pod_root}/ios/model_detect\"",
85
+ "\"#{pod_root}/ios/stt\"",
86
+ "\"#{pod_root}/ios/tts\"",
87
+ "\"#{pod_root}/ios/online_stt\"",
88
+ "\"#{device_headers}\"",
89
+ "\"#{simulator_headers}\""
90
+ ]
91
+ if has_libarchive
92
+ header_search_paths << "\"#{libarchive_device_headers}\""
93
+ header_search_paths << "\"#{libarchive_simulator_headers}\""
94
+ end
95
+ if has_ffmpeg
96
+ header_search_paths << "\"#{ffmpeg_device_headers}\""
97
+ header_search_paths << "\"#{ffmpeg_simulator_headers}\""
98
+ end
99
+
75
100
  s.pod_target_xcconfig = {
76
- "HEADER_SEARCH_PATHS" => "$(inherited) \"#{pod_root}/ios\" \"#{pod_root}/ios/archive\" \"#{pod_root}/ios/model_detect\" \"#{pod_root}/ios/stt\" \"#{pod_root}/ios/tts\" \"#{pod_root}/ios/online_stt\" \"#{libarchive_dir}\" \"#{device_headers}\" \"#{simulator_headers}\"",
77
- "GCC_PREPROCESSOR_DEFINITIONS" => '$(inherited) PLATFORM_CONFIG_H=\\"libarchive_darwin_config.h\\"',
101
+ "HEADER_SEARCH_PATHS" => header_search_paths.join(" "),
102
+ "GCC_PREPROCESSOR_DEFINITIONS" => gcc_defs,
78
103
  "CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
79
104
  "CLANG_CXX_LIBRARY" => "libc++",
105
+ "OTHER_CPLUSPLUSFLAGS" => "$(inherited)",
80
106
  "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" => "$(inherited) \"#{device_slice}\"",
81
107
  "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" => "$(inherited) \"#{simulator_slice}\"",
82
- "OTHER_LDFLAGS" => "$(inherited) -lsherpa-onnx"
108
+ "OTHER_LDFLAGS" => ld_flags
83
109
  }
84
110
 
85
111
  s.user_target_xcconfig = {
@@ -87,10 +113,10 @@ Pod::Spec.new do |s|
87
113
  "CLANG_CXX_LIBRARY" => "libc++",
88
114
  "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" => "$(inherited) \"#{device_slice}\"",
89
115
  "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" => "$(inherited) \"#{simulator_slice}\"",
90
- "OTHER_LDFLAGS" => "$(inherited) -lsherpa-onnx"
116
+ "OTHER_LDFLAGS" => ld_flags
91
117
  }
92
118
 
93
- s.libraries = "c++", "z"
119
+ s.libraries = "c++", "z", "iconv", "bz2"
94
120
 
95
121
  install_modules_dependencies(s)
96
- end
122
+ end
@@ -103,7 +103,7 @@ android {
103
103
  jniLibs {
104
104
  excludes += [
105
105
  "**/libavcodec.so", "**/libavformat.so", "**/libavutil.so",
106
- "**/libavfilter.so", "**/libswresample.so", "**/libshine.so"
106
+ "**/libavfilter.so", "**/libswresample.so", "**/libshine.so", "**/libopus.so"
107
107
  ]
108
108
  }
109
109
  }
@@ -132,10 +132,16 @@ android {
132
132
  }
133
133
  }
134
134
 
135
+ // Resolve com.xdcobra.sherpa only from this repo (never from JitPack or other app repos).
135
136
  repositories {
137
+ exclusiveContent {
138
+ forRepository { maven { url "https://xdcobra.github.io/maven" } }
139
+ filter {
140
+ includeGroup "com.xdcobra.sherpa"
141
+ }
142
+ }
136
143
  mavenCentral()
137
144
  google()
138
- maven { url "https://xdcobra.github.io/maven" }
139
145
  }
140
146
 
141
147
  // Configurations used by prebuilt-download.gradle: downloadNativeLibsIfNeeded (AAR --> jniLibs + headers),
@@ -104,14 +104,32 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
104
104
  def storedSherpaVersion = (sherpaVersionFile.exists() ? sherpaVersionFile.text.trim() : null)
105
105
  def sherpaNeedsUpdate = !hasAllSherpaLibs() || !hasSherpaHeaders() || storedSherpaVersion == null || storedSherpaVersion != currentSherpaVersion
106
106
 
107
+ def currentFfmpegVersion = project.ext.ffmpegVersion
108
+ def ffmpegVersionFile = new File(downloadDir, "ffmpeg-version.txt")
109
+ def storedFfmpegVersion = (ffmpegVersionFile.exists() ? ffmpegVersionFile.text.trim() : null)
110
+ def ffmpegNeedsUpdate = !hasAllFfmpegLibs() || !hasFfmpegHeaders() || storedFfmpegVersion == null || storedFfmpegVersion != currentFfmpegVersion
111
+
112
+ def currentLibarchiveVersion = project.ext.libarchiveVersion
113
+ def libarchiveVersionFile = new File(downloadDir, "libarchive-version.txt")
114
+ def storedLibarchiveVersion = (libarchiveVersionFile.exists() ? libarchiveVersionFile.text.trim() : null)
115
+ def libarchiveNeedsUpdate = !hasAllLibarchiveLibs() || !hasLibarchiveHeaders() || storedLibarchiveVersion == null || storedLibarchiveVersion != currentLibarchiveVersion
116
+
107
117
  if (hasAllSherpaLibs() && hasSherpaHeaders() && !sherpaNeedsUpdate) {
108
118
  println "[sherpa-onnx] Native libs + headers: (1) already present, version ${currentSherpaVersion}"
109
119
  }
110
120
  if (sherpaNeedsUpdate && storedSherpaVersion != null && storedSherpaVersion != currentSherpaVersion) {
111
121
  println "[sherpa-onnx] Version change detected (${storedSherpaVersion} -> ${currentSherpaVersion}), refreshing libs and headers"
112
122
  }
123
+ if (ffmpegNeedsUpdate && storedFfmpegVersion != null && storedFfmpegVersion != currentFfmpegVersion) {
124
+ println "[FFmpeg] Version change detected (${storedFfmpegVersion} -> ${currentFfmpegVersion}), refreshing libs and headers"
125
+ }
126
+ if (libarchiveNeedsUpdate && storedLibarchiveVersion != null && storedLibarchiveVersion != currentLibarchiveVersion) {
127
+ println "[libarchive] Version change detected (${storedLibarchiveVersion} -> ${currentLibarchiveVersion}), refreshing libs and headers"
128
+ }
113
129
 
114
130
  def sherpaUpdatedFromAar = [false]
131
+ def ffmpegUpdatedFromAar = [false]
132
+ def libarchiveUpdatedFromAar = [false]
115
133
  if (sherpaNeedsUpdate) {
116
134
  try {
117
135
  def aarFiles = project.configurations.sherpaOnnxAar.files
@@ -145,7 +163,7 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
145
163
  }
146
164
  }
147
165
 
148
- if (!sherpaOnnxDisableFfmpeg && (!hasAllFfmpegLibs() || !hasFfmpegHeaders())) {
166
+ if (!sherpaOnnxDisableFfmpeg && ffmpegNeedsUpdate) {
149
167
  try {
150
168
  def aarFiles = project.configurations.ffmpegAar.files
151
169
  if (!aarFiles.isEmpty()) {
@@ -168,6 +186,9 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
168
186
  copy { from aarIncludeDir; into ffmpegIncludeDir }
169
187
  println "Extracted FFmpeg headers from Maven AAR"
170
188
  }
189
+ downloadDir.mkdirs()
190
+ ffmpegVersionFile.text = currentFfmpegVersion
191
+ ffmpegUpdatedFromAar[0] = true
171
192
  println "[FFmpeg] Native libs + headers: (2) Maven AAR (${aar.name})"
172
193
  }
173
194
  } catch (Exception e) {
@@ -175,7 +196,7 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
175
196
  }
176
197
  }
177
198
 
178
- if (!sherpaOnnxDisableLibarchive && (!hasAllLibarchiveLibs() || !hasLibarchiveHeaders())) {
199
+ if (!sherpaOnnxDisableLibarchive && libarchiveNeedsUpdate) {
179
200
  try {
180
201
  def aarFiles = project.configurations.libarchiveAar.files
181
202
  if (!aarFiles.isEmpty()) {
@@ -198,6 +219,9 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
198
219
  copy { from aarIncludeDir; into libarchiveIncludeDir }
199
220
  println "Extracted libarchive headers from Maven AAR"
200
221
  }
222
+ downloadDir.mkdirs()
223
+ libarchiveVersionFile.text = currentLibarchiveVersion
224
+ libarchiveUpdatedFromAar[0] = true
201
225
  println "[libarchive] Native libs + headers: (2) Maven AAR (${aar.name})"
202
226
  }
203
227
  } catch (Exception e) {
@@ -237,14 +261,27 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
237
261
 
238
262
  def repo = project.findProperty('prebuiltGitHubRepo') ?: getGitHubRepo()
239
263
  if (!repo) {
240
- def needFfmpeg = !sherpaOnnxDisableFfmpeg && (!hasAllFfmpegLibs() || !hasFfmpegHeaders())
241
- def needLibarchive = !sherpaOnnxDisableLibarchive && (!hasAllLibarchiveLibs() || !hasLibarchiveHeaders())
242
- if (needFfmpeg || needLibarchive || (sherpaNeedsUpdate && !sherpaUpdatedFromAar[0])) {
264
+ def needFfmpeg = !sherpaOnnxDisableFfmpeg && ffmpegNeedsUpdate && !ffmpegUpdatedFromAar[0]
265
+ def needLibarchive = !sherpaOnnxDisableLibarchive && libarchiveNeedsUpdate && !libarchiveUpdatedFromAar[0]
266
+ def needSherpa = sherpaNeedsUpdate && !sherpaUpdatedFromAar[0]
267
+ if (needFfmpeg || needLibarchive || needSherpa) {
268
+ def diag = [
269
+ "prebuiltGitHubRepo=${project.findProperty('prebuiltGitHubRepo') ?: '(not set)'}",
270
+ "git remote origin=${getGitHubRepo() ?: '(not a GitHub URL or git unavailable)'}",
271
+ "sherpaOnnxDisableFfmpeg=${sherpaOnnxDisableFfmpeg}",
272
+ "sherpaOnnxDisableLibarchive=${sherpaOnnxDisableLibarchive}",
273
+ "sherpaNeedsUpdate=${sherpaNeedsUpdate} sherpaUpdatedFromAar=${sherpaUpdatedFromAar[0]}",
274
+ "ffmpegNeedsUpdate=${ffmpegNeedsUpdate} ffmpegUpdatedFromAar=${ffmpegUpdatedFromAar[0]}",
275
+ "libarchiveNeedsUpdate=${libarchiveNeedsUpdate} libarchiveUpdatedFromAar=${libarchiveUpdatedFromAar[0]}",
276
+ "needFfmpeg=${needFfmpeg} needLibarchive=${needLibarchive} needSherpa=${needSherpa}"
277
+ ].join(", ")
243
278
  throw new RuntimeException(
244
- "Native libs/headers still missing and GitHub repo unknown. Set -PprebuiltGitHubRepo=owner/repo or ensure git remote origin is a GitHub URL. " +
279
+ "Native libs/headers still missing and GitHub repo unknown. " +
280
+ "Set -PprebuiltGitHubRepo=owner/repo or ensure git remote origin is a GitHub URL. " +
245
281
  "Alternatively run third_party/ffmpeg_prebuilt/copy_prebuilts_to_sdk.js, third_party/sherpa-onnx-prebuilt/copy_prebuilts_to_sdk.js, third_party/libarchive_prebuilt/copy_prebuilts_to_sdk.js, or use Maven (com.xdcobra.sherpa:ffmpeg / sherpa-onnx / libarchive), or ensure ANDROID_RELEASE_TAG releases exist. " +
246
282
  (sherpaOnnxDisableFfmpeg ? "(FFmpeg disabled via sherpaOnnxDisableFfmpeg=true.) " : "") +
247
- (sherpaOnnxDisableLibarchive ? "(libarchive disabled via sherpaOnnxDisableLibarchive=true.)" : "")
283
+ (sherpaOnnxDisableLibarchive ? "(libarchive disabled via sherpaOnnxDisableLibarchive=true.) " : "") +
284
+ "Diagnostics: [${diag}]"
248
285
  )
249
286
  }
250
287
  return
@@ -252,13 +289,13 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
252
289
  def baseUrl = "https://github.com/${repo}/releases/download"
253
290
  downloadDir.mkdirs()
254
291
 
255
- if (!sherpaOnnxDisableFfmpeg && (!hasAllFfmpegLibs() || !hasFfmpegHeaders())) {
292
+ if (!sherpaOnnxDisableFfmpeg && ffmpegNeedsUpdate && !ffmpegUpdatedFromAar[0]) {
256
293
  def tagFile = file("${project.projectDir.parent}/third_party/ffmpeg_prebuilt/ANDROID_RELEASE_TAG")
257
294
  def tag = readReleaseTag(tagFile)
258
295
  if (!tag) throw new RuntimeException("Missing or empty third_party/ffmpeg_prebuilt/ANDROID_RELEASE_TAG")
259
296
  def zipFile = new File(downloadDir, "ffmpeg-android.zip")
260
297
  def url = "${baseUrl}/${tag}/ffmpeg-android.zip"
261
- exec { commandLine 'curl', '-sSL', '-o', zipFile, url; workingDir project.projectDir }
298
+ project.exec { commandLine 'curl', '-sSL', '-o', zipFile, url; workingDir project.projectDir }
262
299
  if (!zipFile.exists() || zipFile.length() == 0) throw new RuntimeException("Download failed or empty: ${url}")
263
300
  def ffmpegExtractDir = new File(downloadDir, "ffmpeg-extract")
264
301
  if (ffmpegExtractDir.exists()) ffmpegExtractDir.deleteDir()
@@ -273,16 +310,18 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
273
310
  if (ffmpegIncludeInZip.exists()) {
274
311
  copy { from fileTree(ffmpegIncludeInZip); into ffmpegIncludeDir }
275
312
  }
313
+ downloadDir.mkdirs()
314
+ ffmpegVersionFile.text = currentFfmpegVersion
276
315
  println "Downloaded and extracted FFmpeg prebuilts (libs + include) from ${tag}"
277
316
  }
278
317
 
279
- if (!sherpaOnnxDisableLibarchive && (!hasAllLibarchiveLibs() || !hasLibarchiveHeaders())) {
318
+ if (!sherpaOnnxDisableLibarchive && libarchiveNeedsUpdate && !libarchiveUpdatedFromAar[0]) {
280
319
  def tagFile = file("${project.projectDir.parent}/third_party/libarchive_prebuilt/ANDROID_RELEASE_TAG")
281
320
  def tag = readReleaseTag(tagFile)
282
321
  if (!tag) throw new RuntimeException("Missing or empty third_party/libarchive_prebuilt/ANDROID_RELEASE_TAG")
283
322
  def zipFile = new File(downloadDir, "libarchive-android.zip")
284
323
  def url = "${baseUrl}/${tag}/libarchive-android.zip"
285
- exec { commandLine 'curl', '-sSL', '-o', zipFile, url; workingDir project.projectDir }
324
+ project.exec { commandLine 'curl', '-sSL', '-o', zipFile, url; workingDir project.projectDir }
286
325
  if (!zipFile.exists() || zipFile.length() == 0) throw new RuntimeException("Download failed or empty: ${url}")
287
326
  def libarchiveExtractDir = new File(downloadDir, "libarchive-extract")
288
327
  if (libarchiveExtractDir.exists()) libarchiveExtractDir.deleteDir()
@@ -298,6 +337,8 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
298
337
  libarchiveIncludeDir.mkdirs()
299
338
  copy { from libarchiveIncludeInZip; into libarchiveIncludeDir }
300
339
  }
340
+ downloadDir.mkdirs()
341
+ libarchiveVersionFile.text = currentLibarchiveVersion
301
342
  println "Downloaded and extracted libarchive prebuilts (libs + include) from ${tag}"
302
343
  }
303
344
 
@@ -307,7 +348,7 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
307
348
  if (!tag) throw new RuntimeException("Missing or empty third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG")
308
349
  def zipFile = new File(downloadDir, "sherpa-onnx-android.zip")
309
350
  def url = "${baseUrl}/${tag}/sherpa-onnx-android.zip"
310
- exec { commandLine 'curl', '-sSL', '-o', zipFile, url; workingDir project.projectDir }
351
+ project.exec { commandLine 'curl', '-sSL', '-o', zipFile, url; workingDir project.projectDir }
311
352
  if (!zipFile.exists() || zipFile.length() == 0) throw new RuntimeException("Download failed or empty: ${url}")
312
353
  def sherpaExtractDir = new File(downloadDir, "sherpa-onnx-extract")
313
354
  if (sherpaExtractDir.exists()) sherpaExtractDir.deleteDir()
@@ -30,6 +30,7 @@ if (!ffmpegVersion) {
30
30
  ffmpegVersion = v ?: (project.hasProperty('ffmpegVersion') ? project.ffmpegVersion : '8.0.1')
31
31
  }
32
32
  project.ext.ffmpegVersion = ffmpegVersion
33
+ println "[react-native-sherpa-onnx] ffmpeg version (extracted/used): ${ffmpegVersion}"
33
34
 
34
35
  // libarchive: 1. LIBARCHIVE_VERSION env 2. ANDROID_RELEASE_TAG 3. property 4. default
35
36
  def libarchiveVersion = System.getenv('LIBARCHIVE_VERSION')
@@ -38,10 +39,13 @@ if (!libarchiveVersion) {
38
39
  libarchiveVersion = v ?: (project.hasProperty('libarchiveVersion') ? project.libarchiveVersion : '3.8.5')
39
40
  }
40
41
  project.ext.libarchiveVersion = libarchiveVersion
42
+ println "[react-native-sherpa-onnx] libarchive version (extracted/used): ${libarchiveVersion}"
41
43
 
42
- // onnxruntime (ORT Java bridge): 1. ORT_VERSION env 2. property 3. default
44
+ // onnxruntime (ORT Java bridge): 1. ORT_VERSION env 2. ANDROID_RELEASE_TAG 3. property 4. default
43
45
  def ortVersion = System.getenv('ORT_VERSION')
44
46
  if (!ortVersion) {
45
- ortVersion = project.hasProperty('ortVersion') ? project.ortVersion : '1.24.2-qnn2.43.1.260218'
47
+ def v = readVersionFromTagFile(new File(moduleRoot, 'third_party/onnxruntime_prebuilt/ANDROID_RELEASE_TAG'), 'ort-android-qnn-v')
48
+ ortVersion = v ?: (project.hasProperty('ortVersion') ? project.ortVersion : '1.24.2-qnn2.43.1.260218')
46
49
  }
47
50
  project.ext.ortVersion = ortVersion
51
+ println "[react-native-sherpa-onnx] onnxruntime version (extracted/used): ${ortVersion}"
@@ -76,6 +76,8 @@ set(SOURCES
76
76
  jni/model_detect/sherpa-onnx-model-detect-helper.cpp
77
77
  jni/model_detect/sherpa-onnx-model-detect-stt.cpp
78
78
  jni/model_detect/sherpa-onnx-model-detect-tts.cpp
79
+ jni/model_detect/sherpa-onnx-validate-stt.cpp
80
+ jni/model_detect/sherpa-onnx-validate-tts.cpp
79
81
  jni/model_detect/sherpa-onnx-detect-jni-common.cpp
80
82
  jni/model_detect/sherpa-onnx-stt-wrapper.cpp
81
83
  jni/model_detect/sherpa-onnx-tts-wrapper.cpp