react-native-nitro-onnx 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/NOTICE +241 -0
  2. package/NitroOnnxSpeech.podspec +51 -0
  3. package/Package.swift +52 -0
  4. package/README.md +398 -0
  5. package/android/CMakeLists.txt +117 -0
  6. package/android/build.gradle +65 -0
  7. package/android/src/main/AndroidManifest.xml +6 -0
  8. package/android/src/main/assets/silero_vad.onnx +0 -0
  9. package/android/src/main/cpp/cpp-adapter.cpp +24 -0
  10. package/android/src/main/java/com/margelo/nitro/onnx/speech/OnnxSpeechPackage.kt +67 -0
  11. package/assets/silero_vad.onnx +0 -0
  12. package/cpp/AndroidPthreadCompat.cpp +16 -0
  13. package/cpp/AsrEngine.cpp +277 -0
  14. package/cpp/AsrEngine.hpp +110 -0
  15. package/cpp/AudioFileReader.cpp +177 -0
  16. package/cpp/AudioFileReader.hpp +26 -0
  17. package/cpp/AudioUtils.cpp +28 -0
  18. package/cpp/AudioUtils.hpp +38 -0
  19. package/cpp/ModelSingleton.hpp +51 -0
  20. package/cpp/NitroOnnxSpeech.cpp +68 -0
  21. package/cpp/NitroOnnxSpeech.hpp +42 -0
  22. package/cpp/OfflineAsr.cpp +81 -0
  23. package/cpp/OfflineAsr.hpp +33 -0
  24. package/cpp/ResourceDir.cpp +29 -0
  25. package/cpp/ResourceDir.hpp +18 -0
  26. package/cpp/SpeakerEngine.cpp +170 -0
  27. package/cpp/SpeakerEngine.hpp +70 -0
  28. package/cpp/SpeakerManager.cpp +93 -0
  29. package/cpp/SpeakerManager.hpp +43 -0
  30. package/cpp/StreamingAsr.cpp +123 -0
  31. package/cpp/StreamingAsr.hpp +55 -0
  32. package/cpp/ThreadPool.cpp +41 -0
  33. package/cpp/ThreadPool.hpp +62 -0
  34. package/cpp/Tts.cpp +132 -0
  35. package/cpp/Tts.hpp +38 -0
  36. package/cpp/TtsEngine.cpp +222 -0
  37. package/cpp/TtsEngine.hpp +77 -0
  38. package/cpp/Vad.cpp +126 -0
  39. package/cpp/Vad.hpp +62 -0
  40. package/cpp/VadEngine.cpp +217 -0
  41. package/cpp/VadEngine.hpp +126 -0
  42. package/ios/OnnxSpeechInitializer.mm +37 -0
  43. package/ios/PrivacyInfo.xcprivacy +14 -0
  44. package/lib/index.d.ts +11 -0
  45. package/lib/index.d.ts.map +1 -0
  46. package/lib/index.js +19 -0
  47. package/lib/index.js.map +1 -0
  48. package/lib/specs/OnnxSpeech.nitro.d.ts +264 -0
  49. package/lib/specs/OnnxSpeech.nitro.d.ts.map +1 -0
  50. package/lib/specs/OnnxSpeech.nitro.js +6 -0
  51. package/lib/specs/OnnxSpeech.nitro.js.map +1 -0
  52. package/nitro.json +19 -0
  53. package/nitrogen/generated/.gitattributes +1 -0
  54. package/nitrogen/generated/android/NitroOnnxSpeech+autolinking.cmake +86 -0
  55. package/nitrogen/generated/android/NitroOnnxSpeech+autolinking.gradle +27 -0
  56. package/nitrogen/generated/android/NitroOnnxSpeechOnLoad.cpp +49 -0
  57. package/nitrogen/generated/android/NitroOnnxSpeechOnLoad.hpp +34 -0
  58. package/nitrogen/generated/android/kotlin/com/margelo/nitro/onnx/speech/NitroOnnxSpeechOnLoad.kt +35 -0
  59. package/nitrogen/generated/ios/NitroOnnxSpeech+autolinking.rb +62 -0
  60. package/nitrogen/generated/ios/NitroOnnxSpeech-Swift-Cxx-Bridge.cpp +17 -0
  61. package/nitrogen/generated/ios/NitroOnnxSpeech-Swift-Cxx-Bridge.hpp +27 -0
  62. package/nitrogen/generated/ios/NitroOnnxSpeech-Swift-Cxx-Umbrella.hpp +38 -0
  63. package/nitrogen/generated/ios/NitroOnnxSpeechAutolinking.mm +35 -0
  64. package/nitrogen/generated/ios/NitroOnnxSpeechAutolinking.swift +16 -0
  65. package/nitrogen/generated/shared/c++/AsrModelConfig.hpp +142 -0
  66. package/nitrogen/generated/shared/c++/AsrModelType.hpp +112 -0
  67. package/nitrogen/generated/shared/c++/AsrResult.hpp +105 -0
  68. package/nitrogen/generated/shared/c++/HybridOfflineAsrSpec.cpp +25 -0
  69. package/nitrogen/generated/shared/c++/HybridOfflineAsrSpec.hpp +73 -0
  70. package/nitrogen/generated/shared/c++/HybridOnnxSpeechSpec.cpp +27 -0
  71. package/nitrogen/generated/shared/c++/HybridOnnxSpeechSpec.hpp +82 -0
  72. package/nitrogen/generated/shared/c++/HybridSpeakerManagerSpec.cpp +28 -0
  73. package/nitrogen/generated/shared/c++/HybridSpeakerManagerSpec.hpp +77 -0
  74. package/nitrogen/generated/shared/c++/HybridStreamingAsrSpec.cpp +32 -0
  75. package/nitrogen/generated/shared/c++/HybridStreamingAsrSpec.hpp +81 -0
  76. package/nitrogen/generated/shared/c++/HybridTtsSpec.cpp +26 -0
  77. package/nitrogen/generated/shared/c++/HybridTtsSpec.hpp +74 -0
  78. package/nitrogen/generated/shared/c++/HybridVadSpec.cpp +31 -0
  79. package/nitrogen/generated/shared/c++/HybridVadSpec.hpp +81 -0
  80. package/nitrogen/generated/shared/c++/RegisteredSpeaker.hpp +91 -0
  81. package/nitrogen/generated/shared/c++/SpeakerEmbeddingConfig.hpp +91 -0
  82. package/nitrogen/generated/shared/c++/TtsModelConfig.hpp +178 -0
  83. package/nitrogen/generated/shared/c++/TtsModelType.hpp +88 -0
  84. package/nitrogen/generated/shared/c++/TtsResult.hpp +91 -0
  85. package/nitrogen/generated/shared/c++/VadConfig.hpp +100 -0
  86. package/nitrogen/generated/shared/c++/VadSegment.hpp +91 -0
  87. package/package.json +62 -0
  88. package/scripts/prepare-sherpa-onnx.js +236 -0
  89. package/scripts/test-cpp.js +24 -0
  90. package/src/index.ts +45 -0
  91. package/src/specs/OnnxSpeech.nitro.ts +326 -0
