react-native-sherpa-onnx 0.3.2 → 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 (83) hide show
  1. package/README.md +84 -77
  2. package/SherpaOnnx.podspec +79 -45
  3. package/android/build.gradle +8 -2
  4. package/android/prebuilt-download.gradle +70 -16
  5. package/android/prebuilt-versions.gradle +14 -6
  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 +96 -142
  11. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-helper.h +40 -4
  12. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-stt.cpp +774 -316
  13. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect-tts.cpp +208 -122
  14. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-model-detect.h +92 -0
  15. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-stt-wrapper.cpp +3 -0
  16. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-tts-wrapper.cpp +14 -2
  17. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-stt.cpp +229 -0
  18. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-stt.h +38 -0
  19. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-tts.cpp +144 -0
  20. package/android/src/main/cpp/jni/model_detect/sherpa-onnx-validate-tts.h +38 -0
  21. package/android/src/main/cpp/jni/module/sherpa-onnx-module-jni.cpp +1 -1
  22. package/android/src/main/java/com/sherpaonnx/SherpaOnnxModule.kt +157 -11
  23. package/android/src/main/java/com/sherpaonnx/SherpaOnnxPcmCapture.kt +150 -0
  24. package/android/src/main/java/com/sherpaonnx/SherpaOnnxSttHelper.kt +75 -24
  25. package/android/src/main/java/com/sherpaonnx/SherpaOnnxTtsHelper.kt +52 -1
  26. package/ios/SherpaOnnx+PcmLiveStream.mm +288 -0
  27. package/ios/SherpaOnnx+STT.mm +2 -0
  28. package/ios/SherpaOnnx+TTS.mm +17 -0
  29. package/ios/SherpaOnnx.mm +27 -3
  30. package/ios/SherpaOnnxAudioConvert.h +28 -0
  31. package/ios/SherpaOnnxAudioConvert.mm +698 -0
  32. package/ios/archive/sherpa-onnx-archive-helper.mm +12 -0
  33. package/ios/model_detect/sherpa-onnx-model-detect-helper.h +37 -3
  34. package/ios/model_detect/sherpa-onnx-model-detect-helper.mm +80 -45
  35. package/ios/model_detect/sherpa-onnx-model-detect-stt.mm +629 -267
  36. package/ios/model_detect/sherpa-onnx-model-detect-tts.mm +148 -56
  37. package/ios/model_detect/sherpa-onnx-model-detect.h +72 -0
  38. package/ios/model_detect/sherpa-onnx-validate-stt.h +38 -0
  39. package/ios/model_detect/sherpa-onnx-validate-stt.mm +229 -0
  40. package/ios/model_detect/sherpa-onnx-validate-tts.h +38 -0
  41. package/ios/model_detect/sherpa-onnx-validate-tts.mm +144 -0
  42. package/ios/stt/sherpa-onnx-stt-wrapper.mm +4 -0
  43. package/lib/module/NativeSherpaOnnx.js.map +1 -1
  44. package/lib/module/audio/index.js +55 -1
  45. package/lib/module/audio/index.js.map +1 -1
  46. package/lib/module/download/ModelDownloadManager.js +14 -0
  47. package/lib/module/download/ModelDownloadManager.js.map +1 -1
  48. package/lib/module/index.js +10 -0
  49. package/lib/module/index.js.map +1 -1
  50. package/lib/module/stt/streaming.js +6 -3
  51. package/lib/module/stt/streaming.js.map +1 -1
  52. package/lib/module/tts/index.js +13 -1
  53. package/lib/module/tts/index.js.map +1 -1
  54. package/lib/typescript/src/NativeSherpaOnnx.d.ts +32 -3
  55. package/lib/typescript/src/NativeSherpaOnnx.d.ts.map +1 -1
  56. package/lib/typescript/src/audio/index.d.ts +20 -1
  57. package/lib/typescript/src/audio/index.d.ts.map +1 -1
  58. package/lib/typescript/src/download/ModelDownloadManager.d.ts +2 -1
  59. package/lib/typescript/src/download/ModelDownloadManager.d.ts.map +1 -1
  60. package/lib/typescript/src/index.d.ts +10 -0
  61. package/lib/typescript/src/index.d.ts.map +1 -1
  62. package/lib/typescript/src/stt/streaming.d.ts.map +1 -1
  63. package/lib/typescript/src/stt/streamingTypes.d.ts +1 -1
  64. package/lib/typescript/src/stt/streamingTypes.d.ts.map +1 -1
  65. package/lib/typescript/src/tts/index.d.ts +12 -1
  66. package/lib/typescript/src/tts/index.d.ts.map +1 -1
  67. package/package.json +6 -1
  68. package/scripts/check-model-csvs.sh +72 -0
  69. package/scripts/setup-ios-framework.sh +272 -191
  70. package/src/NativeSherpaOnnx.ts +37 -3
  71. package/src/audio/index.ts +84 -1
  72. package/src/download/ModelDownloadManager.ts +19 -0
  73. package/src/index.tsx +15 -0
  74. package/src/stt/streaming.ts +10 -5
  75. package/src/stt/streamingTypes.ts +1 -1
  76. package/src/tts/index.ts +25 -1
  77. package/third_party/ffmpeg_prebuilt/ANDROID_RELEASE_TAG +1 -1
  78. package/third_party/libarchive_prebuilt/ANDROID_RELEASE_TAG +1 -1
  79. package/third_party/libarchive_prebuilt/IOS_RELEASE_TAG +1 -1
  80. package/third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG +1 -1
  81. package/third_party/sherpa-onnx-prebuilt/IOS_RELEASE_TAG +1 -1
  82. package/ios/scripts/patch-libarchive-includes.sh +0 -61
  83. package/ios/scripts/setup-ios-libarchive.sh +0 -98
