@gmessier/nitro-speech 0.3.3 → 0.4.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.
- package/LICENSE +21 -0
- package/README.md +176 -148
- package/android/build.gradle +0 -1
- package/android/src/main/cpp/cpp-adapter.cpp +5 -1
- package/android/src/main/java/com/margelo/nitro/nitrospeech/HybridNitroSpeech.kt +2 -0
- package/android/src/main/java/com/margelo/nitro/nitrospeech/recognizer/AutoStopper.kt +82 -18
- package/android/src/main/java/com/margelo/nitro/nitrospeech/recognizer/HybridRecognizer.kt +118 -30
- package/android/src/main/java/com/margelo/nitro/nitrospeech/recognizer/Logger.kt +16 -0
- package/android/src/main/java/com/margelo/nitro/nitrospeech/recognizer/RecognitionListenerSession.kt +35 -24
- package/ios/{BufferUtil.swift → Audio/AudioBufferConverter.swift} +3 -34
- package/ios/Audio/AudioLevelTracker.swift +60 -0
- package/ios/Coordinator.swift +105 -0
- package/ios/Engines/AnalyzerEngine.swift +241 -0
- package/ios/Engines/DictationRuntime.swift +67 -0
- package/ios/Engines/RecognizerEngine.swift +315 -0
- package/ios/Engines/SFSpeechEngine.swift +119 -0
- package/ios/Engines/SpeechRuntime.swift +58 -0
- package/ios/Engines/TranscriberRuntimeProtocol.swift +21 -0
- package/ios/HybridNitroSpeech.swift +1 -10
- package/ios/HybridRecognizer.swift +142 -191
- package/ios/LocaleManager.swift +73 -0
- package/ios/{AppStateObserver.swift → Shared/AppStateObserver.swift} +1 -2
- package/ios/Shared/AutoStopper.swift +147 -0
- package/ios/Shared/HapticImpact.swift +24 -0
- package/ios/Shared/Log.swift +41 -0
- package/ios/Shared/Permissions.swift +59 -0
- package/ios/Shared/Utils.swift +58 -0
- package/lib/NitroSpeech.d.ts +2 -0
- package/lib/NitroSpeech.js +2 -0
- package/lib/Recognizer/RecognizerRef.d.ts +7 -0
- package/lib/Recognizer/RecognizerRef.js +16 -0
- package/lib/Recognizer/SpeechRecognizer.d.ts +8 -0
- package/lib/Recognizer/SpeechRecognizer.js +9 -0
- package/lib/Recognizer/methods.d.ts +9 -0
- package/lib/Recognizer/methods.js +33 -0
- package/lib/Recognizer/types.d.ts +6 -0
- package/lib/Recognizer/types.js +1 -0
- package/lib/Recognizer/useRecognizer.d.ts +16 -0
- package/lib/Recognizer/useRecognizer.js +71 -0
- package/lib/Recognizer/useRecognizerIsActive.d.ts +25 -0
- package/lib/Recognizer/useRecognizerIsActive.js +40 -0
- package/lib/Recognizer/useVoiceInputVolume.d.ts +25 -0
- package/lib/Recognizer/useVoiceInputVolume.js +52 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.js +7 -0
- package/lib/specs/NitroSpeech.nitro.d.ts +8 -0
- package/lib/specs/NitroSpeech.nitro.js +1 -0
- package/lib/specs/Recognizer.nitro.d.ts +97 -0
- package/lib/specs/Recognizer.nitro.js +1 -0
- package/lib/specs/SpeechRecognitionConfig.d.ts +162 -0
- package/lib/specs/SpeechRecognitionConfig.js +1 -0
- package/lib/specs/VolumeChangeEvent.d.ts +31 -0
- package/lib/specs/VolumeChangeEvent.js +1 -0
- package/nitro.json +0 -4
- package/nitrogen/generated/android/NitroSpeech+autolinking.cmake +2 -2
- package/nitrogen/generated/android/NitroSpeechOnLoad.cpp +4 -2
- package/nitrogen/generated/android/c++/JFunc_void_VolumeChangeEvent.hpp +78 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_std__string_.hpp +14 -14
- package/nitrogen/generated/android/c++/JHybridRecognizerSpec.cpp +73 -19
- package/nitrogen/generated/android/c++/JHybridRecognizerSpec.hpp +8 -4
- package/nitrogen/generated/android/c++/JIosPreset.hpp +58 -0
- package/nitrogen/generated/android/c++/JMutableSpeechRecognitionConfig.hpp +79 -0
- package/nitrogen/generated/android/c++/{JSpeechToTextParams.hpp → JSpeechRecognitionConfig.hpp} +48 -30
- package/nitrogen/generated/android/c++/JVolumeChangeEvent.hpp +65 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrospeech/Func_void_VolumeChangeEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrospeech/HybridRecognizerSpec.kt +22 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrospeech/IosPreset.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrospeech/MutableSpeechRecognitionConfig.kt +76 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrospeech/SpeechRecognitionConfig.kt +121 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrospeech/VolumeChangeEvent.kt +61 -0
- package/nitrogen/generated/ios/NitroSpeech-Swift-Cxx-Bridge.cpp +46 -30
- package/nitrogen/generated/ios/NitroSpeech-Swift-Cxx-Bridge.hpp +211 -69
- package/nitrogen/generated/ios/NitroSpeech-Swift-Cxx-Umbrella.hpp +13 -3
- package/nitrogen/generated/ios/c++/HybridRecognizerSpecSwift.hpp +49 -9
- package/nitrogen/generated/ios/swift/Func_void_VolumeChangeEvent.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
- package/nitrogen/generated/ios/swift/HybridRecognizerSpec.swift +7 -3
- package/nitrogen/generated/ios/swift/HybridRecognizerSpec_cxx.swift +78 -18
- package/nitrogen/generated/ios/swift/IosPreset.swift +40 -0
- package/nitrogen/generated/ios/swift/MutableSpeechRecognitionConfig.swift +118 -0
- package/nitrogen/generated/ios/swift/{SpeechToTextParams.swift → SpeechRecognitionConfig.swift} +108 -43
- package/nitrogen/generated/ios/swift/VolumeChangeEvent.swift +52 -0
- package/nitrogen/generated/shared/c++/HybridRecognizerSpec.cpp +5 -1
- package/nitrogen/generated/shared/c++/HybridRecognizerSpec.hpp +18 -7
- package/nitrogen/generated/shared/c++/IosPreset.hpp +76 -0
- package/nitrogen/generated/shared/c++/MutableSpeechRecognitionConfig.hpp +105 -0
- package/nitrogen/generated/shared/c++/{SpeechToTextParams.hpp → SpeechRecognitionConfig.hpp} +39 -20
- package/nitrogen/generated/shared/c++/VolumeChangeEvent.hpp +91 -0
- package/package.json +15 -16
- package/src/NitroSpeech.ts +5 -0
- package/src/Recognizer/RecognizerRef.ts +27 -0
- package/src/Recognizer/SpeechRecognizer.ts +10 -0
- package/src/Recognizer/methods.ts +45 -0
- package/src/Recognizer/types.ts +34 -0
- package/src/Recognizer/useRecognizer.ts +87 -0
- package/src/Recognizer/useRecognizerIsActive.ts +49 -0
- package/src/Recognizer/useVoiceInputVolume.ts +65 -0
- package/src/index.ts +13 -182
- package/src/specs/NitroSpeech.nitro.ts +2 -163
- package/src/specs/Recognizer.nitro.ts +113 -0
- package/src/specs/SpeechRecognitionConfig.ts +167 -0
- package/src/specs/VolumeChangeEvent.ts +31 -0
- package/android/proguard-rules.pro +0 -1
- package/ios/AnylyzerTranscriber.swift +0 -331
- package/ios/AutoStopper.swift +0 -69
- package/ios/HapticImpact.swift +0 -32
- package/ios/LegacySpeechRecognizer.swift +0 -161
- package/lib/commonjs/index.js +0 -145
- package/lib/commonjs/index.js.map +0 -1
- package/lib/commonjs/package.json +0 -1
- package/lib/commonjs/specs/NitroSpeech.nitro.js +0 -6
- package/lib/commonjs/specs/NitroSpeech.nitro.js.map +0 -1
- package/lib/module/index.js +0 -138
- package/lib/module/index.js.map +0 -1
- package/lib/module/package.json +0 -1
- package/lib/module/specs/NitroSpeech.nitro.js +0 -4
- package/lib/module/specs/NitroSpeech.nitro.js.map +0 -1
- package/lib/tsconfig.tsbuildinfo +0 -1
- package/lib/typescript/index.d.ts +0 -50
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/specs/NitroSpeech.nitro.d.ts +0 -162
- package/lib/typescript/specs/NitroSpeech.nitro.d.ts.map +0 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrospeech/SpeechToTextParams.kt +0 -68
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 George Messier
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -5,39 +5,42 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/@gmessier/nitro-speech)
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
> If you hit an issue, please open a GitHub issue or reach out to me on Discord / Twitter (X) — response is guaranteed.
|
|
8
|
+
> If you hit an issue or want to request a feature, please open a GitHub issue or reach out to me on Discord / Twitter (X) — response is guaranteed.
|
|
9
9
|
>
|
|
10
10
|
> - GitHub Issues: [NotGeorgeMessier/nitro-speech/issues](https://github.com/NotGeorgeMessier/nitro-speech/issues)
|
|
11
11
|
> - Discord: `gmessier`
|
|
12
12
|
> - Twitter (X): `SufferingGeorge`
|
|
13
13
|
|
|
14
|
-
React Native Real-Time Speech Recognition Library, powered by [Nitro Modules](https://github.com/mrousavy/nitro).
|
|
15
|
-
|
|
16
|
-
#### Compatibility:
|
|
17
|
-
‼️ Newest versions of `@gmessier/nitro-speech` requires [react-native-nitro-modules 0.35.0 or higher](https://github.com/mrousavy/nitro/releases/tag/v0.35.0).
|
|
18
|
-
|
|
19
|
-
| Compatibility | Supported versions |
|
|
20
|
-
|---|---|
|
|
21
|
-
| `react-native-nitro-modules <= 0.34.*` | `@gmessier/nitro-speech <= 0.2.*` |
|
|
22
|
-
| `react-native-nitro-modules >= 0.35.*` | `@gmessier/nitro-speech >= 0.3.*` |
|
|
23
|
-
|
|
24
14
|
#### Key Features:
|
|
25
15
|
|
|
26
|
-
- Built
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
- Configurable
|
|
33
|
-
-
|
|
34
|
-
|
|
16
|
+
- ⚡ Built with Nitro Modules for low-overhead native binding
|
|
17
|
+
- 🌎 Supports 60+ languages
|
|
18
|
+
- 🍎 The only library that uses new `SpeechAnalyzer` with `SpeechTranscriber` or `DictationTranscriber` API for iOS 26+ (with fallback to legacy `SFSpeechRecognition` for older versions)
|
|
19
|
+
- ⏱️ Timer for silence
|
|
20
|
+
- Configurable `autoFinishRecognitionMs` value (default: 8 sec)
|
|
21
|
+
- Callback `onAutoFinishProgress` fires periodically with interval
|
|
22
|
+
- Configurable interval `autoFinishProgressIntervalMs` value (default: 1 sec)
|
|
23
|
+
- Method `updateConfig` with `autoFinishRecognitionMs` and `autoFinishProgressIntervalMs`
|
|
24
|
+
allows changing the value on the fly
|
|
25
|
+
- Method `resetAutoFinishTime` resets the Timer to the threshold
|
|
26
|
+
- Method `addAutoFinishTime` adds ms once without changing threshold
|
|
27
|
+
- Configurable volume-based sensitivity `resetAutoFinishVoiceSensitivity` for the timer from 0 to 1
|
|
28
|
+
- 🎤 Rich user voice input management
|
|
29
|
+
- Hook `useVoiceInputVolume()` for `raw` or `smoothed` normalized volume level from 0 to 1 -> easy to use for UI animations;
|
|
30
|
+
And `db` as human-friendly value
|
|
31
|
+
- Flexible callback `onVolumeChange` for custom behavior
|
|
32
|
+
- Static method `getVoiceInputVolume()`
|
|
33
|
+
- 🧩 Lifecycle methods: `prewarm` | `updateConfig` | `getIsActive`
|
|
34
|
+
- 👆 Configurable Haptic Feedback on start and finish
|
|
35
|
+
- 🎚️ Speech-quality configurations:
|
|
35
36
|
- Result is grouped by speech segments into Batches.
|
|
36
|
-
- Param `
|
|
37
|
-
- Param `
|
|
38
|
-
-
|
|
37
|
+
- Param `iosPreset` - `shortForm` or `general` enables best transcriber for your situation
|
|
38
|
+
- Param `disableRepeatingFilter` - filters out consecutive duplicate words.
|
|
39
|
+
- Param `androidDisableBatchHandling` - disables empty partial results
|
|
40
|
+
- Many more, see `SpeechRecognitionConfig`
|
|
41
|
+
- 🔓 Embedded Permission handling
|
|
39
42
|
- Callback `onPermissionDenied` - if user denied the request
|
|
40
|
-
- Everything else that could be found in Expo or other libraries
|
|
43
|
+
- 📦 Everything else that could be found in Expo or other libraries
|
|
41
44
|
|
|
42
45
|
## Table of Contents
|
|
43
46
|
|
|
@@ -48,10 +51,12 @@ React Native Real-Time Speech Recognition Library, powered by [Nitro Modules](ht
|
|
|
48
51
|
- [Recommended: useRecognizer Hook](#recommended-userecognizer-hook)
|
|
49
52
|
- [With React Navigation (important)](#with-react-navigation-important)
|
|
50
53
|
- [Cross-component control: RecognizerRef](#cross-component-control-recognizerref)
|
|
54
|
+
- [Multithreading (react-native-worklets)](#multithreading-react-native-worklets)
|
|
51
55
|
- [Voice input volume](#voice-input-volume)
|
|
52
|
-
- [
|
|
53
|
-
- [
|
|
56
|
+
- [useRecognizerIsActive](#userecognizerisactive)
|
|
57
|
+
- [Unsafe: SpeechRecognizer](#unsafe-speechrecognizer)
|
|
54
58
|
- [Requirements](#requirements)
|
|
59
|
+
- [Compatibility](#compatibility)
|
|
55
60
|
- [Troubleshooting](#troubleshooting)
|
|
56
61
|
|
|
57
62
|
## Installation
|
|
@@ -88,6 +93,7 @@ No additional setup required.
|
|
|
88
93
|
|
|
89
94
|
### Android
|
|
90
95
|
|
|
96
|
+
No actions required.
|
|
91
97
|
The library declares the required permission in its `AndroidManifest.xml` (merged automatically):
|
|
92
98
|
|
|
93
99
|
```xml
|
|
@@ -112,20 +118,31 @@ Both permissions are required for speech recognition to work on iOS.
|
|
|
112
118
|
|
|
113
119
|
| Feature | Description | iOS | Android |
|
|
114
120
|
|---------|-------------|-----|---------|
|
|
115
|
-
| **Real-time transcription** |
|
|
116
|
-
| **
|
|
117
|
-
| **Auto-finish
|
|
118
|
-
| **
|
|
119
|
-
| **
|
|
121
|
+
| **Real-time transcription** | Gets partial results as the user speaks | ✅ | ✅ |
|
|
122
|
+
| **Locale support** | 60+ Supported locales | ✅ | ✅ |
|
|
123
|
+
| **Auto-finish on silence** | Automatically stops recognition after configurable inactivity period | ✅ | ✅ |
|
|
124
|
+
| **Auto-finish progress** | Callback `onAutoFinishProgress` with countdown until auto-stop | ✅ | ✅ |
|
|
125
|
+
| **Add Auto-finish Time** | Adds time to the auto finish timer once without changing the timer threshold | ✅ | ✅ |
|
|
126
|
+
| **Reset Auto-finish Time** | Resets the Timer to the threshold | ✅ | ✅ |
|
|
127
|
+
| **Voice input volume** | `useVoiceInputVolume`, `getVoiceInputVolume()`, `onVolumeChange` | ✅ | ✅ |
|
|
128
|
+
| **Reset Auto-finish Sensitivity** | The voice detector sensitivity to reset the Auto-finish time | ✅ | ✅ |
|
|
129
|
+
| **Prewarm** | Prepares resources, downloads assets, confirms locale availability | ✅ | ✅ |
|
|
130
|
+
| **Update config** | Static method `updateConfig` allows updating the config on the fly | ✅ | ✅ |
|
|
131
|
+
| **Is Active** | Static method `getIsActive()` | ✅ | ✅ |
|
|
132
|
+
| **Haptic feedback** | Haptic feedback on recording start/stop | ✅ | ✅ |
|
|
120
133
|
| **Permission handling** | Dedicated `onPermissionDenied` callback | ✅ | ✅ |
|
|
121
|
-
| **
|
|
134
|
+
| **Background handling** | Stop when app loses focus/goes to background | ✅ | ✅ |
|
|
122
135
|
| **Repeating word filter** | Removes consecutive duplicate words from artifacts | ✅ | ✅ |
|
|
123
|
-
| **
|
|
136
|
+
| **Offensive word masking** | Control whether offensive words are masked with * | iOS 26+ | ✅ |
|
|
124
137
|
| **Contextual strings** | Domain-specific vocabulary for improved accuracy | ✅ | ✅ |
|
|
125
|
-
| **Automatic punctuation** | Adds punctuation to transcription (iOS 16+) | ✅ | Auto |
|
|
126
138
|
| **Language model selection** | Choose between web search vs free-form models | Auto | ✅ |
|
|
127
|
-
| **
|
|
139
|
+
| **Batch handling** | Filters out empty or repeated results | Auto | ✅ |
|
|
128
140
|
| **Formatting quality** | Prefer quality vs speed in formatting | Auto | ✅ |
|
|
141
|
+
| **Transcription preset** | `iosPreset` adapts for short phrases (`shortForm`) or `general` conversation | ✅ | Auto |
|
|
142
|
+
| **Automatic punctuation** | Adds punctuation to transcription (iOS 16+) | ✅ | Auto |
|
|
143
|
+
| **Atypical speech hint** | Hint iOS that speech may include accent, lisp, or other confounding traits | ✅ | Auto |
|
|
144
|
+
| **getSupportedLocalesIOS** | Supported locales for iOS (No available API for Android) | ✅ | X |
|
|
145
|
+
|
|
129
146
|
|
|
130
147
|
## Usage
|
|
131
148
|
|
|
@@ -141,8 +158,12 @@ function MyComponent() {
|
|
|
141
158
|
const {
|
|
142
159
|
startListening,
|
|
143
160
|
stopListening,
|
|
161
|
+
resetAutoFinishTime,
|
|
144
162
|
addAutoFinishTime,
|
|
145
|
-
|
|
163
|
+
updateConfig,
|
|
164
|
+
getSupportedLocalesIOS,
|
|
165
|
+
getIsActive,
|
|
166
|
+
getVoiceInputVolume,
|
|
146
167
|
} = useRecognizer({
|
|
147
168
|
onReadyForSpeech: () => {
|
|
148
169
|
console.log('Listening...');
|
|
@@ -167,18 +188,22 @@ function MyComponent() {
|
|
|
167
188
|
return (
|
|
168
189
|
<View>
|
|
169
190
|
<TouchableOpacity onPress={() => startListening({
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
autoFinishRecognitionMs: 8000,
|
|
173
|
-
|
|
191
|
+
// Universal
|
|
192
|
+
locale: "en-US",
|
|
174
193
|
contextualStrings: ['custom', 'words'],
|
|
175
|
-
|
|
194
|
+
maskOffensiveWords: false,
|
|
195
|
+
// Mutable properties
|
|
196
|
+
autoFinishRecognitionMs: 12000,
|
|
197
|
+
autoFinishProgressIntervalMs: 1000,
|
|
198
|
+
resetAutoFinishVoiceSensitivity: 0.4,
|
|
199
|
+
disableRepeatingFilter: false,
|
|
176
200
|
startHapticFeedbackStyle: 'medium',
|
|
177
201
|
stopHapticFeedbackStyle: 'light',
|
|
178
|
-
// iOS specific
|
|
202
|
+
// iOS specific, non-mutable
|
|
179
203
|
iosAddPunctuation: true,
|
|
180
|
-
|
|
181
|
-
|
|
204
|
+
iosPreset: 'general',
|
|
205
|
+
iosAtypicalSpeech: false,
|
|
206
|
+
// Android specific, non-mutable
|
|
182
207
|
androidFormattingPreferQuality: false,
|
|
183
208
|
androidUseWebSearchModel: false,
|
|
184
209
|
androidDisableBatchHandling: false,
|
|
@@ -191,22 +216,31 @@ function MyComponent() {
|
|
|
191
216
|
<TouchableOpacity onPress={() => addAutoFinishTime(5000)}>
|
|
192
217
|
<Text>Add 5s to Timer</Text>
|
|
193
218
|
</TouchableOpacity>
|
|
194
|
-
<TouchableOpacity onPress={() =>
|
|
195
|
-
<Text>
|
|
219
|
+
<TouchableOpacity onPress={() => resetAutoFinishTime()}>
|
|
220
|
+
<Text>Reset Timer</Text>
|
|
221
|
+
</TouchableOpacity>
|
|
222
|
+
<TouchableOpacity onPress={() => updateConfig(
|
|
223
|
+
{
|
|
224
|
+
autoFinishRecognitionMs: 12000,
|
|
225
|
+
autoFinishProgressIntervalMs: 500,
|
|
226
|
+
resetAutoFinishVoiceSensitivity: 0.65,
|
|
227
|
+
},
|
|
228
|
+
true
|
|
229
|
+
)>
|
|
230
|
+
<Text>Update Timer to 12s, 500ms interval, 0.65 sensitivity, with reset</Text>
|
|
196
231
|
</TouchableOpacity>
|
|
197
232
|
</View>
|
|
198
233
|
);
|
|
199
234
|
}
|
|
200
235
|
```
|
|
201
236
|
|
|
202
|
-
|
|
203
|
-
For other components, avoid creating another `useRecognizer` instance for the same session.
|
|
237
|
+
On iOS 26+, the recognizer prefers the newer `SpeechTranscriber` path for general cases. Setting `iosPreset: 'shortForm'`, `iosAddPunctuation: false`, or `iosAtypicalSpeech: true` switches priority to `DictationTranscriber` that is better suited for short utterances or non-standard speech patterns.
|
|
204
238
|
|
|
205
239
|
### With React Navigation (important)
|
|
206
240
|
|
|
207
241
|
React Navigation **doesn’t unmount screens** when you navigate — the screen can stay mounted in the background and come back without remounting. See: [Navigation lifecycle (React Navigation)](https://reactnavigation.org/docs/8.x/navigation-lifecycle/#summary).
|
|
208
242
|
|
|
209
|
-
Because of that, prefer tying recognition cleanup to **focus state**, not just component unmount. A simple approach is `useIsFocused()` and passing it into `useRecognizer`’s `destroyDeps` so recognition stops when the screen blurs. See: `
|
|
243
|
+
Because of that, prefer tying recognition cleanup to **focus state**, not just component unmount. A simple approach is `useIsFocused()` and passing it into `useRecognizer`’s `destroyDeps` so recognition stops when the screen blurs. See: [`useIsFocused` (React Navigation)](https://reactnavigation.org/docs/8.x/use-is-focused).
|
|
210
244
|
|
|
211
245
|
```typescript
|
|
212
246
|
const isFocused = useIsFocused();
|
|
@@ -229,26 +263,59 @@ import { RecognizerRef } from '@gmessier/nitro-speech';
|
|
|
229
263
|
|
|
230
264
|
RecognizerRef.startListening({ locale: 'en-US' });
|
|
231
265
|
RecognizerRef.addAutoFinishTime(5000);
|
|
232
|
-
RecognizerRef.
|
|
266
|
+
RecognizerRef.resetAutoFinishTime();
|
|
267
|
+
RecognizerRef.updateConfig(
|
|
268
|
+
{
|
|
269
|
+
autoFinishRecognitionMs: 12000,
|
|
270
|
+
autoFinishProgressIntervalMs: 500,
|
|
271
|
+
resetAutoFinishVoiceSensitivity: 0.65,
|
|
272
|
+
},
|
|
273
|
+
true
|
|
274
|
+
);
|
|
233
275
|
RecognizerRef.getIsActive();
|
|
276
|
+
RecognizerRef.getVoiceInputVolume();
|
|
234
277
|
RecognizerRef.stopListening();
|
|
278
|
+
// iOS only
|
|
279
|
+
RecognizerRef.getSupportedLocalesIOS();
|
|
235
280
|
```
|
|
236
281
|
|
|
237
282
|
`RecognizerRef` exposes only method handlers and is safe for cross-component method access.
|
|
238
283
|
|
|
284
|
+
### Multithreading (react-native-worklets)
|
|
285
|
+
All methods are thread-safe and can be called from UI thread or custom worklets
|
|
286
|
+
```typescript
|
|
287
|
+
import { createWorkletRuntime, scheduleOnRuntime } from 'react-native-worklets';
|
|
288
|
+
const workletRuntime = createWorkletRuntime({ name: 'background' });
|
|
289
|
+
|
|
290
|
+
onPress={() => {
|
|
291
|
+
scheduleOnRuntime(workletRuntime, () => {
|
|
292
|
+
// or SpeechRecognizer
|
|
293
|
+
// or just updateConfig from useRecognizer
|
|
294
|
+
RecognizerRef.updateConfig({
|
|
295
|
+
autoFinishRecognitionMs: 10000,
|
|
296
|
+
autoFinishProgressIntervalMs: 200,
|
|
297
|
+
resetAutoFinishVoiceSensitivity: 0.10,
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
}}
|
|
301
|
+
```
|
|
302
|
+
|
|
239
303
|
### Voice input volume
|
|
240
304
|
|
|
241
305
|
#### useVoiceInputVolume
|
|
242
306
|
|
|
243
|
-
|
|
244
|
-
⚠️ **Technical limitation**: this approach re-renders component a lot.
|
|
307
|
+
⚠️ **Technical limitation**: this hook re-renders component a lot.
|
|
245
308
|
|
|
246
309
|
```typescript
|
|
247
310
|
import { useVoiceInputVolume } from '@gmessier/nitro-speech';
|
|
248
311
|
|
|
249
312
|
function VoiceMeter() {
|
|
250
|
-
const
|
|
251
|
-
return
|
|
313
|
+
const volumeEvent = useVoiceInputVolume();
|
|
314
|
+
return <>
|
|
315
|
+
<Text>{volumeEvent.smoothedVolume.toFixed(2)}</Text>
|
|
316
|
+
<Text>{volumeEvent.rawVolume.toFixed(2)}</Text>
|
|
317
|
+
<Text>{volumeEvent.db}</Text>
|
|
318
|
+
</>;
|
|
252
319
|
}
|
|
253
320
|
```
|
|
254
321
|
|
|
@@ -265,9 +332,9 @@ function VoiceMeter() {
|
|
|
265
332
|
} = useRecognizer(
|
|
266
333
|
{
|
|
267
334
|
// ...
|
|
268
|
-
onVolumeChange: (
|
|
335
|
+
onVolumeChange: (volumeEvent) => {
|
|
269
336
|
"worklet";
|
|
270
|
-
sharedVolume.value =
|
|
337
|
+
sharedVolume.value = volumeEvent.smoothedVolume
|
|
271
338
|
},
|
|
272
339
|
// ...
|
|
273
340
|
}
|
|
@@ -275,155 +342,116 @@ function VoiceMeter() {
|
|
|
275
342
|
}
|
|
276
343
|
```
|
|
277
344
|
|
|
345
|
+
### useRecognizerIsActive
|
|
278
346
|
|
|
279
|
-
|
|
347
|
+
```typescript
|
|
348
|
+
import { useRecognizerIsActive } from '@gmessier/nitro-speech';
|
|
280
349
|
|
|
281
|
-
|
|
350
|
+
function MyComponent() {
|
|
351
|
+
const isActive = useRecognizerIsActive();
|
|
352
|
+
return <Text>{isActive ? 'Listening...' : 'Not listening'}</Text>;
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Unsafe: SpeechRecognizer
|
|
357
|
+
|
|
358
|
+
`SpeechRecognizer` is the hybrid object. It gives direct access to callbacks and control methods, but it is unsafe to orchestrate the full session directly from it.
|
|
282
359
|
|
|
283
360
|
```typescript
|
|
284
|
-
import {
|
|
361
|
+
import { SpeechRecognizer, speechRecognizerVolumeChangeHandler } from '@gmessier/nitro-speech';
|
|
285
362
|
|
|
286
363
|
// Set up callbacks
|
|
287
|
-
|
|
364
|
+
SpeechRecognizer.onReadyForSpeech = () => {
|
|
288
365
|
console.log('Listening...');
|
|
289
366
|
};
|
|
290
367
|
|
|
291
|
-
|
|
368
|
+
SpeechRecognizer.onResult = (textBatches) => {
|
|
292
369
|
console.log('Result:', textBatches.join('\n'));
|
|
293
370
|
};
|
|
294
371
|
|
|
295
|
-
|
|
372
|
+
SpeechRecognizer.onRecordingStopped = () => {
|
|
296
373
|
console.log('Stopped');
|
|
297
374
|
};
|
|
298
375
|
|
|
299
|
-
|
|
376
|
+
SpeechRecognizer.onAutoFinishProgress = (timeLeftMs) => {
|
|
300
377
|
console.log('Auto-stop in:', timeLeftMs, 'ms');
|
|
301
378
|
};
|
|
302
379
|
|
|
303
|
-
|
|
380
|
+
SpeechRecognizer.onError = (error) => {
|
|
304
381
|
console.log('Error:', error);
|
|
305
382
|
};
|
|
306
383
|
|
|
307
|
-
|
|
384
|
+
SpeechRecognizer.onPermissionDenied = () => {
|
|
308
385
|
console.log('Permission denied');
|
|
309
386
|
};
|
|
310
387
|
|
|
311
|
-
|
|
388
|
+
SpeechRecognizer.onVolumeChange = (volume) => {
|
|
312
389
|
console.log('new volume: ', volume);
|
|
313
390
|
};
|
|
314
|
-
// OR use
|
|
315
|
-
|
|
391
|
+
// OR use speechRecognizerVolumeChangeHandler to enable useVoiceInputVolume hook manually
|
|
392
|
+
SpeechRecognizer.onVolumeChange = speechRecognizerVolumeChangeHandler
|
|
316
393
|
|
|
317
394
|
|
|
318
395
|
// Start listening
|
|
319
|
-
|
|
396
|
+
SpeechRecognizer.startListening({
|
|
320
397
|
locale: 'en-US',
|
|
321
398
|
});
|
|
322
399
|
|
|
323
400
|
// Stop listening
|
|
324
|
-
|
|
401
|
+
SpeechRecognizer.stopListening();
|
|
325
402
|
|
|
326
403
|
// Manually add time to auto finish timer
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
// Update
|
|
331
|
-
|
|
332
|
-
|
|
404
|
+
SpeechRecognizer.addAutoFinishTime(5000); // Add 5 seconds
|
|
405
|
+
SpeechRecognizer.addAutoFinishTime(); // Reset to original time
|
|
406
|
+
|
|
407
|
+
// Update config
|
|
408
|
+
SpeechRecognizer.updateConfig({
|
|
409
|
+
autoFinishRecognitionMs: 10000,
|
|
410
|
+
autoFinishProgressIntervalMs: 200,
|
|
411
|
+
resetAutoFinishVoiceSensitivity: 0.10,
|
|
412
|
+
}, true); // Set to 10 seconds, 200ms interval, 0.10 sensitivity, with reset
|
|
333
413
|
```
|
|
334
414
|
|
|
335
415
|
### ⚠️ About dispose()
|
|
336
416
|
|
|
337
|
-
The `
|
|
417
|
+
The `SpeechRecognizer.dispose()` method is **NOT SAFE** and should rarely be used. Hybrid Objects in Nitro are typically managed by the JS garbage collector automatically. Only call `dispose()` in performance-critical scenarios where you need to eagerly destroy objects.
|
|
338
418
|
|
|
339
419
|
**See:** [Nitro dispose() documentation](https://nitro.margelo.com/docs/hybrid-objects#dispose)
|
|
340
420
|
|
|
341
|
-
## API Reference
|
|
342
|
-
|
|
343
|
-
### `useRecognizer(callbacks, destroyDeps?)`
|
|
344
|
-
|
|
345
|
-
#### Usage notes
|
|
346
|
-
|
|
347
|
-
- Use `useRecognizer` once per session/screen as the session setup owner.
|
|
348
|
-
- Cleanup stops recognition, so mounting multiple instances can unexpectedly end an active session.
|
|
349
|
-
- For method access in non-owner components, use `RecognizerRef`.
|
|
350
|
-
|
|
351
|
-
#### Parameters
|
|
352
|
-
|
|
353
|
-
- `callbacks` (object):
|
|
354
|
-
- `onReadyForSpeech?: () => void` - Called when speech recognition starts
|
|
355
|
-
- `onResult?: (textBatches: string[]) => void` - Called every time when partial result is ready (array of text batches)
|
|
356
|
-
- `onRecordingStopped?: () => void` - Called when recording stops
|
|
357
|
-
- `onAutoFinishProgress?: (timeLeftMs: number) => void` - Called each second during auto-finish countdown
|
|
358
|
-
- `onError?: (message: string) => void` - Called when an error occurs
|
|
359
|
-
- `onPermissionDenied?: () => void` - Called if microphone permission is denied
|
|
360
|
-
- `destroyDeps` (array, optional) - Additional dependencies for the cleanup effect. When any of these change (or the component unmounts), recognition is stopped.
|
|
361
|
-
|
|
362
|
-
#### Returns
|
|
363
|
-
|
|
364
|
-
- `startListening(params: SpeechToTextParams)` - Start speech recognition with the given parameters
|
|
365
|
-
- `stopListening()` - Stop speech recognition
|
|
366
|
-
- `addAutoFinishTime(additionalTimeMs?: number)` - Add time to the auto-finish timer (or reset to original if no parameter)
|
|
367
|
-
- `updateAutoFinishTime(newTimeMs: number, withRefresh?: boolean)` - Update the auto-finish timer
|
|
368
|
-
- `getIsActive()` - Returns true if the speech recognition is active
|
|
369
|
-
|
|
370
|
-
### `RecognizerRef`
|
|
371
|
-
|
|
372
|
-
- `startListening(params: SpeechToTextParams)`
|
|
373
|
-
- `stopListening()`
|
|
374
|
-
- `addAutoFinishTime(additionalTimeMs?: number)`
|
|
375
|
-
- `updateAutoFinishTime(newTimeMs: number, withRefresh?: boolean)`
|
|
376
|
-
- `getIsActive()`
|
|
377
|
-
|
|
378
|
-
### `useVoiceInputVolume`
|
|
379
|
-
|
|
380
|
-
- `useVoiceInputVolume(): number`
|
|
381
|
-
|
|
382
|
-
### `RecognizerSession`
|
|
383
|
-
|
|
384
|
-
- Exposes callbacks (`onReadyForSpeech`, `onResult`, etc.) and control methods.
|
|
385
|
-
- Prefer `useRecognizer` (single owner) + `RecognizerRef` for app-level usage.
|
|
386
|
-
|
|
387
|
-
### `SpeechToTextParams`
|
|
388
|
-
|
|
389
|
-
Configuration object for speech recognition.
|
|
390
|
-
|
|
391
|
-
#### Common Parameters
|
|
392
|
-
|
|
393
|
-
- `locale?: string` - Language locale (default: `"en-US"`)
|
|
394
|
-
- `autoFinishRecognitionMs?: number` - Auto-stop timeout in milliseconds (default: `8000`)
|
|
395
|
-
- `contextualStrings?: string[]` - Array of domain-specific words for better recognition
|
|
396
|
-
- `disableRepeatingFilter?: boolean` - Disable filter that removes consecutive duplicate words (default: `false`)
|
|
397
|
-
- `startHapticFeedbackStyle?: 'light' | 'medium' | 'heavy' | 'none'` - Haptic feedback style when microphone starts recording (default: `"medium"`)
|
|
398
|
-
- `stopHapticFeedbackStyle?: 'light' | 'medium' | 'heavy' | 'none'` - Haptic feedback style when microphone stops recording (default: `"medium"`)
|
|
399
|
-
- `maskOffensiveWords?: boolean` - Mask offensive words with asterisks. (Android 13+, iOS 26+, default: `false`. iOS <26: always `false`)
|
|
400
|
-
|
|
401
|
-
#### iOS-Specific Parameters
|
|
402
|
-
|
|
403
|
-
- `iosAddPunctuation?: boolean` - Add punctuation to results (iOS 16+, default: `true`)
|
|
404
|
-
|
|
405
|
-
#### Android-Specific Parameters
|
|
406
|
-
|
|
407
|
-
- `androidFormattingPreferQuality?: boolean` - Prefer quality over latency (Android 13+, default: `false`)
|
|
408
|
-
- `androidUseWebSearchModel?: boolean` - Use web search language model instead of free-form (default: `false`)
|
|
409
|
-
- `androidDisableBatchHandling?: boolean` - Disable default batch handling (may add many empty batches, default: `false`)
|
|
410
|
-
|
|
411
421
|
## Requirements
|
|
412
422
|
|
|
413
423
|
- React Native >= 0.76
|
|
414
424
|
- New Arch Only
|
|
415
425
|
- react-native-nitro-modules
|
|
416
426
|
|
|
427
|
+
## Compatibility
|
|
428
|
+
|
|
429
|
+
Latest versions of `@gmessier/nitro-speech` require [react-native-nitro-modules 0.35.0 or higher](https://github.com/mrousavy/nitro/releases/tag/v0.35.0).
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
| Compatibility | Supported versions |
|
|
433
|
+
| -------------------------------------- | --------------------------------- |
|
|
434
|
+
| `react-native-nitro-modules <= 0.34.*` | `@gmessier/nitro-speech <= 0.2.*` |
|
|
435
|
+
| `react-native-nitro-modules >= 0.35.*` | `@gmessier/nitro-speech >= 0.3.*` |
|
|
436
|
+
|
|
417
437
|
## Troubleshooting
|
|
418
438
|
|
|
419
439
|
### Android Gradle sync issues
|
|
420
440
|
|
|
421
|
-
If you're having issues with Android Gradle sync, try running the prebuild for the
|
|
441
|
+
If you're having issues with Android Gradle sync, try running the prebuild for the library that causes the issue:
|
|
442
|
+
|
|
443
|
+
e.g. failed in `react-native-nitro-modules`:
|
|
422
444
|
|
|
423
445
|
```bash
|
|
424
446
|
cd android && ./gradlew :react-native-nitro-modules:preBuild
|
|
425
447
|
```
|
|
426
448
|
|
|
449
|
+
e.g. failed in `react-native-worklets`:
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
cd android && ./gradlew :react-native-worklets:preBuild
|
|
453
|
+
```
|
|
454
|
+
|
|
427
455
|
## License
|
|
428
456
|
|
|
429
457
|
MIT
|
package/android/build.gradle
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
#include <jni.h>
|
|
2
|
+
#include <fbjni/fbjni.h>
|
|
2
3
|
#include "NitroSpeechOnLoad.hpp"
|
|
3
4
|
|
|
4
5
|
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
|
|
5
|
-
return
|
|
6
|
+
return facebook::jni::initialize(vm, []() {
|
|
7
|
+
margelo::nitro::nitrospeech::registerAllNatives();
|
|
8
|
+
});
|
|
6
9
|
}
|
|
10
|
+
|