@@ -0,0 +1,100 @@
1
+ ///
2
+ /// VadConfig.hpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #pragma once
9
+
10
+ #if __has_include(<NitroModules/JSIConverter.hpp>)
11
+ #include <NitroModules/JSIConverter.hpp>
12
+ #else
13
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
14
+ #endif
15
+ #if __has_include(<NitroModules/NitroDefines.hpp>)
16
+ #include <NitroModules/NitroDefines.hpp>
17
+ #else
18
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
19
+ #endif
20
+ #if __has_include(<NitroModules/JSIHelpers.hpp>)
21
+ #include <NitroModules/JSIHelpers.hpp>
22
+ #else
23
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
24
+ #endif
25
+ #if __has_include(<NitroModules/PropNameIDCache.hpp>)
26
+ #include <NitroModules/PropNameIDCache.hpp>
27
+ #else
28
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
29
+ #endif
30
+
31
+
32
+
33
+ #include <string>
34
+ #include <optional>
35
+
36
+ namespace margelo::nitro::onnx::speech {
37
+
38
+ /**
39
+ * A struct which can be represented as a JavaScript object (VadConfig).
40
+ */
41
+ struct VadConfig final {
42
+ public:
43
+ std::optional<std::string> modelPath SWIFT_PRIVATE;
44
+ std::optional<double> threshold SWIFT_PRIVATE;
45
+ std::optional<double> minSilenceDurationMs SWIFT_PRIVATE;
46
+ std::optional<double> minSpeechDurationMs SWIFT_PRIVATE;
47
+ std::optional<double> preBufferMs SWIFT_PRIVATE;
48
+
49
+ public:
50
+ 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
+
53
+ public:
54
+ friend bool operator==(const VadConfig& lhs, const VadConfig& rhs) = default;
55
+ };
56
+
57
+ } // namespace margelo::nitro::onnx::speech
58
+
59
+ namespace margelo::nitro {
60
+
61
+ // C++ VadConfig <> JS VadConfig (object)
62
+ template <>
63
+ struct JSIConverter<margelo::nitro::onnx::speech::VadConfig> final {
64
+ static inline margelo::nitro::onnx::speech::VadConfig fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
65
+ jsi::Object obj = arg.asObject(runtime);
66
+ return margelo::nitro::onnx::speech::VadConfig(
67
+ JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "modelPath"))),
68
+ JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "threshold"))),
69
+ JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "minSilenceDurationMs"))),
70
+ 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
+ );
73
+ }
74
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::onnx::speech::VadConfig& arg) {
75
+ jsi::Object obj(runtime);
76
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "modelPath"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.modelPath));
77
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "threshold"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.threshold));
78
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "minSilenceDurationMs"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.minSilenceDurationMs));
79
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "minSpeechDurationMs"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.minSpeechDurationMs));
80
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "preBufferMs"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.preBufferMs));
81
+ return obj;
82
+ }
83
+ static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
84
+ if (!value.isObject()) {
85
+ return false;
86
+ }
87
+ jsi::Object obj = value.getObject(runtime);
88
+ if (!nitro::isPlainObject(runtime, obj)) {
89
+ return false;
90
+ }
91
+ if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "modelPath")))) return false;
92
+ if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "threshold")))) return false;
93
+ if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "minSilenceDurationMs")))) return false;
94
+ if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "minSpeechDurationMs")))) return false;
95
+ if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "preBufferMs")))) return false;
96
+ return true;
97
+ }
98
+ };
99
+
100
+ } // namespace margelo::nitro
@@ -0,0 +1,91 @@
1
+ ///
2
+ /// VadSegment.hpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #pragma once
9
+
10
+ #if __has_include(<NitroModules/JSIConverter.hpp>)
11
+ #include <NitroModules/JSIConverter.hpp>
12
+ #else
13
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
14
+ #endif
15
+ #if __has_include(<NitroModules/NitroDefines.hpp>)
16
+ #include <NitroModules/NitroDefines.hpp>
17
+ #else
18
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
19
+ #endif
20
+ #if __has_include(<NitroModules/JSIHelpers.hpp>)
21
+ #include <NitroModules/JSIHelpers.hpp>
22
+ #else
23
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
24
+ #endif
25
+ #if __has_include(<NitroModules/PropNameIDCache.hpp>)
26
+ #include <NitroModules/PropNameIDCache.hpp>
27
+ #else
28
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
29
+ #endif
30
+
31
+
32
+
33
+ #include <NitroModules/ArrayBuffer.hpp>
34
+
35
+ namespace margelo::nitro::onnx::speech {
36
+
37
+ /**
38
+ * A struct which can be represented as a JavaScript object (VadSegment).
39
+ */
40
+ struct VadSegment final {
41
+ public:
42
+ double startMs SWIFT_PRIVATE;
43
+ double endMs SWIFT_PRIVATE;
44
+ std::shared_ptr<ArrayBuffer> samples SWIFT_PRIVATE;
45
+
46
+ public:
47
+ VadSegment() = default;
48
+ explicit VadSegment(double startMs, double endMs, std::shared_ptr<ArrayBuffer> samples): startMs(startMs), endMs(endMs), samples(samples) {}
49
+
50
+ public:
51
+ friend bool operator==(const VadSegment& lhs, const VadSegment& rhs) = default;
52
+ };
53
+
54
+ } // namespace margelo::nitro::onnx::speech
55
+
56
+ namespace margelo::nitro {
57
+
58
+ // C++ VadSegment <> JS VadSegment (object)
59
+ template <>
60
+ struct JSIConverter<margelo::nitro::onnx::speech::VadSegment> final {
61
+ static inline margelo::nitro::onnx::speech::VadSegment fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
62
+ jsi::Object obj = arg.asObject(runtime);
63
+ return margelo::nitro::onnx::speech::VadSegment(
64
+ JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "startMs"))),
65
+ JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "endMs"))),
66
+ JSIConverter<std::shared_ptr<ArrayBuffer>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "samples")))
67
+ );
68
+ }
69
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::onnx::speech::VadSegment& arg) {
70
+ jsi::Object obj(runtime);
71
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "startMs"), JSIConverter<double>::toJSI(runtime, arg.startMs));
72
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "endMs"), JSIConverter<double>::toJSI(runtime, arg.endMs));
73
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "samples"), JSIConverter<std::shared_ptr<ArrayBuffer>>::toJSI(runtime, arg.samples));
74
+ return obj;
75
+ }
76
+ static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
77
+ if (!value.isObject()) {
78
+ return false;
79
+ }
80
+ jsi::Object obj = value.getObject(runtime);
81
+ if (!nitro::isPlainObject(runtime, obj)) {
82
+ return false;
83
+ }
84
+ if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "startMs")))) return false;
85
+ if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "endMs")))) return false;
86
+ if (!JSIConverter<std::shared_ptr<ArrayBuffer>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "samples")))) return false;
87
+ return true;
88
+ }
89
+ };
90
+
91
+ } // namespace margelo::nitro
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "react-native-nitro-onnx",
3
+ "version": "0.1.0",
4
+ "description": "React Native Nitro module wrapping sherpa-onnx for local ASR, TTS, VAD and voice cloning",
5
+ "license": "MIT",
6
+ "homepage": "https://github.com/zydbkqf/react-native-nitro-onnx",
7
+ "author": "Denis Cheung (https://github.com/zydbkqf)",
8
+ "type": "module",
9
+ "main": "lib/index.js",
10
+ "types": "lib/index.d.ts",
11
+ "source": "src/index.ts",
12
+ "scripts": {
13
+ "postinstall": "node scripts/prepare-sherpa-onnx.js",
14
+ "prespecs": "node scripts/prepare-sherpa-onnx.js",
15
+ "build": "tsc",
16
+ "specs": "nitrogen",
17
+ "test": "jest",
18
+ "test:cpp": "node scripts/test-cpp.js"
19
+ },
20
+ "peerDependencies": {
21
+ "react": "*",
22
+ "react-native": ">=0.78.0",
23
+ "react-native-nitro-modules": ">=0.35.8"
24
+ },
25
+ "devDependencies": {
26
+ "@types/jest": "^29.5.0",
27
+ "@types/node": "^20.0.0",
28
+ "@types/react": "^18.0.0",
29
+ "jest": "^29.7.0",
30
+ "jest-util": "^29.7.0",
31
+ "nitrogen": "*",
32
+ "react": "*",
33
+ "react-native": "*",
34
+ "react-native-nitro-modules": ">=0.35.8",
35
+ "ts-jest": "^29.1.0",
36
+ "typescript": "5.4.5"
37
+ },
38
+ "files": [
39
+ "src",
40
+ "!src/__tests__",
41
+ "!src/__mocks__",
42
+ "lib",
43
+ "!lib/__tests__",
44
+ "!lib/__mocks__",
45
+ "cpp",
46
+ "!cpp/tests",
47
+ "!cpp/build*",
48
+ "!cpp/sherpa-onnx-prebuilt",
49
+ "android",
50
+ "ios",
51
+ "assets",
52
+ "scripts",
53
+ "Package.swift",
54
+ "nitro.json",
55
+ "nitrogen",
56
+ "NitroOnnxSpeech.podspec",
57
+ "LICENSE",
58
+ "NOTICE",
59
+ "README.md"
60
+ ],
61
+ "packageManager": "yarn@4.17.1"
62
+ }
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env node
2
+ // ------------------------------------------------------------------------------
3
+ // Downloads the sherpa-onnx prebuilt trees needed by Android and iOS builds
4
+ // into cpp/sherpa-onnx-prebuilt.
5
+ //
6
+ // The directory layout after a successful run is:
7
+ //
8
+ // cpp/sherpa-onnx-prebuilt/
9
+ // include/sherpa-onnx/c-api/c-api.h
10
+ // lib/ # host static libraries (optional)
11
+ // android/jniLibs/<abi>/ # Android shared libraries
12
+ // ios/SherpaOnnxC.xcframework/ # iOS device + simulator static archive
13
+ //
14
+ // Host libraries are only downloaded when running on the matching host
15
+ // platform. Android and iOS trees are always fetched so that cross-platform
16
+ // React Native builds can proceed without extra environment variables.
17
+ // ------------------------------------------------------------------------------
18
+
19
+ import { execFile } from "node:child_process";
20
+ import { createWriteStream, existsSync, mkdirSync } from "node:fs";
21
+ import fs from "node:fs/promises";
22
+ import https from "node:https";
23
+ import os from "node:os";
24
+ import path from "node:path";
25
+ import { pipeline } from "node:stream/promises";
26
+ import { promisify } from "node:util";
27
+
28
+ const VERSION = "v1.13.7";
29
+ const PREBUILT_DIR = path.join(process.cwd(), "cpp", "sherpa-onnx-prebuilt");
30
+ const execFileAsync = promisify(execFile);
31
+
32
+ function platformArchive() {
33
+ const platform = os.platform();
34
+ const arch = os.arch();
35
+ if (platform === "darwin" && arch === "arm64") {
36
+ return `sherpa-onnx-${VERSION}-osx-arm64-static-lib.tar.bz2`;
37
+ }
38
+ if (platform === "darwin" && arch === "x64") {
39
+ return `sherpa-onnx-${VERSION}-osx-x64-static-lib.tar.bz2`;
40
+ }
41
+ if (platform === "linux" && arch === "x64") {
42
+ return `sherpa-onnx-${VERSION}-linux-x64-static-lib.tar.bz2`;
43
+ }
44
+ if (platform === "linux" && arch === "arm64") {
45
+ return `sherpa-onnx-${VERSION}-linux-aarch64-static-lib.tar.bz2`;
46
+ }
47
+ if (platform === "win32" && arch === "x64") {
48
+ return `sherpa-onnx-${VERSION}-win-x64-static-MD-Release-lib.tar.bz2`;
49
+ }
50
+ if (platform === "win32" && arch === "arm64") {
51
+ return `sherpa-onnx-${VERSION}-win-arm64-static-MD-Release-lib.tar.bz2`;
52
+ }
53
+ return null;
54
+ }
55
+
56
+ function isHostLibPresent() {
57
+ const unixLib = path.join(PREBUILT_DIR, "lib", "libsherpa-onnx-c-api.a");
58
+ const windowsLib = path.join(PREBUILT_DIR, "lib", "sherpa-onnx-c-api.lib");
59
+ return existsSync(unixLib) || existsSync(windowsLib);
60
+ }
61
+
62
+ function isAndroidLibPresent() {
63
+ return existsSync(
64
+ path.join(PREBUILT_DIR, "android", "jniLibs", "arm64-v8a", "libsherpa-onnx-c-api.so")
65
+ );
66
+ }
67
+
68
+ function isIosFrameworkPresent() {
69
+ return existsSync(
70
+ path.join(PREBUILT_DIR, "ios", "SherpaOnnxC.xcframework", "Info.plist")
71
+ );
72
+ }
73
+
74
+ function isHeaderPresent() {
75
+ return existsSync(
76
+ path.join(PREBUILT_DIR, "include", "sherpa-onnx", "c-api", "c-api.h")
77
+ );
78
+ }
79
+
80
+ async function downloadFile(url, destination) {
81
+ const file = createWriteStream(destination);
82
+ await new Promise((resolve, reject) => {
83
+ https
84
+ .get(url, (response) => {
85
+ if (response.statusCode === 302 || response.statusCode === 301) {
86
+ downloadFile(response.headers.location, destination).then(resolve).catch(reject);
87
+ return;
88
+ }
89
+ if (response.statusCode !== 200) {
90
+ reject(new Error(`Download failed for ${url}: ${response.statusCode}`));
91
+ return;
92
+ }
93
+ pipeline(response, file).then(resolve).catch(reject);
94
+ })
95
+ .on("error", reject);
96
+ });
97
+ }
98
+
99
+ async function extractTarBz2(archivePath, cwd, stripComponents = 1) {
100
+ // Use the system tar binary. Windows 10/11 ships tar.exe with bzip2 support.
101
+ await execFileAsync("tar", [
102
+ "-xjf",
103
+ archivePath,
104
+ "-C",
105
+ cwd,
106
+ `--strip-components=${stripComponents}`,
107
+ ]);
108
+ }
109
+
110
+ async function extractZip(archivePath, cwd) {
111
+ if (os.platform() === "win32") {
112
+ await execFileAsync("powershell", [
113
+ "-Command",
114
+ `Expand-Archive -Path "${archivePath}" -DestinationPath "${cwd}" -Force`,
115
+ ]);
116
+ } else {
117
+ await execFileAsync("unzip", ["-q", "-o", archivePath, "-d", cwd]);
118
+ }
119
+ }
120
+
121
+ async function downloadHeader() {
122
+ const includeDir = path.join(PREBUILT_DIR, "include", "sherpa-onnx", "c-api");
123
+ mkdirSync(includeDir, { recursive: true });
124
+
125
+ const url = `https://raw.githubusercontent.com/k2-fsa/sherpa-onnx/${VERSION}/sherpa-onnx/c-api/c-api.h`;
126
+ const destination = path.join(includeDir, "c-api.h");
127
+ console.log("Downloading sherpa-onnx C API header...");
128
+ await downloadFile(url, destination);
129
+ }
130
+
131
+ async function downloadHostLibs() {
132
+ const archive = platformArchive();
133
+ if (archive == null) {
134
+ console.log("Skipping host library download: unsupported host platform.");
135
+ return;
136
+ }
137
+
138
+ const url = `https://github.com/k2-fsa/sherpa-onnx/releases/download/${VERSION}/${archive}`;
139
+ const downloadPath = path.join(PREBUILT_DIR, archive);
140
+
141
+ console.log(`Downloading host sherpa-onnx prebuilt: ${archive}...`);
142
+ await downloadFile(url, downloadPath);
143
+
144
+ console.log("Extracting host archive...");
145
+ await extractTarBz2(downloadPath, PREBUILT_DIR, 1);
146
+ await fs.unlink(downloadPath);
147
+ }
148
+
149
+ async function downloadAndroidLibs() {
150
+ const archive = `sherpa-onnx-${VERSION}-android.tar.bz2`;
151
+ const url = `https://github.com/k2-fsa/sherpa-onnx/releases/download/${VERSION}/${archive}`;
152
+ const downloadPath = path.join(PREBUILT_DIR, archive);
153
+
154
+ console.log(`Downloading Android sherpa-onnx prebuilt: ${archive}...`);
155
+ await downloadFile(url, downloadPath);
156
+
157
+ // The archive contains a top-level jniLibs/ directory. Extract it to a
158
+ // temporary location and move it into android/jniLibs.
159
+ const tempDir = path.join(PREBUILT_DIR, `.android-tmp-${Date.now()}`);
160
+ mkdirSync(tempDir, { recursive: true });
161
+ console.log("Extracting Android archive...");
162
+ await extractTarBz2(downloadPath, tempDir, 0);
163
+
164
+ const sourceDir = path.join(tempDir, "jniLibs");
165
+ const targetDir = path.join(PREBUILT_DIR, "android", "jniLibs");
166
+ if (existsSync(targetDir)) {
167
+ await fs.rm(targetDir, { recursive: true, force: true });
168
+ }
169
+ mkdirSync(path.dirname(targetDir), { recursive: true });
170
+ await fs.rename(sourceDir, targetDir);
171
+ await fs.rm(tempDir, { recursive: true, force: true });
172
+ await fs.unlink(downloadPath);
173
+ }
174
+
175
+ async function downloadIosFramework() {
176
+ const archive = `sherpa-onnx-${VERSION}-ios-shared-onnxruntime-static.xcframework.zip`;
177
+ const url = `https://github.com/k2-fsa/sherpa-onnx/releases/download/xcframework/${archive}`;
178
+ const downloadPath = path.join(PREBUILT_DIR, archive);
179
+
180
+ console.log(`Downloading iOS sherpa-onnx prebuilt: ${archive}...`);
181
+ await downloadFile(url, downloadPath);
182
+
183
+ // The archive contains the xcframework at the top level. The
184
+ // ios-shared-onnxruntime-static variant names it SherpaOnnxC.xcframework
185
+ // (matching the inner framework name so CocoaPods generates correct linker
186
+ // flags). Extract to a temporary location and move it into ios/.
187
+ const tempDir = path.join(PREBUILT_DIR, `.ios-tmp-${Date.now()}`);
188
+ mkdirSync(tempDir, { recursive: true });
189
+ console.log("Extracting iOS archive...");
190
+ await extractZip(downloadPath, tempDir);
191
+
192
+ const targetDir = path.join(PREBUILT_DIR, "ios", "SherpaOnnxC.xcframework");
193
+ if (existsSync(targetDir)) {
194
+ await fs.rm(targetDir, { recursive: true, force: true });
195
+ }
196
+ mkdirSync(path.dirname(targetDir), { recursive: true });
197
+
198
+ const expectedName = path.join(tempDir, "SherpaOnnxC.xcframework");
199
+ const legacyName = path.join(tempDir, "sherpa-onnx.xcframework");
200
+ const sourceDir = existsSync(expectedName) ? expectedName : legacyName;
201
+
202
+ await fs.rename(sourceDir, targetDir);
203
+ await fs.rm(tempDir, { recursive: true, force: true });
204
+ await fs.unlink(downloadPath);
205
+ }
206
+
207
+ async function main() {
208
+ mkdirSync(PREBUILT_DIR, { recursive: true });
209
+
210
+ const tasks = [];
211
+ if (!isHeaderPresent()) {
212
+ tasks.push(downloadHeader());
213
+ }
214
+ if (!isHostLibPresent()) {
215
+ tasks.push(downloadHostLibs());
216
+ }
217
+ if (!isAndroidLibPresent()) {
218
+ tasks.push(downloadAndroidLibs());
219
+ }
220
+ if (!isIosFrameworkPresent()) {
221
+ tasks.push(downloadIosFramework());
222
+ }
223
+
224
+ if (tasks.length === 0) {
225
+ console.log("sherpa-onnx prebuilt tree is already present.");
226
+ return;
227
+ }
228
+
229
+ await Promise.all(tasks);
230
+ console.log(`sherpa-onnx prebuilt tree ready at ${PREBUILT_DIR}`);
231
+ }
232
+
233
+ main().catch((err) => {
234
+ console.error(err);
235
+ process.exit(1);
236
+ });
@@ -0,0 +1,24 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { execSync } from 'child_process';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ const ROOT = path.resolve(__dirname, '..');
10
+ const ANDROID_CMAKE_DIR = path.join(ROOT, 'android');
11
+ const BUILD_DIR = path.join(ROOT, 'cpp', 'build-tests');
12
+
13
+ function run(command, cwd) {
14
+ console.log(`[test-cpp] ${command}`);
15
+ execSync(command, { cwd, stdio: 'inherit' });
16
+ }
17
+
18
+ if (!fs.existsSync(BUILD_DIR)) {
19
+ fs.mkdirSync(BUILD_DIR, { recursive: true });
20
+ }
21
+
22
+ run(`cmake -S "${ANDROID_CMAKE_DIR}" -B "${BUILD_DIR}" -DBUILD_ONNX_SPEECH_TESTS=ON`, ROOT);
23
+ run(`cmake --build "${BUILD_DIR}" --target NitroOnnxSpeechTests --parallel`, ROOT);
24
+ run(`ctest --test-dir "${BUILD_DIR}" --output-on-failure`, ROOT);
package/src/index.ts ADDED
@@ -0,0 +1,45 @@
1
+ // ------------------------------------------------------------------------------
2
+ // Public entry point for react-native-nitro-onnx.
3
+ // ------------------------------------------------------------------------------
4
+
5
+ import { NitroModules } from "react-native-nitro-modules";
6
+ import type { AudioFormat, OnnxSpeech } from "./specs/OnnxSpeech.nitro.js";
7
+
8
+ export type {
9
+ AudioFormat,
10
+ Result,
11
+ VadConfig,
12
+ VadSegment,
13
+ VadEvents,
14
+ Vad,
15
+ AsrModelType,
16
+ AsrModelConfig,
17
+ AsrResult,
18
+ StreamingAsrEvents,
19
+ OfflineAsr,
20
+ StreamingAsr,
21
+ TtsModelType,
22
+ TtsModelConfig,
23
+ TtsResult,
24
+ Tts,
25
+ SpeakerEmbeddingConfig,
26
+ RegisteredSpeaker,
27
+ SpeakerManager,
28
+ OnnxSpeech,
29
+ } from "./specs/OnnxSpeech.nitro.js";
30
+
31
+ /**
32
+ * Get the shared OnnxSpeech Nitro module instance.
33
+ * Heavy AI models are loaded on demand and cached as singletons behind
34
+ * the individual hybrid objects (Vad, Asr, Tts, SpeakerManager).
35
+ */
36
+ export function getOnnxSpeech(): OnnxSpeech {
37
+ return NitroModules.createHybridObject<OnnxSpeech>("NitroOnnxSpeech");
38
+ }
39
+
40
+ /** Default 16 kHz mono f32 PCM format used by every audio interface. */
41
+ export const DEFAULT_AUDIO_FORMAT: AudioFormat = {
42
+ sampleRate: 16000,
43
+ channels: 1,
44
+ sampleFormat: "f32le",
45
+ };