package/README.md CHANGED
@@ -14,6 +14,8 @@ React Native SDK for sherpa-onnx – offline and streaming speech processing
14
14
  [![Android](https://img.shields.io/badge/Android-Supported-green)](https://www.android.com/)
15
15
  [![iOS](https://img.shields.io/badge/iOS-Supported-blue)](https://www.apple.com/ios/)
16
16
 
17
+ <a href="https://www.buymeacoffee.com/xdcobra" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" width="150" /></a>
18
+
17
19
  </div>
18
20
 
19
21
  > **⚠️ SDK 0.3.0 – Breaking changes from 0.2.0**
@@ -21,16 +23,57 @@ React Native SDK for sherpa-onnx – offline and streaming speech processing
21
23
 
22
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).
23
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
+
24
67
  ## Table of contents
25
68
 
69
+ - [Installation](#installation)
70
+ - [Android](#android)
71
+ - [iOS](#ios)
26
72
  - [Feature Support](#feature-support)
27
73
  - [Platform Support Status](#platform-support-status)
28
74
  - [Supported Model Types](#supported-model-types)
29
75
  - [Speech-to-Text (STT) Models](#speech-to-text-stt-models)
30
76
  - [Text-to-Speech (TTS) Models](#text-to-speech-tts-models)
31
- - [Installation](#installation)
32
- - [Android](#android)
33
- - [iOS](#ios)
34
77
  - [Documentation](#documentation)
35
78
  - [Requirements](#requirements)
36
79
  - [Breaking changes (upgrading to 0.3.0)](#breaking-changes-upgrading-to-030)
@@ -48,12 +91,13 @@ A React Native TurboModule that provides offline and streaming speech processing
48
91
  | Feature | Status | Notes |
49
92
  |---------|--------|-------|
50
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). |
51
- | 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). |
52
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). |
53
- | 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). |
54
98
  | Execution providers (CPU, NNAPI, XNNPACK, Core ML, QNN) | ✅ **Supported** | See [Execution provider support](./docs/execution-providers.md). |
55
- | Play Asset Delivery (PAD) | ✅ **Supported** | Android only. See [Model Setup](./docs/MODEL_SETUP.md). |
56
- | 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). |
57
101
  | Model quantization | ✅ **Supported** | Automatic detection and preference for quantized (int8) models. |
58
102
  | Flexible model loading | ✅ **Supported** | Asset models, file system models, or auto-detection. |
59
103
  | TypeScript | ✅ **Supported** | Full type definitions included. |
@@ -75,95 +119,57 @@ A React Native TurboModule that provides offline and streaming speech processing
75
119
 
76
120
  | Model Type | `modelType` Value | Description | Download Links |
77
121
  | ------------------------ | ----------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
78
- | **Zipformer/Transducer** | `'transducer'` | Requires `encoder.onnx`, `decoder.onnx`, `joiner.onnx`, and `tokens.txt` | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-transducer/index.html) |
79
- | **Paraformer** | `'paraformer'` | Requires `model.onnx` (or `model.int8.onnx`) and `tokens.txt` | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-paraformer/index.html) |
80
- | **NeMo CTC** | `'nemo_ctc'` | Requires `model.onnx` (or `model.int8.onnx`) and `tokens.txt` | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-ctc/nemo/index.html) |
81
- | **Whisper** | `'whisper'` | Requires `encoder.onnx`, `decoder.onnx`, and `tokens.txt` | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/whisper/index.html) |
82
- | **WeNet CTC** | `'wenet_ctc'` | Requires `model.onnx` (or `model.int8.onnx`) and `tokens.txt` | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-ctc/wenet/index.html) |
83
- | **SenseVoice** | `'sense_voice'` | Requires `model.onnx` (or `model.int8.onnx`) and `tokens.txt` | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/sense-voice/index.html) |
84
- | **FunASR Nano** | `'funasr_nano'` | Requires `encoder_adaptor.onnx`, `llm.onnx`, `embedding.onnx`, and `tokenizer` directory | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/funasr-nano/index.html) |
85
- | **Tone CTC (t-one)** | `'tone_ctc'` | Single `model.onnx` + `tokens.txt`. Folder name usually contains `t-one`, `t_one` or `tone` | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/online-ctc/index.html) |
86
-
87
- 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).
122
+ | **Zipformer/Transducer** | `'transducer'` | Encoder–decoder–joiner (e.g. icefall). Good balance of speed and accuracy. Folder name should contain **zipformer** or **transducer** for auto-detection. | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-transducer/index.html) |
123
+ | **LSTM Transducer** | `'transducer'` | Same layout as Zipformer (encoder–decoder–joiner). LSTM-based streaming ASR; detected as transducer. Folder name may contain **lstm**. | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/online-transducer/lstm-transducer-models.html) |
124
+ | **Paraformer** | `'paraformer'` | Single-model non-autoregressive ASR; fast and accurate. Detected by `model.onnx`; no folder token required. | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-paraformer/index.html) |
125
+ | **NeMo CTC** | `'nemo_ctc'` | NeMo CTC; good for English and streaming. Folder name should contain **nemo** or **parakeet**. | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-ctc/nemo/index.html) |
126
+ | **Whisper** | `'whisper'` | Multilingual, encoder–decoder; strong zero-shot. Detected by encoder+decoder (no joiner); folder token optional. | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/whisper/index.html) |
127
+ | **WeNet CTC** | `'wenet_ctc'` | CTC from WeNet; compact. Folder name should contain **wenet**. | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-ctc/wenet/index.html) |
128
+ | **SenseVoice** | `'sense_voice'` | Multilingual with emotion/punctuation. Folder name should contain **sense** or **sensevoice**. | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/sense-voice/index.html) |
129
+ | **FunASR Nano** | `'funasr_nano'` | Lightweight LLM-based ASR. Folder name should contain **funasr** or **funasr-nano**. | [Download](https://k2-fsa.github.io/sherpa/onnx/pretrained_models/funasr-nano/index.html) |
130
+ | **Moonshine (v1)** | `'moonshine'` | Four-part streaming-capable ASR (preprocess, encode, uncached/cached decode). Folder name should contain **moonshine**. | [Download](https://k2-fsa.github.io/sherpa/onnx/moonshine/index.html) |
131
+ | **Moonshine (v2)** | `'moonshine_v2'` | Two-part Moonshine (encoder + merged decoder); `.onnx` or `.ort`. Folder name should contain **moonshine** (v2 preferred if both layouts present). | [Download](https://k2-fsa.github.io/sherpa/onnx/moonshine/index.html) |
132
+ | **Fire Red ASR** | `'fire_red_asr'` | Fire Red encoder–decoder ASR. Folder name should contain **fire_red** or **fire-red**. | [Download](https://k2-fsa.github.io/sherpa/onnx/FireRedAsr/index.html) |
133
+ | **Dolphin** | `'dolphin'` | Single-model CTC. Folder name should contain **dolphin**. | [Download](https://k2-fsa.github.io/sherpa/onnx/Dolphin/index.html) |
134
+ | **Canary** | `'canary'` | NeMo Canary multilingual. Folder name should contain **canary**. | [Download](https://k2-fsa.github.io/sherpa/onnx/nemo/canary.html) |
135
+ | **Omnilingual** | `'omnilingual'` | Omnilingual CTC. Folder name should contain **omnilingual**. | [Download](https://k2-fsa.github.io/sherpa/onnx/omnilingual-asr/index.html) |
136
+ | **MedASR** | `'medasr'` | Medical ASR CTC. Folder name should contain **medasr**. | [Download](https://github.com/k2-fsa/sherpa-onnx) |
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) |
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) |
139
+
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).
88
141
 
89
142
  ### Text-to-Speech (TTS) Models
90
143
 
91
144
  | Model Type | `modelType` Value | Description | Download Links |
92
145
  | ---------------- | ----------------- | ---------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
93
- | **VITS** | `'vits'` | Fast, high-quality TTS. Includes Piper, Coqui, MeloTTS, MMS variants. Requires `model.onnx`, `tokens.txt` | [Download](https://github.com/k2-fsa/sherpa-onnx/releases/tag/tts-models) |
94
- | **Matcha** | `'matcha'` | High-quality acoustic model + vocoder. Requires `acoustic_model.onnx`, `vocoder.onnx`, `tokens.txt` | [Download](https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/matcha.html) |
95
- | **Kokoro** | `'kokoro'` | Multi-speaker, multi-language. Requires `model.onnx`, `voices.bin`, `tokens.txt`, `espeak-ng-data/` | [Download](https://github.com/k2-fsa/sherpa-onnx/releases/tag/tts-models) |
96
- | **KittenTTS** | `'kitten'` | Lightweight, multi-speaker. Requires `model.onnx`, `voices.bin`, `tokens.txt`, `espeak-ng-data/` | [Download](https://github.com/k2-fsa/sherpa-onnx/releases/tag/tts-models) |
97
- | **Zipvoice** | `'zipvoice'` | Voice cloning capable. Requires `encoder.onnx`, `decoder.onnx`, `vocoder.onnx`, `tokens.txt` | [Download](https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/zipvoice.html) |
98
- | **Pocket** | `'pocket'` | Flow-matching TTS. Requires `lm_flow.onnx`, `lm_main.onnx`, `encoder.onnx`, `decoder.onnx`, `text_conditioner.onnx`, `vocab.json`, `token_scores.json` | [Download](https://github.com/k2-fsa/sherpa-onnx/releases/tag/tts-models) |
99
-
100
- For **streaming TTS** (incremental generation, low latency), use `createStreamingTTS()` with supported model types. See [Streaming Text-to-Speech](./docs/tts_streaming.md).
101
-
102
- ## Installation
103
-
104
- ```sh
105
- npm install react-native-sherpa-onnx
106
- ```
107
-
108
- If your project uses Yarn (v3+) or Plug'n'Play, configure Yarn to use the Node Modules linker to avoid postinstall issues:
109
-
110
- ```yaml
111
- # .yarnrc.yml
112
- nodeLinker: node-modules
113
- ```
114
-
115
- Alternatively, set the environment variable during install:
116
-
117
- ```sh
118
- YARN_NODE_LINKER=node-modules yarn install
119
- ```
120
-
121
- ### Android
122
-
123
- 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).
124
-
125
-
126
- ### iOS
127
-
128
- 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).
129
-
130
- #### Setup
131
-
132
- ```sh
133
- cd your-app/ios
134
- bundle install
135
- bundle exec pod install
136
- ```
137
-
138
- 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`.
139
-
140
- #### For Advanced Users: Building the Framework Locally
141
- #### Advanced: Building the iOS framework yourself
142
-
143
- 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:
144
-
145
- - **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).
146
- - **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)).
146
+ | **VITS** | `'vits'` | Fast, high-quality TTS (Piper, Coqui, MeloTTS, MMS). Folder name should contain **vits** if used with other voice models. | [Download](https://github.com/k2-fsa/sherpa-onnx/releases/tag/tts-models) |
147
+ | **Matcha** | `'matcha'` | High-quality acoustic model + vocoder. Detected by acoustic_model + vocoder; no folder token required. | [Download](https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/matcha.html) |
148
+ | **Kokoro** | `'kokoro'` | Multi-speaker, multi-language. Folder name should contain **kokoro** (not kitten) for auto-detection. | [Download](https://github.com/k2-fsa/sherpa-onnx/releases/tag/tts-models) |
149
+ | **KittenTTS** | `'kitten'` | Lightweight, multi-speaker. Folder name should contain **kitten** (not kokoro) for auto-detection. | [Download](https://github.com/k2-fsa/sherpa-onnx/releases/tag/tts-models) |
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) |
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) |
147
152
 
148
- 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).
149
154
 
150
155
  ## Documentation
151
156
 
152
157
  - [Speech-to-Text (STT)](./docs/stt.md) – Offline transcription (file or samples)
153
- - [Streaming (Online) Speech-to-Text](./docs/stt_streaming.md) – Real-time recognition, partial results, endpoint detection
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)
154
160
  - [Text-to-Speech (TTS)](./docs/tts.md) – Offline and streaming generation
155
- - [Streaming Text-to-Speech](./docs/tts_streaming.md) – Incremental TTS (createStreamingTTS)
161
+ - [Streaming Text-to-Speech](./docs/tts-streaming.md) – Incremental TTS (createStreamingTTS)
156
162
  - [Execution provider support (QNN, NNAPI, XNNPACK, Core ML)](./docs/execution-providers.md) – Checking and using acceleration backends
157
163
  - [Voice Activity Detection (VAD)](./docs/vad.md)
158
164
  - [Speaker Diarization](./docs/diarization.md)
159
165
  - [Speech Enhancement](./docs/enhancement.md)
160
166
  - [Source Separation](./docs/separation.md)
161
- - [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
162
168
  - [Model Download Manager](./docs/download-manager.md)
163
169
  - [Disable FFMPEG](./docs/disable-ffmpeg.md)
164
170
  - [Disable LIBARCHIVE](./docs/disable-libarchive.md)
165
171
 
166
- 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).
167
173
 
168
174
  ## Requirements
169
175
 
@@ -179,7 +185,7 @@ We provide example applications to help you get started with `react-native-sherp
179
185
 
180
186
  The example app included in this repository demonstrates audio-to-text transcription, text-to-speech, and streaming features. It includes:
181
187
 
182
- - Multiple model type support (Zipformer, Paraformer, NeMo CTC, Whisper, WeNet CTC, SenseVoice, FunASR Nano)
188
+ - Multiple model type support (Zipformer, Paraformer, NeMo CTC, Whisper, WeNet CTC, SenseVoice, FunASR Nano, Moonshine, and more)
183
189
  - Model selection and configuration
184
190
  - **Offline** audio file transcription
185
191
  - **Online (streaming) STT** – live transcription from the microphone with partial results
@@ -202,6 +208,7 @@ yarn android # or yarn ios
202
208
  <td><img src="./docs/images/example_stt_2.png" alt="Transcribe cantonese audio" width="240" /></td>
203
209
  </tr>
204
210
  <tr>
211
+ <td><img src="./docs/images/example_streaming.png" alt="Text to speech generation" width="240" /></td>
205
212
  <td><img src="./docs/images/example_tts.png" alt="Text to speech generation" width="240" /></td>
206
213
  <td><img src="./docs/images/example_provider.png" alt="Text to speech generation" width="240" /></td>
207
214
  </tr>
@@ -2,39 +2,17 @@ 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
5
 
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.")
6
+ # Run iOS framework setup when podspec is loaded (works for :path pods).
7
+ setup_script = File.join(pod_root, "scripts", "setup-ios-framework.sh")
8
+ if File.exist?(setup_script)
9
+ prev = ENV["SHERPA_ONNX_PROJECT_ROOT"]
10
+ ENV["SHERPA_ONNX_PROJECT_ROOT"] = pod_root
11
+ unless system("bash", setup_script)
12
+ ENV["SHERPA_ONNX_PROJECT_ROOT"] = prev
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}")
14
+ end
15
+ ENV["SHERPA_ONNX_PROJECT_ROOT"] = prev
38
16
  end
39
17
 
40
18
  Pod::Spec.new do |s|
@@ -48,15 +26,31 @@ Pod::Spec.new do |s|
48
26
  s.platforms = { :ios => min_ios_version_supported }
49
27
  s.source = { :git => "https://github.com/XDcobra/react-native-sherpa-onnx.git", :tag => "#{s.version}" }
50
28
 
51
- # Download sherpa-onnx XCFramework from GitHub Releases before pod install (uses IOS_RELEASE_TAG for pinned version).
52
- setup_script = File.join(pod_root, "scripts", "setup-ios-framework.sh")
53
- s.prepare_command = "bash \"#{setup_script}\""
54
-
55
- s.source_files = ["ios/**/*.{h,m,mm,swift,cpp}", *libarchive_sources]
29
+ s.source_files = ["ios/**/*.{h,m,mm,swift,cpp}"]
56
30
  s.private_header_files = "ios/**/*.h"
57
31
 
58
- s.frameworks = "Foundation", "Accelerate", "CoreML"
59
- s.vendored_frameworks = "ios/Frameworks/sherpa_onnx.xcframework"
32
+ s.frameworks = "Foundation", "Accelerate", "CoreML", "AVFoundation", "AudioToolbox"
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
60
54
  # Absolute paths so headers are found regardless of PODS_TARGET_SRCROOT (e.g. when building via React Native CLI).
61
55
  xcframework_root = File.join(pod_root, "ios", "Frameworks", "sherpa_onnx.xcframework")
62
56
  simulator_headers = File.join(xcframework_root, "ios-arm64_x86_64-simulator", "Headers")
@@ -64,14 +58,54 @@ Pod::Spec.new do |s|
64
58
  simulator_slice = File.join(xcframework_root, "ios-arm64_x86_64-simulator")
65
59
  device_slice = File.join(xcframework_root, "ios-arm64")
66
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
+
67
100
  s.pod_target_xcconfig = {
68
- "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}\"",
69
- "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,
70
103
  "CLANG_CXX_LANGUAGE_STANDARD" => "c++17",
71
104
  "CLANG_CXX_LIBRARY" => "libc++",
105
+ "OTHER_CPLUSPLUSFLAGS" => "$(inherited)",
72
106
  "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" => "$(inherited) \"#{device_slice}\"",
73
107
  "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" => "$(inherited) \"#{simulator_slice}\"",
74
- "OTHER_LDFLAGS" => "$(inherited) -lsherpa-onnx"
108
+ "OTHER_LDFLAGS" => ld_flags
75
109
  }
76
110
 
77
111
  s.user_target_xcconfig = {
@@ -79,10 +113,10 @@ Pod::Spec.new do |s|
79
113
  "CLANG_CXX_LIBRARY" => "libc++",
80
114
  "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" => "$(inherited) \"#{device_slice}\"",
81
115
  "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" => "$(inherited) \"#{simulator_slice}\"",
82
- "OTHER_LDFLAGS" => "$(inherited) -lsherpa-onnx"
116
+ "OTHER_LDFLAGS" => ld_flags
83
117
  }
84
118
 
85
- s.libraries = "c++", "z"
119
+ s.libraries = "c++", "z", "iconv", "bz2"
86
120
 
87
121
  install_modules_dependencies(s)
88
- 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),
@@ -99,12 +99,38 @@ def readReleaseTag = { File tagFile ->
99
99
  project.tasks.register("downloadNativeLibsIfNeeded") {
100
100
  doLast {
101
101
  def downloadDir = file("${project.buildDir}/prebuilt-downloads")
102
+ def currentSherpaVersion = project.ext.sherpaOnnxVersion
103
+ def sherpaVersionFile = new File(downloadDir, "sherpa-onnx-version.txt")
104
+ def storedSherpaVersion = (sherpaVersionFile.exists() ? sherpaVersionFile.text.trim() : null)
105
+ def sherpaNeedsUpdate = !hasAllSherpaLibs() || !hasSherpaHeaders() || storedSherpaVersion == null || storedSherpaVersion != currentSherpaVersion
102
106
 
103
- if (hasAllSherpaLibs() && hasSherpaHeaders()) {
104
- println "[sherpa-onnx] Native libs + headers: (1) local third_party (jniLibs + cpp/include already present)"
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
+
117
+ if (hasAllSherpaLibs() && hasSherpaHeaders() && !sherpaNeedsUpdate) {
118
+ println "[sherpa-onnx] Native libs + headers: (1) already present, version ${currentSherpaVersion}"
119
+ }
120
+ if (sherpaNeedsUpdate && storedSherpaVersion != null && storedSherpaVersion != currentSherpaVersion) {
121
+ println "[sherpa-onnx] Version change detected (${storedSherpaVersion} -> ${currentSherpaVersion}), refreshing libs and headers"
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"
105
128
  }
106
129
 
107
- if (!hasAllSherpaLibs() || !hasSherpaHeaders()) {
130
+ def sherpaUpdatedFromAar = [false]
131
+ def ffmpegUpdatedFromAar = [false]
132
+ def libarchiveUpdatedFromAar = [false]
133
+ if (sherpaNeedsUpdate) {
108
134
  try {
109
135
  def aarFiles = project.configurations.sherpaOnnxAar.files
110
136
  if (!aarFiles.isEmpty()) {
@@ -127,6 +153,9 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
127
153
  copy { from fileTree(aarExtractDir) { include 'c-api/**' }; into includeSherpaDir }
128
154
  println "Extracted sherpa-onnx C-API headers from Maven AAR"
129
155
  }
156
+ downloadDir.mkdirs()
157
+ sherpaVersionFile.text = currentSherpaVersion
158
+ sherpaUpdatedFromAar[0] = true
130
159
  println "[sherpa-onnx] Native libs + headers: (2) Maven AAR (${aar.name})"
131
160
  }
132
161
  } catch (Exception e) {
@@ -134,7 +163,7 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
134
163
  }
135
164
  }
136
165
 
137
- if (!sherpaOnnxDisableFfmpeg && (!hasAllFfmpegLibs() || !hasFfmpegHeaders())) {
166
+ if (!sherpaOnnxDisableFfmpeg && ffmpegNeedsUpdate) {
138
167
  try {
139
168
  def aarFiles = project.configurations.ffmpegAar.files
140
169
  if (!aarFiles.isEmpty()) {
@@ -157,6 +186,9 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
157
186
  copy { from aarIncludeDir; into ffmpegIncludeDir }
158
187
  println "Extracted FFmpeg headers from Maven AAR"
159
188
  }
189
+ downloadDir.mkdirs()
190
+ ffmpegVersionFile.text = currentFfmpegVersion
191
+ ffmpegUpdatedFromAar[0] = true
160
192
  println "[FFmpeg] Native libs + headers: (2) Maven AAR (${aar.name})"
161
193
  }
162
194
  } catch (Exception e) {
@@ -164,7 +196,7 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
164
196
  }
165
197
  }
166
198
 
167
- if (!sherpaOnnxDisableLibarchive && (!hasAllLibarchiveLibs() || !hasLibarchiveHeaders())) {
199
+ if (!sherpaOnnxDisableLibarchive && libarchiveNeedsUpdate) {
168
200
  try {
169
201
  def aarFiles = project.configurations.libarchiveAar.files
170
202
  if (!aarFiles.isEmpty()) {
@@ -187,6 +219,9 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
187
219
  copy { from aarIncludeDir; into libarchiveIncludeDir }
188
220
  println "Extracted libarchive headers from Maven AAR"
189
221
  }
222
+ downloadDir.mkdirs()
223
+ libarchiveVersionFile.text = currentLibarchiveVersion
224
+ libarchiveUpdatedFromAar[0] = true
190
225
  println "[libarchive] Native libs + headers: (2) Maven AAR (${aar.name})"
191
226
  }
192
227
  } catch (Exception e) {
@@ -226,14 +261,27 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
226
261
 
227
262
  def repo = project.findProperty('prebuiltGitHubRepo') ?: getGitHubRepo()
228
263
  if (!repo) {
229
- def needFfmpeg = !sherpaOnnxDisableFfmpeg && (!hasAllFfmpegLibs() || !hasFfmpegHeaders())
230
- def needLibarchive = !sherpaOnnxDisableLibarchive && (!hasAllLibarchiveLibs() || !hasLibarchiveHeaders())
231
- if (needFfmpeg || needLibarchive || !hasAllSherpaLibs() || !hasSherpaHeaders()) {
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(", ")
232
278
  throw new RuntimeException(
233
- "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. " +
234
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. " +
235
282
  (sherpaOnnxDisableFfmpeg ? "(FFmpeg disabled via sherpaOnnxDisableFfmpeg=true.) " : "") +
236
- (sherpaOnnxDisableLibarchive ? "(libarchive disabled via sherpaOnnxDisableLibarchive=true.)" : "")
283
+ (sherpaOnnxDisableLibarchive ? "(libarchive disabled via sherpaOnnxDisableLibarchive=true.) " : "") +
284
+ "Diagnostics: [${diag}]"
237
285
  )
238
286
  }
239
287
  return
@@ -241,13 +289,13 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
241
289
  def baseUrl = "https://github.com/${repo}/releases/download"
242
290
  downloadDir.mkdirs()
243
291
 
244
- if (!sherpaOnnxDisableFfmpeg && (!hasAllFfmpegLibs() || !hasFfmpegHeaders())) {
292
+ if (!sherpaOnnxDisableFfmpeg && ffmpegNeedsUpdate && !ffmpegUpdatedFromAar[0]) {
245
293
  def tagFile = file("${project.projectDir.parent}/third_party/ffmpeg_prebuilt/ANDROID_RELEASE_TAG")
246
294
  def tag = readReleaseTag(tagFile)
247
295
  if (!tag) throw new RuntimeException("Missing or empty third_party/ffmpeg_prebuilt/ANDROID_RELEASE_TAG")
248
296
  def zipFile = new File(downloadDir, "ffmpeg-android.zip")
249
297
  def url = "${baseUrl}/${tag}/ffmpeg-android.zip"
250
- exec { commandLine 'curl', '-sSL', '-o', zipFile, url; workingDir project.projectDir }
298
+ project.exec { commandLine 'curl', '-sSL', '-o', zipFile, url; workingDir project.projectDir }
251
299
  if (!zipFile.exists() || zipFile.length() == 0) throw new RuntimeException("Download failed or empty: ${url}")
252
300
  def ffmpegExtractDir = new File(downloadDir, "ffmpeg-extract")
253
301
  if (ffmpegExtractDir.exists()) ffmpegExtractDir.deleteDir()
@@ -262,16 +310,18 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
262
310
  if (ffmpegIncludeInZip.exists()) {
263
311
  copy { from fileTree(ffmpegIncludeInZip); into ffmpegIncludeDir }
264
312
  }
313
+ downloadDir.mkdirs()
314
+ ffmpegVersionFile.text = currentFfmpegVersion
265
315
  println "Downloaded and extracted FFmpeg prebuilts (libs + include) from ${tag}"
266
316
  }
267
317
 
268
- if (!sherpaOnnxDisableLibarchive && (!hasAllLibarchiveLibs() || !hasLibarchiveHeaders())) {
318
+ if (!sherpaOnnxDisableLibarchive && libarchiveNeedsUpdate && !libarchiveUpdatedFromAar[0]) {
269
319
  def tagFile = file("${project.projectDir.parent}/third_party/libarchive_prebuilt/ANDROID_RELEASE_TAG")
270
320
  def tag = readReleaseTag(tagFile)
271
321
  if (!tag) throw new RuntimeException("Missing or empty third_party/libarchive_prebuilt/ANDROID_RELEASE_TAG")
272
322
  def zipFile = new File(downloadDir, "libarchive-android.zip")
273
323
  def url = "${baseUrl}/${tag}/libarchive-android.zip"
274
- exec { commandLine 'curl', '-sSL', '-o', zipFile, url; workingDir project.projectDir }
324
+ project.exec { commandLine 'curl', '-sSL', '-o', zipFile, url; workingDir project.projectDir }
275
325
  if (!zipFile.exists() || zipFile.length() == 0) throw new RuntimeException("Download failed or empty: ${url}")
276
326
  def libarchiveExtractDir = new File(downloadDir, "libarchive-extract")
277
327
  if (libarchiveExtractDir.exists()) libarchiveExtractDir.deleteDir()
@@ -287,16 +337,18 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
287
337
  libarchiveIncludeDir.mkdirs()
288
338
  copy { from libarchiveIncludeInZip; into libarchiveIncludeDir }
289
339
  }
340
+ downloadDir.mkdirs()
341
+ libarchiveVersionFile.text = currentLibarchiveVersion
290
342
  println "Downloaded and extracted libarchive prebuilts (libs + include) from ${tag}"
291
343
  }
292
344
 
293
- if (!hasAllSherpaLibs() || !hasSherpaHeaders()) {
345
+ if (sherpaNeedsUpdate && !sherpaUpdatedFromAar[0]) {
294
346
  def tagFile = file("${project.projectDir.parent}/third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG")
295
347
  def tag = readReleaseTag(tagFile)
296
348
  if (!tag) throw new RuntimeException("Missing or empty third_party/sherpa-onnx-prebuilt/ANDROID_RELEASE_TAG")
297
349
  def zipFile = new File(downloadDir, "sherpa-onnx-android.zip")
298
350
  def url = "${baseUrl}/${tag}/sherpa-onnx-android.zip"
299
- exec { commandLine 'curl', '-sSL', '-o', zipFile, url; workingDir project.projectDir }
351
+ project.exec { commandLine 'curl', '-sSL', '-o', zipFile, url; workingDir project.projectDir }
300
352
  if (!zipFile.exists() || zipFile.length() == 0) throw new RuntimeException("Download failed or empty: ${url}")
301
353
  def sherpaExtractDir = new File(downloadDir, "sherpa-onnx-extract")
302
354
  if (sherpaExtractDir.exists()) sherpaExtractDir.deleteDir()
@@ -319,6 +371,8 @@ project.tasks.register("downloadNativeLibsIfNeeded") {
319
371
  sherpaOnnxClassesDir.mkdirs()
320
372
  copy { from sherpaJavaJar; into sherpaOnnxClassesDir }
321
373
  }
374
+ downloadDir.mkdirs()
375
+ sherpaVersionFile.text = currentSherpaVersion
322
376
  println "[sherpa-onnx] Native libs + headers: (3) GitHub release (${tag})"
323
377
  } else {
324
378
  def sherpaClassesJar = file("${project.projectDir.parent}/third_party/sherpa-onnx-prebuilt/android/java/classes.jar")