@iternio/react-native-auto-play 0.4.9 → 0.4.11

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 (163) hide show
  1. package/README.md +0 -26
  2. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlay.kt +89 -0
  3. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/VoiceInputManager.kt +20 -286
  4. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/utils/ThreadUtil.kt +13 -6
  5. package/ios/hybrid/HybridAutoPlay.swift +47 -2
  6. package/ios/utils/VoiceInputManager.swift +40 -144
  7. package/lib/index.d.ts +1 -3
  8. package/lib/index.js +1 -2
  9. package/lib/specs/AutoPlay.nitro.d.ts +29 -0
  10. package/nitro.json +0 -10
  11. package/nitrogen/generated/android/ReactNativeAutoPlay+autolinking.cmake +0 -2
  12. package/nitrogen/generated/android/ReactNativeAutoPlayOnLoad.cpp +0 -18
  13. package/nitrogen/generated/android/c++/JActiveCarUxRestrictions.hpp +8 -8
  14. package/nitrogen/generated/android/c++/JGridTemplateConfig.hpp +16 -16
  15. package/nitrogen/generated/android/c++/JHybridAndroidAutoTelemetrySpec.cpp +4 -4
  16. package/nitrogen/generated/android/c++/JHybridAutoPlaySpec.cpp +47 -4
  17. package/nitrogen/generated/android/c++/JHybridAutoPlaySpec.hpp +4 -0
  18. package/nitrogen/generated/android/c++/JHybridClusterSpec.cpp +4 -4
  19. package/nitrogen/generated/android/c++/JHybridGridTemplateSpec.cpp +4 -4
  20. package/nitrogen/generated/android/c++/JHybridListTemplateSpec.cpp +4 -4
  21. package/nitrogen/generated/android/c++/JHybridMapTemplateSpec.cpp +15 -15
  22. package/nitrogen/generated/android/c++/JInformationTemplateConfig.hpp +16 -16
  23. package/nitrogen/generated/android/c++/JLaneGuidance.hpp +16 -16
  24. package/nitrogen/generated/android/c++/JListTemplateConfig.hpp +16 -16
  25. package/nitrogen/generated/android/c++/JMapTemplateConfig.hpp +16 -16
  26. package/nitrogen/generated/android/c++/JMessageTemplateConfig.hpp +16 -16
  27. package/nitrogen/generated/android/c++/JNitroAttributedString.hpp +8 -8
  28. package/nitrogen/generated/android/c++/JNitroBaseMapTemplateConfig.hpp +16 -16
  29. package/nitrogen/generated/android/c++/JNitroManeuver.cpp +4 -4
  30. package/nitrogen/generated/android/c++/JNitroManeuver.hpp +4 -4
  31. package/nitrogen/generated/android/c++/JNitroRoutingManeuver.hpp +16 -16
  32. package/nitrogen/generated/android/c++/JNitroSection.hpp +8 -8
  33. package/nitrogen/generated/android/c++/JPermissionRequestResult.hpp +16 -16
  34. package/nitrogen/generated/android/c++/JRouteChoice.hpp +32 -32
  35. package/nitrogen/generated/android/c++/JSearchTemplateConfig.hpp +8 -8
  36. package/nitrogen/generated/android/c++/JSignInTemplateConfig.hpp +16 -16
  37. package/nitrogen/generated/android/c++/JTripsConfig.hpp +8 -8
  38. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/ActiveCarUxRestrictions.kt +19 -0
  39. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/AppFocusState.kt +15 -0
  40. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/AssetImage.kt +23 -0
  41. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/AutoText.kt +17 -0
  42. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/BooleanTelemetryItem.kt +15 -0
  43. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Distance.kt +15 -0
  44. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/DurationWithTimeZone.kt +15 -0
  45. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/GlyphImage.kt +21 -0
  46. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/GoogleSignIn.kt +19 -0
  47. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/GoogleSignInAccount.kt +27 -0
  48. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/GridTemplateConfig.kt +33 -0
  49. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlaySpec.kt +17 -0
  50. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/ImageLane.kt +15 -0
  51. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/InformationTemplateConfig.kt +35 -0
  52. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/InputSignIn.kt +27 -0
  53. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/LaneGuidance.kt +15 -0
  54. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/ListTemplateConfig.kt +33 -0
  55. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Location.kt +15 -0
  56. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/MapTemplateConfig.kt +51 -0
  57. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/MessageTemplateConfig.kt +37 -0
  58. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NavigationAlertAction.kt +17 -0
  59. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroAction.kt +27 -0
  60. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroAttributedString.kt +15 -0
  61. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroAttributedStringImage.kt +15 -0
  62. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroBaseMapTemplateConfig.kt +29 -0
  63. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroColor.kt +15 -0
  64. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroGridButton.kt +17 -0
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroImage.kt +18 -8
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroLoadingManeuver.kt +17 -0
  67. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroManeuver.kt +18 -8
  68. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroMapButton.kt +17 -0
  69. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroMessageManeuver.kt +19 -0
  70. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroNavigationAlert.kt +31 -0
  71. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroRoutingManeuver.kt +49 -0
  72. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroRow.kt +27 -0
  73. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NitroSection.kt +17 -0
  74. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/NumericTelemetryItem.kt +15 -0
  75. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/PermissionRequestResult.kt +15 -0
  76. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/PinSignIn.kt +15 -0
  77. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Point.kt +15 -0
  78. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/PreferredImageLane.kt +19 -0
  79. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/QrSignIn.kt +15 -0
  80. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/RemoteImage.kt +17 -0
  81. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/RouteChoice.kt +21 -0
  82. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/SafeAreaInsets.kt +21 -0
  83. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/SearchTemplateConfig.kt +39 -0
  84. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/SignInTemplateConfig.kt +37 -0
  85. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/StringTelemetryItem.kt +15 -0
  86. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Telemetry.kt +35 -0
  87. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/TravelEstimates.kt +19 -0
  88. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/TripConfig.kt +15 -0
  89. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/TripPoint.kt +19 -0
  90. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/TripPreviewTextConfiguration.kt +19 -0
  91. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/TripSelectorCallback.kt +13 -0
  92. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/TripsConfig.kt +15 -0
  93. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Variant_GlyphImage_AssetImage_RemoteImage.kt +18 -8
  94. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Variant_PreferredImageLane_ImageLane.kt +16 -7
  95. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Variant_QrSignIn_PinSignIn_InputSignIn_GoogleSignIn.kt +20 -9
  96. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/VehicleTelemetryItem.kt +19 -0
  97. package/nitrogen/generated/ios/ReactNativeAutoPlay+autolinking.rb +2 -0
  98. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Bridge.cpp +16 -41
  99. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Bridge.hpp +126 -201
  100. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Umbrella.hpp +0 -11
  101. package/nitrogen/generated/ios/ReactNativeAutoPlayAutolinking.mm +0 -8
  102. package/nitrogen/generated/ios/ReactNativeAutoPlayAutolinking.swift +0 -12
  103. package/nitrogen/generated/ios/c++/HybridAutoPlaySpecSwift.hpp +34 -0
  104. package/nitrogen/generated/ios/swift/Func_void_bool.swift +5 -5
  105. package/nitrogen/generated/ios/swift/{Func_void_VoiceInputResult.swift → Func_void_std__shared_ptr_ArrayBuffer_.swift} +10 -10
  106. package/nitrogen/generated/ios/swift/HybridAutoPlaySpec.swift +4 -0
  107. package/nitrogen/generated/ios/swift/HybridAutoPlaySpec_cxx.swift +82 -0
  108. package/nitrogen/generated/ios/swift/NitroImage.swift +13 -0
  109. package/nitrogen/generated/ios/swift/NitroManeuver.swift +13 -0
  110. package/nitrogen/generated/ios/swift/Variant_GlyphImage_AssetImage_RemoteImage.swift +13 -0
  111. package/nitrogen/generated/ios/swift/Variant_PreferredImageLane_ImageLane.swift +12 -0
  112. package/nitrogen/generated/shared/c++/HybridAutoPlaySpec.cpp +4 -0
  113. package/nitrogen/generated/shared/c++/HybridAutoPlaySpec.hpp +5 -0
  114. package/package.json +2 -2
  115. package/src/index.ts +1 -3
  116. package/src/specs/AutoPlay.nitro.ts +37 -0
  117. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridVoice.kt +0 -97
  118. package/ios/hybrid/HybridVoice.swift +0 -65
  119. package/lib/HybridAutoPlay.d.ts +0 -2
  120. package/lib/HybridAutoPlay.js +0 -2
  121. package/lib/components/OnAppearedChildRenderer.d.ts +0 -10
  122. package/lib/components/OnAppearedChildRenderer.js +0 -26
  123. package/lib/hooks/useIsAutoPlayFocused.d.ts +0 -7
  124. package/lib/hooks/useIsAutoPlayFocused.js +0 -20
  125. package/lib/hybrid/HybridVoice.d.ts +0 -52
  126. package/lib/hybrid/HybridVoice.js +0 -52
  127. package/lib/hybrid.d.ts +0 -2
  128. package/lib/hybrid.js +0 -2
  129. package/lib/specs/AutomotivePermissionRequestTemplate.d.ts +0 -11
  130. package/lib/specs/AutomotivePermissionRequestTemplate.js +0 -1
  131. package/lib/specs/AutomotivePermissionRequestTemplate.nitro.d.ts +0 -11
  132. package/lib/specs/AutomotivePermissionRequestTemplate.nitro.js +0 -1
  133. package/lib/specs/Voice.nitro.d.ts +0 -11
  134. package/lib/specs/Voice.nitro.js +0 -1
  135. package/lib/templates/AutomotivePermissionRequestTemplate.d.ts +0 -23
  136. package/lib/templates/AutomotivePermissionRequestTemplate.js +0 -18
  137. package/lib/types/Glyphmap.d.ts +0 -4105
  138. package/lib/types/Glyphmap.js +0 -4105
  139. package/lib/types/Voice.d.ts +0 -16
  140. package/lib/types/Voice.js +0 -1
  141. package/nitrogen/generated/android/c++/JFunc_void_VoiceInputChunk.hpp +0 -81
  142. package/nitrogen/generated/android/c++/JHybridVoiceSpec.cpp +0 -104
  143. package/nitrogen/generated/android/c++/JHybridVoiceSpec.hpp +0 -66
  144. package/nitrogen/generated/android/c++/JVoiceInputChunk.hpp +0 -64
  145. package/nitrogen/generated/android/c++/JVoiceInputResult.hpp +0 -64
  146. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_VoiceInputChunk.kt +0 -80
  147. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridVoiceSpec.kt +0 -72
  148. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/VoiceInputChunk.kt +0 -41
  149. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/VoiceInputResult.kt +0 -41
  150. package/nitrogen/generated/ios/c++/HybridVoiceSpecSwift.cpp +0 -11
  151. package/nitrogen/generated/ios/c++/HybridVoiceSpecSwift.hpp +0 -116
  152. package/nitrogen/generated/ios/swift/Func_void_VoiceInputChunk.swift +0 -46
  153. package/nitrogen/generated/ios/swift/HybridVoiceSpec.swift +0 -58
  154. package/nitrogen/generated/ios/swift/HybridVoiceSpec_cxx.swift +0 -234
  155. package/nitrogen/generated/ios/swift/VoiceInputChunk.swift +0 -60
  156. package/nitrogen/generated/ios/swift/VoiceInputResult.swift +0 -60
  157. package/nitrogen/generated/shared/c++/HybridVoiceSpec.cpp +0 -24
  158. package/nitrogen/generated/shared/c++/HybridVoiceSpec.hpp +0 -73
  159. package/nitrogen/generated/shared/c++/VoiceInputChunk.hpp +0 -89
  160. package/nitrogen/generated/shared/c++/VoiceInputResult.hpp +0 -89
  161. package/src/hybrid/HybridVoice.ts +0 -79
  162. package/src/specs/Voice.nitro.ts +0 -16
  163. package/src/types/Voice.ts +0 -18
