react-native-nitro-onnx 0.1.0 → 0.1.1

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.
@@ -41,9 +41,11 @@ Pod::Spec.new do |s|
41
41
  # to match the inner framework name (SherpaOnnxC.framework), which CocoaPods
42
42
  # requires for correct linker flag generation.
43
43
  s.vendored_frameworks = "cpp/sherpa-onnx-prebuilt/ios/SherpaOnnxC.xcframework"
44
+ puts "[NitroOnnxSpeech] 🔧 CoreML execution provider enabled for iOS"
44
45
  s.pod_target_xcconfig = {
45
46
  "HEADER_SEARCH_PATHS" => '"$(PODS_TARGET_SRCROOT)/cpp/sherpa-onnx-prebuilt/include" "$(PODS_TARGET_SRCROOT)/cpp" "$(PODS_TARGET_SRCROOT)/nitrogen/generated/ios"',
46
- "CLANG_CXX_LANGUAGE_STANDARD" => "c++20"
47
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
48
+ "GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) SHERPA_ONNX_ENABLE_COREML=1"
47
49
  }
48
50
 
49
51
  load 'nitrogen/generated/ios/NitroOnnxSpeech+autolinking.rb'
package/README.md CHANGED
@@ -22,7 +22,7 @@ All audio I/O uses zero-copy `ArrayBuffer` with **16 kHz mono f32 PCM**.
22
22
  - [Model File Requirements](#model-file-requirements)
23
23
  - [Installation](#installation)
24
24
  - [Usage](#usage)
25
- - [Qualcomm CPU Detection](#qualcomm-cpu-detection)
25
+ - [Execution Providers](#execution-providers)
26
26
  - [VAD Pre-buffer](#vad-pre-buffer)
27
27
  - [Voice Cloning](#voice-cloning)
28
28
  - [Threading](#threading)
@@ -304,32 +304,67 @@ await tts.saveWav(audio, "/path/to/output.wav");
304
304
  > source.start();
305
305
  > ```
306
306
 
307
- ## Qualcomm CPU Detection
307
+ ## Execution Providers
308
308
 
309
- Use `isQualcommCpu()` to detect Qualcomm chipsets and select optimized QNN execution providers:
309
+ By default, the module automatically selects the best execution provider for your platform:
310
+
311
+ - **Android:** `qnn` — uses Qualcomm NPU via QNN; unsupported operators fall back to NNAPI/CPU.
312
+ - **iOS:** `coreml` — uses Apple Neural Engine via CoreML; unsupported operators fall back to CPU.
313
+
314
+ To disable NPU acceleration and force CPU-only inference, pass `provider: "cpu"` explicitly:
315
+
316
+ ```typescript
317
+ await asr.load({
318
+ type: "whisper",
319
+ // ... other config
320
+ provider: "cpu",
321
+ });
322
+ ```
323
+
324
+ ### Qualcomm SoC Detection
325
+
326
+ Use `getQualcommSoc()` to detect Qualcomm chipsets. Returns the SoC model string (e.g. `"SM8550"`, `"SM8650"`) on Qualcomm Android devices, or an empty string on iOS and non-Qualcomm chips.
327
+
328
+ On Android, it first reads the `ro.soc.model` system property, then falls back to parsing `/proc/cpuinfo`.
310
329
 
311
330
  ```typescript
312
331
  const speech = getOnnxSpeech();
313
- const isQualcomm = speech.isQualcommCpu();
314
-
315
- if (isQualcomm) {
316
- // Use QNN execution provider for better performance on Qualcomm chips
317
- await asr.load({
318
- type: "whisper",
319
- // ... other config
320
- provider: "qnn",
321
- });
332
+ const soc = speech.getQualcommSoc();
333
+
334
+ if (soc) {
335
+ console.log(`Qualcomm SoC: ${soc}`);
336
+ // QNN is the default provider on Android — no need to specify it
337
+ await asr.load({ type: "whisper", /* ... */ });
322
338
  } else {
323
- // Use CPU or other execution provider
324
- await asr.load({
325
- type: "whisper",
326
- // ... other config
327
- provider: "cpu",
328
- });
339
+ await asr.load({ type: "whisper", /* ... */ provider: "cpu" });
329
340
  }
330
341
  ```
331
342
 
332
- > **Note:** `isQualcommCpu()` returns `false` on iOS. It checks `/proc/cpuinfo` on Android to detect Qualcomm processors.
343
+ > **Note:** `getQualcommSoc()` returns `""` on iOS.
344
+
345
+ ### Building with QNN Support
346
+
347
+ QNN is enabled by default on Android (the prebuilt sherpa-onnx libraries include QNN support). You do **not** need `QNN_ROOT` for normal usage.
348
+
349
+ `QNN_ROOT` is **only** required when you need to bundle additional QNN Binary backend libraries from the Qualcomm AI Runtime (QAIRT) SDK. If you don't need the binary backend, simply omit `QNN_ROOT` — the default QNN execution provider works out of the box.
350
+
351
+ **Download QAIRT SDK (only if you need QNN Binary):**
352
+
353
+ Visit [Qualcomm Software Center](https://softwarecenter.qualcomm.com/api/download/software/sdks/Qualcomm_AI_Runtime_Community/All/2.40.0.251030/v2.40.0.251030.zip) to download the SDK (v2.40.0).
354
+
355
+ **Specify QNN_ROOT (optional):**
356
+
357
+ ```bash
358
+ # Via environment variable
359
+ QNN_ROOT=/path/to/qnn/sdk ./gradlew assembleRelease
360
+
361
+ # Or in android/gradle.properties
362
+ QNN_ROOT=/path/to/qnn/sdk
363
+ ```
364
+
365
+ When `QNN_ROOT` is set, the build system will link the QNN core library (`QnnHtp`) and all available HTP version libraries (`QnnHtpV73Stub`/`HtpV73`, `QnnHtpV75Stub`/`HtpV75`, etc.) from the SDK.
366
+
367
+ > **Note:** QNN support is Android-only. On iOS, CoreML is used by default.
333
368
 
334
369
  ## VAD Pre-buffer
335
370
 
@@ -115,3 +115,54 @@ if(ANDROID)
115
115
  endif()
116
116
  find_package(Threads REQUIRED)
117
117
  target_link_libraries(${PROJECT_NAME} Threads::Threads)
118
+
119
+ # QNN SDK support: pass -DQNN_ROOT=/path/to/qnn/sdk to enable QNN execution provider
120
+ set(QNN_ROOT "" CACHE PATH "Path to Qualcomm QNN SDK root directory")
121
+ if(QNN_ROOT)
122
+ message(NOTICE "🔧 QNN execution provider enabled")
123
+ message(NOTICE "📁 QNN SDK path: ${QNN_ROOT}")
124
+ target_include_directories(${PROJECT_NAME} PRIVATE "${QNN_ROOT}/include")
125
+ target_compile_definitions(${PROJECT_NAME} PRIVATE SHERPA_ONNX_ENABLE_QNN)
126
+
127
+ # QNN libraries are in lib/<arch>/ e.g. lib/aarch64-android/
128
+ set(_QNN_LIB_DIR "${QNN_ROOT}/lib/aarch64-android")
129
+ if(NOT EXISTS "${_QNN_LIB_DIR}")
130
+ # Fallback for older SDK layouts
131
+ set(_QNN_LIB_DIR "${QNN_ROOT}/lib/hexagon-v73")
132
+ endif()
133
+
134
+ # Link QNN core library
135
+ if(EXISTS "${_QNN_LIB_DIR}/libQnnHtp.so")
136
+ add_library(QnnHtp SHARED IMPORTED)
137
+ set_target_properties(QnnHtp PROPERTIES
138
+ IMPORTED_LOCATION "${_QNN_LIB_DIR}/libQnnHtp.so"
139
+ )
140
+ target_link_libraries(${PROJECT_NAME} QnnHtp)
141
+ endif()
142
+
143
+ # Link all available HTP version stubs and runtimes (v73, v75, v79, v81, etc.)
144
+ file(GLOB _QNN_HEXAGON_DIRS "${QNN_ROOT}/lib/hexagon-v*")
145
+ foreach(_HEXAGON_DIR ${_QNN_HEXAGON_DIRS})
146
+ get_filename_component(_HEXAGON_NAME "${_HEXAGON_DIR}" NAME)
147
+ # Extract version number from "hexagon-v73" -> "73"
148
+ string(REGEX REPLACE ".*hexagon-v([0-9]+).*" "\\1" _HTP_VER "${_HEXAGON_NAME}")
149
+ if(_HTP_VER)
150
+ set(_STUB_LIB "QnnHtpV${_HTP_VER}Stub")
151
+ set(_RUNTIME_LIB "HtpV${_HTP_VER}")
152
+
153
+ foreach(_QNN_LIB ${_STUB_LIB} ${_RUNTIME_LIB})
154
+ set(_LIB_PATH "${_HEXAGON_DIR}/lib${_QNN_LIB}.so")
155
+ if(EXISTS "${_LIB_PATH}")
156
+ add_library(${_QNN_LIB} SHARED IMPORTED)
157
+ set_target_properties(${_QNN_LIB} PROPERTIES
158
+ IMPORTED_LOCATION "${_LIB_PATH}"
159
+ )
160
+ target_link_libraries(${PROJECT_NAME} ${_QNN_LIB})
161
+ endif()
162
+ endforeach()
163
+ endif()
164
+ endforeach()
165
+ else()
166
+ message(NOTICE "🔧 QNN execution provider enabled (without external SDK)")
167
+ target_compile_definitions(${PROJECT_NAME} PRIVATE SHERPA_ONNX_ENABLE_QNN)
168
+ endif()
@@ -24,6 +24,12 @@ android {
24
24
  arguments "-DANDROID_STL=c++_shared"
25
25
  abiFilters (*reactNativeArchitectures())
26
26
 
27
+ // Pass QNN_ROOT to CMake if provided via gradle.properties or env var
28
+ def qnnRoot = findProperty("QNN_ROOT") ?: System.getenv("QNN_ROOT")
29
+ if (qnnRoot) {
30
+ arguments "-DQNN_ROOT=${qnnRoot}"
31
+ }
32
+
27
33
  buildTypes {
28
34
  debug {
29
35
  cppFlags "-O1 -g"
@@ -57,9 +57,9 @@ class OnnxSpeechPackage : ReactPackage {
57
57
  }
58
58
  }
59
59
 
60
- override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
60
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
61
61
  ensureResources(reactContext)
62
- return emptyList()
62
+ return super.getModule(name, reactContext)
63
63
  }
64
64
 
65
65
  @Suppress("OVERRIDE_DEPRECATION")
package/cpp/AsrEngine.cpp CHANGED
@@ -96,7 +96,8 @@ void OfflineAsrEngine::load(const AsrEngineConfig& config) {
96
96
 
97
97
  c.model_config.tokens = tokens.c_str();
98
98
  c.model_config.num_threads = config_.numThreads;
99
- c.model_config.debug = 0;
99
+ c.model_config.debug = config_.debug ? 1 : 0;
100
+ c.model_config.provider = config_.provider.c_str();
100
101
  c.decoding_method = config_.decodingMethod.c_str();
101
102
  c.max_active_paths = config_.maxActivePaths;
102
103
 
@@ -201,6 +202,8 @@ void StreamingAsrEngine::load(
201
202
 
202
203
  c.model_config.tokens = tokens.c_str();
203
204
  c.model_config.num_threads = config_.numThreads;
205
+ c.model_config.debug = config_.debug ? 1 : 0;
206
+ c.model_config.provider = config_.provider.c_str();
204
207
  c.decoding_method = config_.decodingMethod.c_str();
205
208
  c.max_active_paths = config_.maxActivePaths;
206
209
  c.enable_endpoint = 1;
package/cpp/AsrEngine.hpp CHANGED
@@ -41,6 +41,14 @@ struct AsrEngineConfig {
41
41
  int32_t maxActivePaths = 4;
42
42
  std::string language = "en";
43
43
  bool useItn = true;
44
+ bool debug = false;
45
+ #ifdef __ANDROID__
46
+ std::string provider = "qnn";
47
+ #elif defined(__APPLE__)
48
+ std::string provider = "coreml";
49
+ #else
50
+ std::string provider = "cpu";
51
+ #endif
44
52
  };
45
53
 
46
54
  /** Native recognition result before conversion to the generated AsrResult. */
@@ -13,6 +13,10 @@
13
13
  #include <cstdio>
14
14
  #include <cstring>
15
15
 
16
+ #ifdef __ANDROID__
17
+ #include <sys/system_properties.h>
18
+ #endif
19
+
16
20
  namespace margelo::nitro::onnx::speech {
17
21
 
18
22
  NitroOnnxSpeech::NitroOnnxSpeech()
@@ -46,23 +50,39 @@ std::string NitroOnnxSpeech::getVersion() {
46
50
  return "0.1.0";
47
51
  }
48
52
 
49
- bool NitroOnnxSpeech::isQualcommCpu() {
53
+ std::string NitroOnnxSpeech::getQualcommSoc() {
50
54
  #ifdef __ANDROID__
55
+ // 1) Try ro.soc.model first (available on most modern Android devices).
56
+ char prop[PROP_VALUE_MAX] = {0};
57
+ if (__system_property_get("ro.soc.model", prop) > 0 && prop[0] != '\0') {
58
+ return std::string(prop);
59
+ }
60
+
61
+ // 2) Fall back to parsing /proc/cpuinfo Hardware line.
51
62
  FILE* f = fopen("/proc/cpuinfo", "r");
52
- if (!f) return false;
63
+ if (!f) return "";
53
64
  char line[256];
54
- bool found = false;
55
65
  while (fgets(line, sizeof(line), f)) {
56
- if (strstr(line, "Qualcomm") != nullptr) {
57
- found = true;
58
- break;
66
+ if (strncmp(line, "Hardware", 8) == 0) {
67
+ char* colon = strchr(line, ':');
68
+ if (!colon) break;
69
+ char* val = colon + 1;
70
+ while (*val == ' ' || *val == '\t') ++val;
71
+ char* nl = strchr(val, '\n');
72
+ if (nl) *nl = '\0';
73
+ if (strstr(val, "Qualcomm") == nullptr) break;
74
+ const char* last = strrchr(val, ' ');
75
+ if (last && *(last + 1) != '\0') {
76
+ fclose(f);
77
+ return std::string(last + 1);
78
+ }
79
+ fclose(f);
80
+ return std::string(val);
59
81
  }
60
82
  }
61
83
  fclose(f);
62
- return found;
63
- #else
64
- return false;
65
84
  #endif
85
+ return "";
66
86
  }
67
87
 
68
88
  } // namespace margelo::nitro::onnx::speech
@@ -32,7 +32,7 @@ class NitroOnnxSpeech : public HybridOnnxSpeechSpec {
32
32
  std::shared_ptr<HybridTtsSpec> createTts() override;
33
33
  std::shared_ptr<HybridSpeakerManagerSpec> createSpeakerManager() override;
34
34
  std::string getVersion() override;
35
- bool isQualcommCpu() override;
35
+ std::string getQualcommSoc() override;
36
36
 
37
37
  private:
38
38
  std::shared_ptr<ThreadPool> threadPool_;
@@ -53,6 +53,18 @@ std::shared_ptr<Promise<void>> OfflineAsr::load(const AsrModelConfig& config) {
53
53
  native.maxActivePaths = static_cast<int32_t>(config.maxActivePaths.value_or(4));
54
54
  native.language = config.language.value_or("en");
55
55
  native.useItn = config.useItn.value_or(true);
56
+ native.debug = config.debug.value_or(false);
57
+ #ifdef __ANDROID__
58
+ #if defined(SHERPA_ONNX_ENABLE_QNN)
59
+ native.provider = config.provider.value_or("qnn");
60
+ #else
61
+ native.provider = config.provider.value_or("nnapi");
62
+ #endif
63
+ #elif defined(__APPLE__)
64
+ native.provider = config.provider.value_or("coreml");
65
+ #else
66
+ native.provider = config.provider.value_or("cpu");
67
+ #endif
56
68
  engine_.load(native);
57
69
  });
58
70
  }
@@ -47,6 +47,14 @@ std::shared_ptr<Promise<void>> StreamingAsr::load(const AsrModelConfig& config)
47
47
  native.numThreads = static_cast<int32_t>(config.numThreads.value_or(2));
48
48
  native.decodingMethod = config.decodingMethod.value_or("greedy_search");
49
49
  native.maxActivePaths = static_cast<int32_t>(config.maxActivePaths.value_or(4));
50
+ native.debug = config.debug.value_or(false);
51
+ #ifdef __ANDROID__
52
+ native.provider = config.provider.value_or("qnn");
53
+ #elif defined(__APPLE__)
54
+ native.provider = config.provider.value_or("coreml");
55
+ #else
56
+ native.provider = config.provider.value_or("cpu");
57
+ #endif
50
58
  engine_.load(native, shared_cast<StreamingAsr>());
51
59
  });
52
60
  }
package/cpp/Tts.cpp CHANGED
@@ -57,6 +57,12 @@ std::shared_ptr<Promise<void>> Tts::load(const TtsModelConfig& config) {
57
57
  native.outputSampleRate = static_cast<int32_t>(config.outputSampleRate.value_or(16000.0));
58
58
  native.speakerId = static_cast<int32_t>(config.speakerId.value_or(0.0));
59
59
  native.speed = static_cast<float>(config.speed.value_or(1.0));
60
+ native.debug = config.debug.value_or(false);
61
+ #ifdef __APPLE__
62
+ native.provider = config.provider.value_or("coreml");
63
+ #else
64
+ native.provider = config.provider.value_or("cpu");
65
+ #endif
60
66
  engine_.load(native);
61
67
  });
62
68
  }
package/cpp/TtsEngine.cpp CHANGED
@@ -146,8 +146,8 @@ void TtsEngine::load(const TtsEngineConfig& config) {
146
146
  }
147
147
 
148
148
  c.model.num_threads = config_.numThreads;
149
- c.model.debug = 1;
150
- c.model.provider = "cpu";
149
+ c.model.debug = config_.debug ? 1 : 0;
150
+ c.model.provider = config_.provider.c_str();
151
151
  c.rule_fsts = "";
152
152
  c.rule_fars = "";
153
153
  c.max_num_sentences = 1;
package/cpp/TtsEngine.hpp CHANGED
@@ -45,6 +45,12 @@ struct TtsEngineConfig {
45
45
  int32_t outputSampleRate = 16000;
46
46
  int32_t speakerId = 0;
47
47
  float speed = 1.0f;
48
+ bool debug = false;
49
+ #ifdef __APPLE__
50
+ std::string provider = "coreml";
51
+ #else
52
+ std::string provider = "cpu";
53
+ #endif
48
54
  };
49
55
 
50
56
  /** Native synthesis result (samples are kept as a float vector). */
package/cpp/Vad.cpp CHANGED
@@ -53,6 +53,7 @@ std::shared_ptr<Promise<void>> Vad::initialize(const VadConfig& config) {
53
53
  .minSilenceDuration = static_cast<float>(config.minSilenceDurationMs.value_or(500.0)) / 1000.0f,
54
54
  .minSpeechDuration = static_cast<float>(config.minSpeechDurationMs.value_or(250.0)) / 1000.0f,
55
55
  .preBufferMs = static_cast<int32_t>(config.preBufferMs.value_or(300.0)),
56
+ .debug = config.debug.value_or(false),
56
57
  },
57
58
  shared_cast<Vad>());
58
59
  });
package/cpp/VadEngine.cpp CHANGED
@@ -42,6 +42,7 @@ void VadEngine::initialize(const VadEngineConfig& config, std::shared_ptr<VadLis
42
42
  vadConfig.silero_vad.min_speech_duration = config_.minSpeechDuration;
43
43
  vadConfig.sample_rate = kSampleRate;
44
44
  vadConfig.num_threads = 1;
45
+ vadConfig.debug = config_.debug ? 1 : 0;
45
46
 
46
47
  // The second argument is the buffer size in milliseconds used internally by
47
48
  // sherpa-onnx. We reuse the configured pre-buffer duration.
package/cpp/VadEngine.hpp CHANGED
@@ -34,6 +34,7 @@ struct VadEngineConfig {
34
34
  float minSilenceDuration = 0.5f;
35
35
  float minSpeechDuration = 0.25f;
36
36
  int32_t preBufferMs = 300;
37
+ bool debug = false;
37
38
  };
38
39
 
39
40
  /** One buffered or emitted speech segment with raw float samples. */
@@ -57,10 +57,12 @@ namespace margelo::nitro::onnx::speech {
57
57
  std::optional<double> maxActivePaths SWIFT_PRIVATE;
58
58
  std::optional<std::string> language SWIFT_PRIVATE;
59
59
  std::optional<bool> useItn SWIFT_PRIVATE;
60
+ std::optional<bool> debug SWIFT_PRIVATE;
61
+ std::optional<std::string> provider SWIFT_PRIVATE;
60
62
 
61
63
  public:
62
64
  AsrModelConfig() = default;
63
- explicit AsrModelConfig(AsrModelType type, std::string modelDir, std::string tokensPath, std::optional<std::string> whisperEncoder, std::optional<std::string> whisperDecoder, std::optional<std::string> encoder, std::optional<std::string> decoder, std::optional<std::string> joiner, std::optional<std::string> model, std::optional<std::string> config, std::optional<double> numThreads, std::optional<std::string> decodingMethod, std::optional<double> maxActivePaths, std::optional<std::string> language, std::optional<bool> useItn): type(type), modelDir(modelDir), tokensPath(tokensPath), whisperEncoder(whisperEncoder), whisperDecoder(whisperDecoder), encoder(encoder), decoder(decoder), joiner(joiner), model(model), config(config), numThreads(numThreads), decodingMethod(decodingMethod), maxActivePaths(maxActivePaths), language(language), useItn(useItn) {}
65
+ explicit AsrModelConfig(AsrModelType type, std::string modelDir, std::string tokensPath, std::optional<std::string> whisperEncoder, std::optional<std::string> whisperDecoder, std::optional<std::string> encoder, std::optional<std::string> decoder, std::optional<std::string> joiner, std::optional<std::string> model, std::optional<std::string> config, std::optional<double> numThreads, std::optional<std::string> decodingMethod, std::optional<double> maxActivePaths, std::optional<std::string> language, std::optional<bool> useItn, std::optional<bool> debug, std::optional<std::string> provider): type(type), modelDir(modelDir), tokensPath(tokensPath), whisperEncoder(whisperEncoder), whisperDecoder(whisperDecoder), encoder(encoder), decoder(decoder), joiner(joiner), model(model), config(config), numThreads(numThreads), decodingMethod(decodingMethod), maxActivePaths(maxActivePaths), language(language), useItn(useItn), debug(debug), provider(provider) {}
64
66
 
65
67
  public:
66
68
  friend bool operator==(const AsrModelConfig& lhs, const AsrModelConfig& rhs) = default;
@@ -90,7 +92,9 @@ namespace margelo::nitro {
90
92
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "decodingMethod"))),
91
93
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "maxActivePaths"))),
92
94
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "language"))),
93
- JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "useItn")))
95
+ JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "useItn"))),
96
+ JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "debug"))),
97
+ JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "provider")))
94
98
  );
95
99
  }
96
100
  static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::onnx::speech::AsrModelConfig& arg) {
@@ -110,6 +114,8 @@ namespace margelo::nitro {
110
114
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "maxActivePaths"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.maxActivePaths));
111
115
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "language"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.language));
112
116
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "useItn"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.useItn));
117
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "debug"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.debug));
118
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "provider"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.provider));
113
119
  return obj;
114
120
  }
115
121
  static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
@@ -135,6 +141,8 @@ namespace margelo::nitro {
135
141
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "maxActivePaths")))) return false;
136
142
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "language")))) return false;
137
143
  if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "useItn")))) return false;
144
+ if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "debug")))) return false;
145
+ if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "provider")))) return false;
138
146
  return true;
139
147
  }
140
148
  };
@@ -20,7 +20,7 @@ namespace margelo::nitro::onnx::speech {
20
20
  prototype.registerHybridMethod("createStreamingAsr", &HybridOnnxSpeechSpec::createStreamingAsr);
21
21
  prototype.registerHybridMethod("createTts", &HybridOnnxSpeechSpec::createTts);
22
22
  prototype.registerHybridMethod("createSpeakerManager", &HybridOnnxSpeechSpec::createSpeakerManager);
23
- prototype.registerHybridMethod("isQualcommCpu", &HybridOnnxSpeechSpec::isQualcommCpu);
23
+ prototype.registerHybridMethod("getQualcommSoc", &HybridOnnxSpeechSpec::getQualcommSoc);
24
24
  });
25
25
  }
26
26
 
@@ -68,7 +68,7 @@ namespace margelo::nitro::onnx::speech {
68
68
  virtual std::shared_ptr<HybridStreamingAsrSpec> createStreamingAsr() = 0;
69
69
  virtual std::shared_ptr<HybridTtsSpec> createTts() = 0;
70
70
  virtual std::shared_ptr<HybridSpeakerManagerSpec> createSpeakerManager() = 0;
71
- virtual bool isQualcommCpu() = 0;
71
+ virtual std::string getQualcommSoc() = 0;
72
72
 
73
73
  protected:
74
74
  // Hybrid Setup
@@ -66,10 +66,12 @@ namespace margelo::nitro::onnx::speech {
66
66
  std::optional<double> outputSampleRate SWIFT_PRIVATE;
67
67
  std::optional<double> speakerId SWIFT_PRIVATE;
68
68
  std::optional<double> speed SWIFT_PRIVATE;
69
+ std::optional<bool> debug SWIFT_PRIVATE;
70
+ std::optional<std::string> provider SWIFT_PRIVATE;
69
71
 
70
72
  public:
71
73
  TtsModelConfig() = default;
72
- explicit TtsModelConfig(TtsModelType type, std::string modelDir, std::optional<std::string> model, std::optional<std::string> acousticModel, std::optional<std::string> vocoder, std::optional<std::string> tokens, std::optional<std::string> lexicon, std::optional<std::string> voices, std::optional<std::string> espeakNgData, std::optional<std::string> dictDir, std::optional<std::string> lmMain, std::optional<std::string> lmFlow, std::optional<std::string> textConditioner, std::optional<std::string> pocketEncoder, std::optional<std::string> pocketDecoder, std::optional<std::string> vocabJson, std::optional<std::string> tokenScoresJson, std::optional<std::string> zipvoiceEncoder, std::optional<std::string> zipvoiceDecoder, std::optional<std::string> config, std::optional<double> numThreads, std::optional<double> outputSampleRate, std::optional<double> speakerId, std::optional<double> speed): type(type), modelDir(modelDir), model(model), acousticModel(acousticModel), vocoder(vocoder), tokens(tokens), lexicon(lexicon), voices(voices), espeakNgData(espeakNgData), dictDir(dictDir), lmMain(lmMain), lmFlow(lmFlow), textConditioner(textConditioner), pocketEncoder(pocketEncoder), pocketDecoder(pocketDecoder), vocabJson(vocabJson), tokenScoresJson(tokenScoresJson), zipvoiceEncoder(zipvoiceEncoder), zipvoiceDecoder(zipvoiceDecoder), config(config), numThreads(numThreads), outputSampleRate(outputSampleRate), speakerId(speakerId), speed(speed) {}
74
+ explicit TtsModelConfig(TtsModelType type, std::string modelDir, std::optional<std::string> model, std::optional<std::string> acousticModel, std::optional<std::string> vocoder, std::optional<std::string> tokens, std::optional<std::string> lexicon, std::optional<std::string> voices, std::optional<std::string> espeakNgData, std::optional<std::string> dictDir, std::optional<std::string> lmMain, std::optional<std::string> lmFlow, std::optional<std::string> textConditioner, std::optional<std::string> pocketEncoder, std::optional<std::string> pocketDecoder, std::optional<std::string> vocabJson, std::optional<std::string> tokenScoresJson, std::optional<std::string> zipvoiceEncoder, std::optional<std::string> zipvoiceDecoder, std::optional<std::string> config, std::optional<double> numThreads, std::optional<double> outputSampleRate, std::optional<double> speakerId, std::optional<double> speed, std::optional<bool> debug, std::optional<std::string> provider): type(type), modelDir(modelDir), model(model), acousticModel(acousticModel), vocoder(vocoder), tokens(tokens), lexicon(lexicon), voices(voices), espeakNgData(espeakNgData), dictDir(dictDir), lmMain(lmMain), lmFlow(lmFlow), textConditioner(textConditioner), pocketEncoder(pocketEncoder), pocketDecoder(pocketDecoder), vocabJson(vocabJson), tokenScoresJson(tokenScoresJson), zipvoiceEncoder(zipvoiceEncoder), zipvoiceDecoder(zipvoiceDecoder), config(config), numThreads(numThreads), outputSampleRate(outputSampleRate), speakerId(speakerId), speed(speed), debug(debug), provider(provider) {}
73
75
 
74
76
  public:
75
77
  friend bool operator==(const TtsModelConfig& lhs, const TtsModelConfig& rhs) = default;
@@ -108,7 +110,9 @@ namespace margelo::nitro {
108
110
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "numThreads"))),
109
111
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "outputSampleRate"))),
110
112
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speakerId"))),
111
- JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speed")))
113
+ JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speed"))),
114
+ JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "debug"))),
115
+ JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "provider")))
112
116
  );
113
117
  }
114
118
  static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::onnx::speech::TtsModelConfig& arg) {
@@ -137,6 +141,8 @@ namespace margelo::nitro {
137
141
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "outputSampleRate"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.outputSampleRate));
138
142
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "speakerId"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.speakerId));
139
143
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "speed"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.speed));
144
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "debug"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.debug));
145
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "provider"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.provider));
140
146
  return obj;
141
147
  }
142
148
  static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
@@ -171,6 +177,8 @@ namespace margelo::nitro {
171
177
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "outputSampleRate")))) return false;
172
178
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speakerId")))) return false;
173
179
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "speed")))) return false;
180
+ if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "debug")))) return false;
181
+ if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "provider")))) return false;
174
182
  return true;
175
183
  }
176
184
  };
@@ -45,10 +45,11 @@ namespace margelo::nitro::onnx::speech {
45
45
  std::optional<double> minSilenceDurationMs SWIFT_PRIVATE;
46
46
  std::optional<double> minSpeechDurationMs SWIFT_PRIVATE;
47
47
  std::optional<double> preBufferMs SWIFT_PRIVATE;
48
+ std::optional<bool> debug SWIFT_PRIVATE;
48
49
 
49
50
  public:
50
51
  VadConfig() = default;
51
- explicit VadConfig(std::optional<std::string> modelPath, std::optional<double> threshold, std::optional<double> minSilenceDurationMs, std::optional<double> minSpeechDurationMs, std::optional<double> preBufferMs): modelPath(modelPath), threshold(threshold), minSilenceDurationMs(minSilenceDurationMs), minSpeechDurationMs(minSpeechDurationMs), preBufferMs(preBufferMs) {}
52
+ explicit VadConfig(std::optional<std::string> modelPath, std::optional<double> threshold, std::optional<double> minSilenceDurationMs, std::optional<double> minSpeechDurationMs, std::optional<double> preBufferMs, std::optional<bool> debug): modelPath(modelPath), threshold(threshold), minSilenceDurationMs(minSilenceDurationMs), minSpeechDurationMs(minSpeechDurationMs), preBufferMs(preBufferMs), debug(debug) {}
52
53
 
53
54
  public:
54
55
  friend bool operator==(const VadConfig& lhs, const VadConfig& rhs) = default;
@@ -68,7 +69,8 @@ namespace margelo::nitro {
68
69
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "threshold"))),
69
70
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "minSilenceDurationMs"))),
70
71
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "minSpeechDurationMs"))),
71
- JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "preBufferMs")))
72
+ JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "preBufferMs"))),
73
+ JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "debug")))
72
74
  );
73
75
  }
74
76
  static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::onnx::speech::VadConfig& arg) {
@@ -78,6 +80,7 @@ namespace margelo::nitro {
78
80
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "minSilenceDurationMs"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.minSilenceDurationMs));
79
81
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "minSpeechDurationMs"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.minSpeechDurationMs));
80
82
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "preBufferMs"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.preBufferMs));
83
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "debug"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.debug));
81
84
  return obj;
82
85
  }
83
86
  static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
@@ -93,6 +96,7 @@ namespace margelo::nitro {
93
96
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "minSilenceDurationMs")))) return false;
94
97
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "minSpeechDurationMs")))) return false;
95
98
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "preBufferMs")))) return false;
99
+ if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "debug")))) return false;
96
100
  return true;
97
101
  }
98
102
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nitro-onnx",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "React Native Nitro module wrapping sherpa-onnx for local ASR, TTS, VAD and voice cloning",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/zydbkqf/react-native-nitro-onnx",
@@ -47,6 +47,8 @@ export interface VadConfig {
47
47
  minSpeechDurationMs?: number;
48
48
  /** How many milliseconds of audio to keep before onSpeechStart. Default: 300. */
49
49
  preBufferMs?: number;
50
+ /** Enable sherpa-onnx debug logging for this model. Default: false. */
51
+ debug?: boolean;
50
52
  }
51
53
 
52
54
  /** VAD segment delivered after speech ends or on explicit pull. */
@@ -130,6 +132,15 @@ export interface AsrModelConfig {
130
132
  language?: string;
131
133
  /** SenseVoice: whether to use itn. */
132
134
  useItn?: boolean;
135
+ /** Enable sherpa-onnx debug logging for this model. Default: false. */
136
+ debug?: boolean;
137
+ /**
138
+ * Execution provider for ONNX Runtime.
139
+ * Default: "qnn" on Android (Qualcomm NPU, unsupported ops fall back to CPU),
140
+ * "coreml" on iOS (Apple Neural Engine, unsupported ops fall back to CPU).
141
+ * Pass "cpu" explicitly to disable NPU acceleration.
142
+ */
143
+ provider?: string;
133
144
  }
134
145
 
135
146
  export interface AsrResult {
@@ -243,6 +254,15 @@ export interface TtsModelConfig {
243
254
  speakerId?: number;
244
255
  /** Speed factor, e.g. 1.0. */
245
256
  speed?: number;
257
+ /** Enable sherpa-onnx debug logging for this model. Default: false. */
258
+ debug?: boolean;
259
+ /**
260
+ * Execution provider for ONNX Runtime.
261
+ * Default: "qnn" on Android (Qualcomm NPU, unsupported ops fall back to CPU),
262
+ * "coreml" on iOS (Apple Neural Engine, unsupported ops fall back to CPU).
263
+ * Pass "cpu" explicitly to disable NPU acceleration.
264
+ */
265
+ provider?: string;
246
266
  }
247
267
 
248
268
  export interface TtsResult {
@@ -321,6 +341,6 @@ export interface OnnxSpeech extends HybridObject<SpeechPlatforms> {
321
341
  createSpeakerManager(): SpeakerManager;
322
342
  /** Get the module version. */
323
343
  readonly version: string;
324
- /** Check if the CPU is a Qualcomm chip. Always returns false on iOS. */
325
- isQualcommCpu(): boolean;
344
+ /** Returns the Qualcomm SoC model (e.g. "SM8550") on Android, or empty string on iOS / non-Qualcomm. */
345
+ getQualcommSoc(): string;
326
346
  }