@@ -1,47 +1,16 @@
1
1
  import AVFoundation
2
2
  import CarPlay
3
- import NitroModules
4
- import Speech
5
3
 
6
- /// Wraps CheckedContinuation so it can only be resumed once even when
7
- /// shared between a stop() call and an async recognition task callback.
8
- private final class ResultBox: @unchecked Sendable {
9
- private var continuation: CheckedContinuation<VoiceInputResult, Error>?
10
- private let lock = NSLock()
11
-
12
- init(_ continuation: CheckedContinuation<VoiceInputResult, Error>) {
13
- self.continuation = continuation
14
- }
15
-
16
- func resume(returning result: VoiceInputResult) {
17
- lock.lock()
18
- defer { lock.unlock() }
19
- continuation?.resume(returning: result)
20
- continuation = nil
21
- }
22
-
23
- func resume(throwing error: Error) {
24
- lock.lock()
25
- defer { lock.unlock() }
26
- continuation?.resume(throwing: error)
27
- continuation = nil
28
- }
29
- }
30
-
31
- /// Captures audio from the car microphone and buffers raw 16 kHz / 16-bit / mono PCM,
32
- /// or transcribes it via SFSpeechRecognizer when preferSpeechToText is true.
4
+ /// Captures audio from the car microphone and buffers raw 16 kHz / 16-bit / mono PCM.
5
+ /// Recording stops automatically when silence is detected or the max duration is reached.
33
6
  class VoiceInputManager {
34
7
  private var audioEngine: AVAudioEngine?
35
8
  private var voiceControlTemplate: CPVoiceControlTemplate?
36
- private var resultBox: ResultBox?
9
+ private var continuation: CheckedContinuation<[Int16], Error>?
37
10
  private var samples: [Int16] = []
38
11
  private var isStopping = false
39
12
  private let stopLock = NSLock()
40
13
 
41
- // STT
42
- private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest?
43
- private var isSTTMode = false
44
-
45
14
  // Timing
46
15
  private var recordingStart: Date?
47
16
  private var silenceStart: Date?
@@ -64,35 +33,30 @@ class VoiceInputManager {
64
33
  interfaceController: AutoPlayInterfaceController?,
65
34
  silenceThresholdMs: Double,
66
35
  maxDurationMs: Double,
67
- listeningText: String,
68
- preferSpeechToText: Bool,
69
- onChunk: ((_ chunk: VoiceInputChunk) -> Void)?,
70
- language: String?
71
- ) async throws -> VoiceInputResult {
72
- return try await withCheckedThrowingContinuation { cont in
73
- let box = ResultBox(cont)
74
- self.resultBox = box
36
+ listeningText: String
37
+ ) async throws -> Data {
38
+ let samples = try await withCheckedThrowingContinuation {
39
+ (cont: CheckedContinuation<[Int16], Error>) in
40
+ self.continuation = cont
75
41
  self.samples = []
76
42
  self.isStopping = false
77
- self.isSTTMode = preferSpeechToText
78
43
 
79
44
  do {
80
45
  try self.startCapture(
81
46
  interfaceController: interfaceController,
82
47
  silenceThresholdMs: silenceThresholdMs,
83
48
  maxDurationMs: maxDurationMs,
84
- listeningText: listeningText,
85
- preferSpeechToText: preferSpeechToText,
86
- onChunk: onChunk,
87
- box: box,
88
- language: language
49
+ listeningText: listeningText
89
50
  )
90
51
  }
91
52
  catch {
92
- self.cleanup(interfaceController: interfaceController)
93
- box.resume(throwing: error)
53
+ self.stopCapture(interfaceController: interfaceController)
54
+ self.continuation = nil
55
+ cont.resume(throwing: error)
94
56
  }
95
57
  }
58
+
59
+ return samplesAsData(samples)
96
60
  }
97
61
 
98
62
  func stop(interfaceController: AutoPlayInterfaceController? = nil) {
@@ -102,22 +66,14 @@ class VoiceInputManager {
102
66
  return
103
67
  }
104
68
  isStopping = true
105
- let wasSTTMode = isSTTMode
106
- let box = resultBox
69
+ let capturedContinuation = continuation
107
70
  let capturedSamples = samples
108
- resultBox = nil
71
+ continuation = nil
109
72
  samples = []
110
73
  stopLock.unlock()
111
74
 
112
- if wasSTTMode {
113
- // endAudio() causes the recognition task to fire its final result,
114
- // which resumes the box. Engine teardown happens there too.
115
- recognitionRequest?.endAudio()
116
- }
117
- else {
118
- cleanup(interfaceController: interfaceController)
119
- box?.resume(returning: makePCMResult(from: capturedSamples))
120
- }
75
+ stopCapture(interfaceController: interfaceController)
76
+ capturedContinuation?.resume(returning: capturedSamples)
121
77
  }
122
78
 
123
79
  // MARK: - Private
@@ -126,16 +82,13 @@ class VoiceInputManager {
126
82
  interfaceController: AutoPlayInterfaceController?,
127
83
  silenceThresholdMs: Double,
128
84
  maxDurationMs: Double,
129
- listeningText: String,
130
- preferSpeechToText: Bool,
131
- onChunk: ((_ chunk: VoiceInputChunk) -> Void)?,
132
- box: ResultBox,
133
- language: String?
85
+ listeningText: String
134
86
  ) throws {
135
87
  guard AVAudioSession.sharedInstance().recordPermission == .granted else {
136
88
  throw VoiceInputError.microphonePermissionDenied
137
89
  }
138
90
 
91
+ // Activate the session first so inputNode reports the correct hardware format
139
92
  let session = AVAudioSession.sharedInstance()
140
93
  try session.setCategory(.playAndRecord, mode: .measurement, options: [])
141
94
  try session.setActive(true)
@@ -144,59 +97,12 @@ class VoiceInputManager {
144
97
  presentVoiceTemplate(interfaceController: interfaceController, listeningText: listeningText)
145
98
  }
146
99
 
147
- var activeRecognitionRequest: SFSpeechAudioBufferRecognitionRequest? = nil
148
-
149
- if preferSpeechToText, SFSpeechRecognizer.authorizationStatus() == .authorized,
150
- let recognizer = language != nil ? SFSpeechRecognizer(locale: Locale(identifier: language!)) : SFSpeechRecognizer(locale: Locale.current),
151
- recognizer.isAvailable
152
- {
153
- let request = SFSpeechAudioBufferRecognitionRequest()
154
- request.shouldReportPartialResults = true
155
- recognitionRequest = request
156
- activeRecognitionRequest = request
157
-
158
- recognizer.recognitionTask(with: request) { [weak self] result, error in
159
- guard let self else { return }
160
-
161
- if error != nil {
162
- // STT failed — fall back to whatever PCM was accumulated
163
- self.stopLock.lock()
164
- let capturedSamples = self.samples
165
- self.samples = []
166
- self.stopLock.unlock()
167
-
168
- self.cleanup(interfaceController: interfaceController)
169
- box.resume(returning: self.makePCMResult(from: capturedSamples))
170
- return
171
- }
172
-
173
- guard let result else { return }
174
-
175
- if result.isFinal {
176
- self.stopLock.lock()
177
- self.isStopping = true
178
- self.samples = []
179
- self.stopLock.unlock()
180
-
181
- self.cleanup(interfaceController: interfaceController)
182
- box.resume(
183
- returning: VoiceInputResult(
184
- transcription: result.bestTranscription.formattedString,
185
- audio: nil
186
- )
187
- )
188
- }
189
- else {
190
- onChunk?(VoiceInputChunk(partial: result.bestTranscription.formattedString, audio: nil))
191
- }
192
- }
193
- }
194
-
195
100
  let engine = AVAudioEngine()
196
101
  let inputNode = engine.inputNode
197
102
  let nativeFormat = inputNode.outputFormat(forBus: 0)
198
103
 
199
- guard let converter = AVAudioConverter(from: nativeFormat, to: VoiceInputManager.targetFormat) else {
104
+ let targetFormat = VoiceInputManager.targetFormat
105
+ guard let converter = AVAudioConverter(from: nativeFormat, to: targetFormat) else {
200
106
  throw VoiceInputError.converterUnavailable
201
107
  }
202
108
 
@@ -210,43 +116,36 @@ class VoiceInputManager {
210
116
  ) { [weak self] buffer, _ in
211
117
  guard let self, !self.isStopping else { return }
212
118
 
213
- // Feed STT if active
214
- activeRecognitionRequest?.append(buffer)
215
-
216
- // Convert to 16kHz int16 for accumulation and PCM chunks
217
119
  let outputFrameCapacity = AVAudioFrameCount(
218
- Double(buffer.frameLength) * VoiceInputManager.sampleRate / nativeFormat.sampleRate
120
+ Double(buffer.frameLength)
121
+ * VoiceInputManager.sampleRate
122
+ / nativeFormat.sampleRate
219
123
  )
124
+
220
125
  guard
221
126
  let outputBuffer = AVAudioPCMBuffer(
222
- pcmFormat: VoiceInputManager.targetFormat,
127
+ pcmFormat: targetFormat,
223
128
  frameCapacity: outputFrameCapacity
224
129
  )
225
130
  else { return }
226
131
 
227
132
  var conversionError: NSError?
228
- let status = converter.convert(to: outputBuffer, error: &conversionError) { _, outStatus in
133
+ let status = converter.convert(to: outputBuffer, error: &conversionError) {
134
+ _,
135
+ outStatus in
229
136
  outStatus.pointee = .haveData
230
137
  return buffer
231
138
  }
139
+
232
140
  guard status != .error, let int16Data = outputBuffer.int16ChannelData else { return }
233
141
 
234
142
  let frameCount = Int(outputBuffer.frameLength)
235
143
  let newSamples = Array(UnsafeBufferPointer(start: int16Data[0], count: frameCount))
236
144
  self.samples.append(contentsOf: newSamples)
237
145
 
238
- // PCM chunk callback
239
- if activeRecognitionRequest == nil, let onChunk {
240
- if let chunkBuffer = try? ArrayBuffer.copy(
241
- data: newSamples.withUnsafeBufferPointer { Data(buffer: $0) }
242
- ) {
243
- onChunk(VoiceInputChunk(partial: nil, audio: chunkBuffer))
244
- }
245
- }
246
-
247
146
  let now = Date()
248
147
 
249
- // Max duration — applies in both modes
148
+ // Max duration check
250
149
  if let start = self.recordingStart,
251
150
  now.timeIntervalSince(start) * 1000 >= maxDurationMs
252
151
  {
@@ -261,9 +160,7 @@ class VoiceInputManager {
261
160
  {
262
161
  let peak = newSamples.reduce(0) { max($0, abs(Int($1))) }
263
162
  if peak < VoiceInputManager.silenceAmplitudeThreshold {
264
- if self.silenceStart == nil {
265
- self.silenceStart = now
266
- }
163
+ if self.silenceStart == nil { self.silenceStart = now }
267
164
  if let silenceBegin = self.silenceStart,
268
165
  now.timeIntervalSince(silenceBegin) * 1000 >= silenceThresholdMs
269
166
  {
@@ -286,11 +183,10 @@ class VoiceInputManager {
286
183
  }
287
184
  }
288
185
 
289
- private func cleanup(interfaceController: AutoPlayInterfaceController?) {
186
+ private func stopCapture(interfaceController: AutoPlayInterfaceController?) {
290
187
  audioEngine?.inputNode.removeTap(onBus: 0)
291
188
  audioEngine?.stop()
292
189
  audioEngine = nil
293
- recognitionRequest = nil
294
190
  recordingStart = nil
295
191
  silenceStart = nil
296
192
  try? AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
@@ -299,12 +195,6 @@ class VoiceInputManager {
299
195
  }
300
196
  }
301
197
 
302
- private func makePCMResult(from samples: [Int16]) -> VoiceInputResult {
303
- let data = samples.withUnsafeBufferPointer { Data(buffer: $0) }
304
- let buffer = try? ArrayBuffer.copy(data: data)
305
- return VoiceInputResult(transcription: nil, audio: buffer)
306
- }
307
-
308
198
  private func presentVoiceTemplate(interfaceController: AutoPlayInterfaceController, listeningText: String) {
309
199
  let listeningState = CPVoiceControlState(
310
200
  identifier: "listening",
@@ -328,6 +218,12 @@ class VoiceInputManager {
328
218
  }
329
219
  voiceControlTemplate = nil
330
220
  }
221
+
222
+ private func samplesAsData(_ samples: [Int16]) -> Data {
223
+ samples.withUnsafeBufferPointer { ptr in
224
+ Data(buffer: ptr)
225
+ }
226
+ }
331
227
  }
332
228
 
333
229
  enum VoiceInputError: Error {
package/lib/index.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { HybridAndroidAutoTelemetry } from './hybrid/HybridAndroidAutoTelemetry';
2
2
  import { HybridAutoPlay } from './hybrid/HybridAutoPlay';
3
- import { HybridVoice } from './hybrid/HybridVoice';
4
3
  import type { AndroidAutomotive } from './specs/AndroidAutomotive.nitro';
5
- export { HybridAndroidAutoTelemetry, HybridAutoPlay, HybridVoice };
4
+ export { HybridAndroidAutoTelemetry, HybridAutoPlay };
6
5
  export declare const HybridAndroidAutomotive: AndroidAutomotive | null;
7
6
  /**
8
7
  * These are the static module names for the app running on the mobile device, head unit screen and the CarPlay dashboard.
@@ -40,7 +39,6 @@ export * from './types/SignInMethod';
40
39
  export * from './types/Telemetry';
41
40
  export * from './types/Text';
42
41
  export * from './types/Trip';
43
- export type { VoiceInputChunk, VoiceInputOptions, VoiceInputResult } from './types/Voice';
44
42
  export type { AlertPriority, NavigationAlert as Alert, NavigationAlertAction as AlertAction, } from './utils/NitroAlert';
45
43
  export type { ThemedColor } from './utils/NitroColor';
46
44
  export type { GridButton } from './utils/NitroGrid';
package/lib/index.js CHANGED
@@ -3,9 +3,8 @@ import { NitroModules } from 'react-native-nitro-modules';
3
3
  import AutoPlayHeadlessJsTask from './AutoPlayHeadlessJsTask';
4
4
  import { HybridAndroidAutoTelemetry } from './hybrid/HybridAndroidAutoTelemetry';
5
5
  import { HybridAutoPlay } from './hybrid/HybridAutoPlay';
6
- import { HybridVoice } from './hybrid/HybridVoice';
7
6
  AutoPlayHeadlessJsTask.registerHeadlessTask(HybridAutoPlay);
8
- export { HybridAndroidAutoTelemetry, HybridAutoPlay, HybridVoice };
7
+ export { HybridAndroidAutoTelemetry, HybridAutoPlay };
9
8
  export const HybridAndroidAutomotive = Platform.OS === 'android'
10
9
  ? NitroModules.createHybridObject('AndroidAutomotive')
11
10
  : null;
@@ -31,6 +31,35 @@ export interface AutoPlay extends HybridObject<{
31
31
  * @namespace Android
32
32
  */
33
33
  addListenerVoiceInput(callback: (coordinates: Location | undefined, query: string | undefined) => void): CleanupCallback;
34
+ /**
35
+ * Returns true if microphone permission has already been granted.
36
+ */
37
+ hasVoiceInputPermission(): boolean;
38
+ /**
39
+ * Request microphone permission from the user.
40
+ * On Android: uses the car context when Android Auto is connected, otherwise
41
+ * falls back to the React Native application context.
42
+ * On iOS: uses AVAudioApplication (iOS 17+) or AVAudioSession (iOS 15–16).
43
+ * Returns true if permission was granted, false if denied.
44
+ */
45
+ requestVoiceInputPermission(): Promise<boolean>;
46
+ /**
47
+ * Start an in-app voice recording session.
48
+ * On Android: acquires audio focus and captures via CarAudioRecord when
49
+ * Android Auto is connected, otherwise uses standard AudioRecord.
50
+ * On iOS: presents CPVoiceControlTemplate (when a car is connected) and
51
+ * captures audio via AVAudioEngine.
52
+ * Resolves with the complete raw PCM buffer (16 kHz, 16-bit, mono) when
53
+ * silence is detected, the max duration is reached, or stopVoiceInput() is called.
54
+ * Rejects if microphone permission has not been granted or recording fails to start.
55
+ */
56
+ startVoiceInput(silenceThresholdMs?: number, maxDurationMs?: number, listeningText?: string): Promise<ArrayBuffer>;
57
+ /**
58
+ * Stop the active voice recording session early. Causes the Promise returned
59
+ * by startVoiceInput() to resolve with the audio captured so far.
60
+ * No-op if no recording is in progress.
61
+ */
62
+ stopVoiceInput(): void;
34
63
  /**
35
64
  * sets the specified template as root template, initializes a new stack
36
65
  * Promise might contain an error message in case setting root template failed
package/nitro.json CHANGED
@@ -9,16 +9,6 @@
9
9
  "androidCxxLibName": "ReactNativeAutoPlay"
10
10
  },
11
11
  "autolinking": {
12
- "Voice": {
13
- "android": {
14
- "implementationClassName": "HybridVoice",
15
- "language": "kotlin"
16
- },
17
- "ios": {
18
- "implementationClassName": "HybridVoice",
19
- "language": "swift"
20
- }
21
- },
22
12
  "AutoPlay": {
23
13
  "android": {
24
14
  "implementationClassName": "HybridAutoPlay",
@@ -45,7 +45,6 @@ target_sources(
45
45
  ../nitrogen/generated/shared/c++/HybridMessageTemplateSpec.cpp
46
46
  ../nitrogen/generated/shared/c++/HybridSearchTemplateSpec.cpp
47
47
  ../nitrogen/generated/shared/c++/HybridSignInTemplateSpec.cpp
48
- ../nitrogen/generated/shared/c++/HybridVoiceSpec.cpp
49
48
  # Android-specific Nitrogen C++ sources
50
49
  ../nitrogen/generated/android/c++/JHybridAndroidAutomotiveSpec.cpp
51
50
  ../nitrogen/generated/android/c++/JHybridAndroidAutoTelemetrySpec.cpp
@@ -63,7 +62,6 @@ target_sources(
63
62
  ../nitrogen/generated/android/c++/JHybridSearchTemplateSpec.cpp
64
63
  ../nitrogen/generated/android/c++/JHybridSignInTemplateSpec.cpp
65
64
  ../nitrogen/generated/android/c++/JVariant_QrSignIn_PinSignIn_InputSignIn_GoogleSignIn.cpp
66
- ../nitrogen/generated/android/c++/JHybridVoiceSpec.cpp
67
65
  )
68
66
 
69
67
  # From node_modules/react-native/ReactAndroid/cmake-utils/folly-flags.cmake
@@ -46,8 +46,6 @@
46
46
  #include "JHybridSearchTemplateSpec.hpp"
47
47
  #include "JHybridSignInTemplateSpec.hpp"
48
48
  #include "JFunc_void_std__optional_std__string__std__optional_GoogleSignInAccount_.hpp"
49
- #include "JHybridVoiceSpec.hpp"
50
- #include "JFunc_void_VoiceInputChunk.hpp"
51
49
  #include <NitroModules/DefaultConstructableObject.hpp>
52
50
 
53
51
  namespace margelo::nitro::swe::iternio::reactnativeautoplay {
@@ -58,14 +56,6 @@ int initialize(JavaVM* vm) {
58
56
  });
59
57
  }
60
58
 
61
- struct JHybridVoiceSpecImpl: public jni::JavaClass<JHybridVoiceSpecImpl, JHybridVoiceSpec::JavaPart> {
62
- static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/swe/iternio/reactnativeautoplay/HybridVoice;";
63
- static std::shared_ptr<JHybridVoiceSpec> create() {
64
- static const auto constructorFn = javaClassStatic()->getConstructor<JHybridVoiceSpecImpl::javaobject()>();
65
- jni::local_ref<JHybridVoiceSpec::JavaPart> javaPart = javaClassStatic()->newObject(constructorFn);
66
- return javaPart->getJHybridVoiceSpec();
67
- }
68
- };
69
59
  struct JHybridAutoPlaySpecImpl: public jni::JavaClass<JHybridAutoPlaySpecImpl, JHybridAutoPlaySpec::JavaPart> {
70
60
  static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlay;";
71
61
  static std::shared_ptr<JHybridAutoPlaySpec> create() {
@@ -191,16 +181,8 @@ void registerAllNatives() {
191
181
  margelo::nitro::swe::iternio::reactnativeautoplay::JHybridSearchTemplateSpec::CxxPart::registerNatives();
192
182
  margelo::nitro::swe::iternio::reactnativeautoplay::JHybridSignInTemplateSpec::CxxPart::registerNatives();
193
183
  margelo::nitro::swe::iternio::reactnativeautoplay::JFunc_void_std__optional_std__string__std__optional_GoogleSignInAccount__cxx::registerNatives();
194
- margelo::nitro::swe::iternio::reactnativeautoplay::JHybridVoiceSpec::CxxPart::registerNatives();
195
- margelo::nitro::swe::iternio::reactnativeautoplay::JFunc_void_VoiceInputChunk_cxx::registerNatives();
196
184
 
197
185
  // Register Nitro Hybrid Objects
198
- HybridObjectRegistry::registerHybridObjectConstructor(
199
- "Voice",
200
- []() -> std::shared_ptr<HybridObject> {
201
- return JHybridVoiceSpecImpl::create();
202
- }
203
- );
204
186
  HybridObjectRegistry::registerHybridObjectConstructor(
205
187
  "AutoPlay",
206
188
  []() -> std::shared_ptr<HybridObject> {
@@ -45,16 +45,16 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay {
45
45
  maxContentDepth,
46
46
  maxCumulativeContentItems,
47
47
  maxRestrictedStringLength,
48
- [&]() {
49
- size_t __size = activeRestrictions->size();
48
+ [&](auto&& __input) {
49
+ size_t __size = __input->size();
50
50
  std::vector<CarUxRestrictions> __vector;
51
51
  __vector.reserve(__size);
52
52
  for (size_t __i = 0; __i < __size; __i++) {
53
- auto __element = activeRestrictions->getElement(__i);
53
+ auto __element = __input->getElement(__i);
54
54
  __vector.push_back(__element->toCpp());
55
55
  }
56
56
  return __vector;
57
- }()
57
+ }(activeRestrictions)
58
58
  );
59
59
  }
60
60
 
@@ -72,16 +72,16 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay {
72
72
  value.maxContentDepth,
73
73
  value.maxCumulativeContentItems,
74
74
  value.maxRestrictedStringLength,
75
- [&]() {
76
- size_t __size = value.activeRestrictions.size();
75
+ [&](auto&& __input) {
76
+ size_t __size = __input.size();
77
77
  jni::local_ref<jni::JArrayClass<JCarUxRestrictions>> __array = jni::JArrayClass<JCarUxRestrictions>::newArray(__size);
78
78
  for (size_t __i = 0; __i < __size; __i++) {
79
- const auto& __element = value.activeRestrictions[__i];
79
+ const auto& __element = __input[__i];
80
80
  auto __elementJni = JCarUxRestrictions::fromCpp(__element);
81
81
  __array->setElement(__i, *__elementJni);
82
82
  }
83
83
  return __array;
84
- }()
84
+ }(value.activeRestrictions)
85
85
  );
86
86
  }
87
87
  };
@@ -141,27 +141,27 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay {
141
141
  }
142
142
  }()) : std::nullopt,
143
143
  autoDismissMs != nullptr ? std::make_optional(autoDismissMs->value()) : std::nullopt,
144
- headerActions != nullptr ? std::make_optional([&]() {
145
- size_t __size = headerActions->size();
144
+ headerActions != nullptr ? std::make_optional([&](auto&& __input) {
145
+ size_t __size = __input->size();
146
146
  std::vector<NitroAction> __vector;
147
147
  __vector.reserve(__size);
148
148
  for (size_t __i = 0; __i < __size; __i++) {
149
- auto __element = headerActions->getElement(__i);
149
+ auto __element = __input->getElement(__i);
150
150
  __vector.push_back(__element->toCpp());
151
151
  }
152
152
  return __vector;
153
- }()) : std::nullopt,
153
+ }(headerActions)) : std::nullopt,
154
154
  title->toCpp(),
155
- [&]() {
156
- size_t __size = buttons->size();
155
+ [&](auto&& __input) {
156
+ size_t __size = __input->size();
157
157
  std::vector<NitroGridButton> __vector;
158
158
  __vector.reserve(__size);
159
159
  for (size_t __i = 0; __i < __size; __i++) {
160
- auto __element = buttons->getElement(__i);
160
+ auto __element = __input->getElement(__i);
161
161
  __vector.push_back(__element->toCpp());
162
162
  }
163
163
  return __vector;
164
- }(),
164
+ }(buttons),
165
165
  mapConfig != nullptr ? std::make_optional(mapConfig->toCpp()) : std::nullopt
166
166
  );
167
167
  }
@@ -184,27 +184,27 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay {
184
184
  value.onDidDisappear.has_value() ? JFunc_void_std__optional_bool__cxx::fromCpp(value.onDidDisappear.value()) : nullptr,
185
185
  value.onPopped.has_value() ? JFunc_void_cxx::fromCpp(value.onPopped.value()) : nullptr,
186
186
  value.autoDismissMs.has_value() ? jni::JDouble::valueOf(value.autoDismissMs.value()) : nullptr,
187
- value.headerActions.has_value() ? [&]() {
188
- size_t __size = value.headerActions.value().size();
187
+ value.headerActions.has_value() ? [&](auto&& __input) {
188
+ size_t __size = __input.size();
189
189
  jni::local_ref<jni::JArrayClass<JNitroAction>> __array = jni::JArrayClass<JNitroAction>::newArray(__size);
190
190
  for (size_t __i = 0; __i < __size; __i++) {
191
- const auto& __element = value.headerActions.value()[__i];
191
+ const auto& __element = __input[__i];
192
192
  auto __elementJni = JNitroAction::fromCpp(__element);
193
193
  __array->setElement(__i, *__elementJni);
194
194
  }
195
195
  return __array;
196
- }() : nullptr,
196
+ }(value.headerActions.value()) : nullptr,
197
197
  JAutoText::fromCpp(value.title),
198
- [&]() {
199
- size_t __size = value.buttons.size();
198
+ [&](auto&& __input) {
199
+ size_t __size = __input.size();
200
200
  jni::local_ref<jni::JArrayClass<JNitroGridButton>> __array = jni::JArrayClass<JNitroGridButton>::newArray(__size);
201
201
  for (size_t __i = 0; __i < __size; __i++) {
202
- const auto& __element = value.buttons[__i];
202
+ const auto& __element = __input[__i];
203
203
  auto __elementJni = JNitroGridButton::fromCpp(__element);
204
204
  __array->setElement(__i, *__elementJni);
205
205
  }
206
206
  return __array;
207
- }(),
207
+ }(value.buttons),
208
208
  value.mapConfig.has_value() ? JNitroBaseMapTemplateConfig::fromCpp(value.mapConfig.value()) : nullptr
209
209
  );
210
210
  }
@@ -90,16 +90,16 @@ namespace margelo::nitro::swe::iternio::reactnativeautoplay {
90
90
  }
91
91
  std::shared_ptr<Promise<PermissionRequestResult>> JHybridAndroidAutoTelemetrySpec::requestAutomotivePermissions(const std::vector<std::string>& permissions, const std::string& message, const std::string& grantButtonText, const std::optional<std::string>& cancelButtonText) {
92
92
  static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>(jni::alias_ref<jni::JArrayClass<jni::JString>> /* permissions */, jni::alias_ref<jni::JString> /* message */, jni::alias_ref<jni::JString> /* grantButtonText */, jni::alias_ref<jni::JString> /* cancelButtonText */)>("requestAutomotivePermissions");
93
- auto __result = method(_javaPart, [&]() {
94
- size_t __size = permissions.size();
93
+ auto __result = method(_javaPart, [&](auto&& __input) {
94
+ size_t __size = __input.size();
95
95
  jni::local_ref<jni::JArrayClass<jni::JString>> __array = jni::JArrayClass<jni::JString>::newArray(__size);
96
96
  for (size_t __i = 0; __i < __size; __i++) {
97
- const auto& __element = permissions[__i];
97
+ const auto& __element = __input[__i];
98
98
  auto __elementJni = jni::make_jstring(__element);
99
99
  __array->setElement(__i, *__elementJni);
100
100
  }
101
101
  return __array;
102
- }(), jni::make_jstring(message), jni::make_jstring(grantButtonText), cancelButtonText.has_value() ? jni::make_jstring(cancelButtonText.value()) : nullptr);
102
+ }(permissions), jni::make_jstring(message), jni::make_jstring(grantButtonText), cancelButtonText.has_value() ? jni::make_jstring(cancelButtonText.value()) : nullptr);
103
103
  return [&]() {
104
104
  auto __promise = Promise<PermissionRequestResult>::create();
105
105
  __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {