@glassly/bluetooth-sdk 0.1.0-dev.26

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 (548) hide show
  1. package/README.md +563 -0
  2. package/android/build.gradle +450 -0
  3. package/android/gradle.properties.example +9 -0
  4. package/android/lc3Lib/CMakeLists.txt +6 -0
  5. package/android/lc3Lib/build.gradle +212 -0
  6. package/android/lc3Lib/proguard-rules.pro +33 -0
  7. package/android/lc3Lib/src/main/AndroidManifest.xml +2 -0
  8. package/android/lc3Lib/src/main/cpp/CMakeLists.txt +8 -0
  9. package/android/lc3Lib/src/main/cpp/google_opus_stuff/CMakeLists.txt +30 -0
  10. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/CMakeLists.txt +7 -0
  11. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.cc +96 -0
  12. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.h +53 -0
  13. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/Makefile.am +6 -0
  14. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h +26 -0
  15. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h.in +26 -0
  16. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/ogg.h +209 -0
  17. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/os_types.h +158 -0
  18. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus.h +981 -0
  19. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_custom.h +342 -0
  20. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_defines.h +799 -0
  21. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_multistream.h +660 -0
  22. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_projection.h +568 -0
  23. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_types.h +166 -0
  24. package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.cc +268 -0
  25. package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.h +115 -0
  26. package/android/lc3Lib/src/main/cpp/google_opus_stuff/opus_tools/opus_header.h +59 -0
  27. package/android/lc3Lib/src/main/cpp/liblc3/CMakeLists.txt +38 -0
  28. package/android/lc3Lib/src/main/cpp/liblc3/include/lc3.h +309 -0
  29. package/android/lc3Lib/src/main/cpp/liblc3/include/lc3_private.h +162 -0
  30. package/android/lc3Lib/src/main/cpp/liblc3/include/rnnoise.h +114 -0
  31. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/CMakeLists.txt +19 -0
  32. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.c +92 -0
  33. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.h +44 -0
  34. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.c +375 -0
  35. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.h +315 -0
  36. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.c +129 -0
  37. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.h +69 -0
  38. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/common.h +148 -0
  39. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.c +70 -0
  40. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.h +43 -0
  41. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/fastmath.h +158 -0
  42. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/lc3.c +702 -0
  43. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.c +893 -0
  44. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.h +111 -0
  45. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_arm.h +506 -0
  46. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_neon.h +281 -0
  47. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/makefile.mk +35 -0
  48. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.c +452 -0
  49. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.h +57 -0
  50. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct_neon.h +296 -0
  51. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/meson.build +46 -0
  52. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.c +61 -0
  53. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.h +57 -0
  54. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.c +880 -0
  55. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.h +103 -0
  56. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.c +904 -0
  57. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.h +119 -0
  58. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.c +3457 -0
  59. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.h +94 -0
  60. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.c +457 -0
  61. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.h +99 -0
  62. package/android/lc3Lib/src/main/cpp/liblc3/liblc3.cpp +159 -0
  63. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/_kiss_fft_guts.h +182 -0
  64. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/arch.h +261 -0
  65. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.c +279 -0
  66. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.h +59 -0
  67. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/common.h +48 -0
  68. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/compile.sh +3 -0
  69. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/denoise.c +646 -0
  70. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.c +601 -0
  71. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.h +203 -0
  72. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/opus_types.h +159 -0
  73. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.c +526 -0
  74. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.h +149 -0
  75. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.c +178 -0
  76. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.h +69 -0
  77. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.c +11051 -0
  78. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.h +34 -0
  79. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_reader.c +168 -0
  80. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_train.py +66 -0
  81. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/tansig_table.h +45 -0
  82. package/android/lc3Lib/src/main/java/com/glassly/lc3Lib/Lc3Cpp.java +38 -0
  83. package/android/lc3Lib/third_party/CMakeLists.txt +23 -0
  84. package/android/lc3Lib/third_party/CMakeLists_libogg.txt +18 -0
  85. package/android/lc3Lib/third_party/CMakeLists_libopus.txt +18 -0
  86. package/android/lc3Lib/third_party/CMakeLists_opus-tools.txt +23 -0
  87. package/android/lc3Lib/third_party/opus_tools/src/AUTHORS +5 -0
  88. package/android/lc3Lib/third_party/opus_tools/src/CMakeLists.txt +4 -0
  89. package/android/lc3Lib/third_party/opus_tools/src/COPYING +371 -0
  90. package/android/lc3Lib/third_party/opus_tools/src/ChangeLog +3 -0
  91. package/android/lc3Lib/third_party/opus_tools/src/Makefile.am +42 -0
  92. package/android/lc3Lib/third_party/opus_tools/src/Makefile.unix +23 -0
  93. package/android/lc3Lib/third_party/opus_tools/src/NEWS +0 -0
  94. package/android/lc3Lib/third_party/opus_tools/src/README +0 -0
  95. package/android/lc3Lib/third_party/opus_tools/src/autogen.sh +115 -0
  96. package/android/lc3Lib/third_party/opus_tools/src/configure.ac +293 -0
  97. package/android/lc3Lib/third_party/opus_tools/src/src/arch.h +239 -0
  98. package/android/lc3Lib/third_party/opus_tools/src/src/audio-in.c +1046 -0
  99. package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.c +245 -0
  100. package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.h +28 -0
  101. package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.c +320 -0
  102. package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.h +51 -0
  103. package/android/lc3Lib/third_party/opus_tools/src/src/lpc.c +157 -0
  104. package/android/lc3Lib/third_party/opus_tools/src/src/lpc.h +27 -0
  105. package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.c +286 -0
  106. package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.h +59 -0
  107. package/android/lc3Lib/third_party/opus_tools/src/src/opusdec.c +884 -0
  108. package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.c +1021 -0
  109. package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.h +101 -0
  110. package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.c +639 -0
  111. package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.h +51 -0
  112. package/android/lc3Lib/third_party/opus_tools/src/src/os_support.h +167 -0
  113. package/android/lc3Lib/third_party/opus_tools/src/src/resample.c +1137 -0
  114. package/android/lc3Lib/third_party/opus_tools/src/src/speex_resampler.h +344 -0
  115. package/android/lc3Lib/third_party/opus_tools/src/src/stack_alloc.h +115 -0
  116. package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.c +125 -0
  117. package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.h +62 -0
  118. package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.c +223 -0
  119. package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.h +60 -0
  120. package/android/settings.gradle +4 -0
  121. package/android/silero/LICENSE.md +17 -0
  122. package/android/silero/build.gradle +50 -0
  123. package/android/silero/proguard-rules.pro +24 -0
  124. package/android/silero/src/androidTest/assets/hello.wav +0 -0
  125. package/android/silero/src/androidTest/java/com/konovalov/vad/silero/VadSileroTest.kt +79 -0
  126. package/android/silero/src/main/assets/LICENSE +21 -0
  127. package/android/silero/src/main/assets/silero_vad.onnx +0 -0
  128. package/android/silero/src/main/java/com/konovalov/vad/silero/Vad.kt +160 -0
  129. package/android/silero/src/main/java/com/konovalov/vad/silero/VadSilero.kt +449 -0
  130. package/android/silero/src/main/java/com/konovalov/vad/silero/config/FrameSize.kt +15 -0
  131. package/android/silero/src/main/java/com/konovalov/vad/silero/config/Mode.kt +14 -0
  132. package/android/silero/src/main/java/com/konovalov/vad/silero/config/SampleRate.kt +12 -0
  133. package/android/silero/src/main/java/com/konovalov/vad/silero/utils/AudioUtils.kt +47 -0
  134. package/android/silero/src/main/java/com/konovalov/vad/silero/utils/TensorMap.kt +41 -0
  135. package/android/silero/src/test/java/com/konovalov/vad/silero/utils/AudioUtilsTest.kt +44 -0
  136. package/android/src/main/AndroidManifest.xml +42 -0
  137. package/android/src/main/assets/G2Firmware/README.md +11 -0
  138. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdk.kt +2325 -0
  139. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkAnalytics.kt +216 -0
  140. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkDebug.kt +14 -0
  141. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkDefaults.kt +7 -0
  142. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkModule.kt +1088 -0
  143. package/android/src/main/java/com/glassly/bluetoothsdk/Bridge.kt +953 -0
  144. package/android/src/main/java/com/glassly/bluetoothsdk/DeviceManager.kt +2528 -0
  145. package/android/src/main/java/com/glassly/bluetoothsdk/DeviceStore.kt +360 -0
  146. package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedChangelogCatalog.kt +8 -0
  147. package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedReleaseMetadata.kt +11 -0
  148. package/android/src/main/java/com/glassly/bluetoothsdk/LocalNetworkModule.kt +414 -0
  149. package/android/src/main/java/com/glassly/bluetoothsdk/ObservableStore.kt +88 -0
  150. package/android/src/main/java/com/glassly/bluetoothsdk/OtaManifest.kt +191 -0
  151. package/android/src/main/java/com/glassly/bluetoothsdk/ReleaseChangelog.kt +61 -0
  152. package/android/src/main/java/com/glassly/bluetoothsdk/ScopedNetworkReadiness.kt +17 -0
  153. package/android/src/main/java/com/glassly/bluetoothsdk/audio/AudioModels.kt +144 -0
  154. package/android/src/main/java/com/glassly/bluetoothsdk/camera/CameraModels.kt +486 -0
  155. package/android/src/main/java/com/glassly/bluetoothsdk/connection/ConnectionModels.kt +78 -0
  156. package/android/src/main/java/com/glassly/bluetoothsdk/controllers/ControllerManager.kt +158 -0
  157. package/android/src/main/java/com/glassly/bluetoothsdk/controllers/R1.kt +937 -0
  158. package/android/src/main/java/com/glassly/bluetoothsdk/debug/BleTraceLogger.kt +165 -0
  159. package/android/src/main/java/com/glassly/bluetoothsdk/events/BluetoothEvents.kt +178 -0
  160. package/android/src/main/java/com/glassly/bluetoothsdk/internal/MapParsing.kt +140 -0
  161. package/android/src/main/java/com/glassly/bluetoothsdk/net/LocalIpv4.kt +57 -0
  162. package/android/src/main/java/com/glassly/bluetoothsdk/otaserver/LocalOtaServer.kt +304 -0
  163. package/android/src/main/java/com/glassly/bluetoothsdk/otaserver/OtaServerModule.kt +120 -0
  164. package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistry.java +108 -0
  165. package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoUploadServer.kt +622 -0
  166. package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/PhotoReceiverModule.kt +156 -0
  167. package/android/src/main/java/com/glassly/bluetoothsdk/requests/DisplayRequests.kt +56 -0
  168. package/android/src/main/java/com/glassly/bluetoothsdk/services/Foreground.kt +272 -0
  169. package/android/src/main/java/com/glassly/bluetoothsdk/services/PhoneMic.kt +1195 -0
  170. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Ar99.java +2653 -0
  171. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/BesOtaHeartbeatGuard.kt +49 -0
  172. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/BesOtaProgressMapper.kt +27 -0
  173. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G1.kt +3878 -0
  174. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G1TextSanitizer.kt +38 -0
  175. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2.kt +6428 -0
  176. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwClassification.kt +49 -0
  177. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwRenderer.kt +1241 -0
  178. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwTextureCache.kt +270 -0
  179. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2FlashProtocol.kt +291 -0
  180. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2Flasher.kt +411 -0
  181. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/GlasslyBle.java +43189 -0
  182. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Mach1.kt +1280 -0
  183. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLive.kt +10817 -0
  184. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLiveL2capChannel.kt +274 -0
  185. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLivePairingAdvertisement.kt +54 -0
  186. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraNex.kt +2011 -0
  187. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Nimo.kt +2532 -0
  188. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/SGCManager.kt +470 -0
  189. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Simulated.kt +228 -0
  190. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/Ar99OtaManager.java +566 -0
  191. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaByteUtils.java +18 -0
  192. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaCommandConstants.java +35 -0
  193. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaCrc32Util.java +13 -0
  194. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaGattTransport.java +11 -0
  195. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaProtocol.java +92 -0
  196. package/android/src/main/java/com/glassly/bluetoothsdk/speakerid/SpeakerIdEngine.kt +525 -0
  197. package/android/src/main/java/com/glassly/bluetoothsdk/status/DeviceStatus.kt +669 -0
  198. package/android/src/main/java/com/glassly/bluetoothsdk/status/RuntimeState.kt +201 -0
  199. package/android/src/main/java/com/glassly/bluetoothsdk/status/WifiHotspotStatus.kt +189 -0
  200. package/android/src/main/java/com/glassly/bluetoothsdk/streaming/StreamModels.kt +518 -0
  201. package/android/src/main/java/com/glassly/bluetoothsdk/stt/STTTools.kt +391 -0
  202. package/android/src/main/java/com/glassly/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +518 -0
  203. package/android/src/main/java/com/glassly/bluetoothsdk/stt/VadGateSpeechPolicy.kt +229 -0
  204. package/android/src/main/java/com/glassly/bluetoothsdk/tts/TTSTools.kt +248 -0
  205. package/android/src/main/java/com/glassly/bluetoothsdk/types/DeviceModels.kt +96 -0
  206. package/android/src/main/java/com/glassly/bluetoothsdk/utils/AES.java +106 -0
  207. package/android/src/main/java/com/glassly/bluetoothsdk/utils/AudioSessionMonitor.kt +189 -0
  208. package/android/src/main/java/com/glassly/bluetoothsdk/utils/AvifExifStripper.java +573 -0
  209. package/android/src/main/java/com/glassly/bluetoothsdk/utils/BitmapJavaUtils.java +169 -0
  210. package/android/src/main/java/com/glassly/bluetoothsdk/utils/BleJsonCompact.java +496 -0
  211. package/android/src/main/java/com/glassly/bluetoothsdk/utils/BlePhotoUploadService.java +677 -0
  212. package/android/src/main/java/com/glassly/bluetoothsdk/utils/BleWireProtocol.java +108 -0
  213. package/android/src/main/java/com/glassly/bluetoothsdk/utils/Constants.kt +46 -0
  214. package/android/src/main/java/com/glassly/bluetoothsdk/utils/G1Text.kt +436 -0
  215. package/android/src/main/java/com/glassly/bluetoothsdk/utils/HeifExifTagReader.java +199 -0
  216. package/android/src/main/java/com/glassly/bluetoothsdk/utils/IncidentLogBleRelayNaming.java +29 -0
  217. package/android/src/main/java/com/glassly/bluetoothsdk/utils/IncidentLogBleUploadService.java +77 -0
  218. package/android/src/main/java/com/glassly/bluetoothsdk/utils/K900LengthCodec.java +115 -0
  219. package/android/src/main/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtils.java +827 -0
  220. package/android/src/main/java/com/glassly/bluetoothsdk/utils/MessageChunkReassembler.java +228 -0
  221. package/android/src/main/java/com/glassly/bluetoothsdk/utils/MessageChunker.java +325 -0
  222. package/android/src/main/java/com/glassly/bluetoothsdk/utils/NexSGCUtils.kt +698 -0
  223. package/android/src/main/java/com/glassly/bluetoothsdk/utils/PhoneAudioMonitor.kt +348 -0
  224. package/android/src/main/java/com/glassly/bluetoothsdk/utils/SmartGlassesConnectionState.java +9 -0
  225. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/Ar99OpusPcmDecoder.java +398 -0
  226. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/ByteUtilAudioPlayer.java +655 -0
  227. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/Lc3Player.java +441 -0
  228. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/PCMAudioPlayer.java +431 -0
  229. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/PcmStreamPlayer.kt +328 -0
  230. package/android/src/main/res/values/strings.xml +4 -0
  231. package/android/src/test/java/com/glassly/bluetoothsdk/BluetoothSdkExceptionTest.kt +18 -0
  232. package/android/src/test/java/com/glassly/bluetoothsdk/OtaManifestDowngradeTest.kt +86 -0
  233. package/android/src/test/java/com/glassly/bluetoothsdk/OtaStartResponsePolicyTest.kt +30 -0
  234. package/android/src/test/java/com/glassly/bluetoothsdk/ReleaseChangelogTest.kt +13 -0
  235. package/android/src/test/java/com/glassly/bluetoothsdk/ScopedNetworkReadinessTest.kt +39 -0
  236. package/android/src/test/java/com/glassly/bluetoothsdk/StreamStatusEventTest.kt +29 -0
  237. package/android/src/test/java/com/glassly/bluetoothsdk/camera/PhotoRequestTest.kt +141 -0
  238. package/android/src/test/java/com/glassly/bluetoothsdk/otaserver/LocalOtaServerTest.kt +82 -0
  239. package/android/src/test/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistryTest.java +75 -0
  240. package/android/src/test/java/com/glassly/bluetoothsdk/services/ForegroundServiceTypeTest.kt +69 -0
  241. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/Ar99AdvertisementMatcherTest.java +22 -0
  242. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/BesOtaHeartbeatGuardTest.kt +73 -0
  243. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/BesOtaProgressMapperTest.kt +67 -0
  244. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/EvenRleTest.kt +63 -0
  245. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G1TextSanitizerTest.kt +31 -0
  246. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwClassificationTest.kt +89 -0
  247. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwRendererTest.kt +344 -0
  248. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwTextureCacheTest.kt +200 -0
  249. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2FlashProtocolTest.kt +131 -0
  250. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/MentraLiveGattCharacteristicsTest.kt +39 -0
  251. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/MentraLivePairingAdvertisementParserTest.kt +133 -0
  252. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/NimoProtocolTest.kt +333 -0
  253. package/android/src/test/java/com/glassly/bluetoothsdk/utils/AvifExifStripperTest.java +46 -0
  254. package/android/src/test/java/com/glassly/bluetoothsdk/utils/BinaryMessageChunkerTest.java +84 -0
  255. package/android/src/test/java/com/glassly/bluetoothsdk/utils/BleJsonCompactTest.java +319 -0
  256. package/android/src/test/java/com/glassly/bluetoothsdk/utils/BlePhotoUploadServiceTest.java +107 -0
  257. package/android/src/test/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtilsEndiannessTest.java +172 -0
  258. package/android/src/test/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtilsTest.java +24 -0
  259. package/android/src/test/java/com/glassly/bluetoothsdk/utils/PhoneAudioMonitorTest.kt +45 -0
  260. package/android/src/test/resources/avif_with_exif.avif +0 -0
  261. package/app.plugin.js +3 -0
  262. package/build/BluetoothSdk.types.d.ts +1354 -0
  263. package/build/BluetoothSdk.types.d.ts.map +1 -0
  264. package/build/BluetoothSdk.types.js +41 -0
  265. package/build/BluetoothSdk.types.js.map +1 -0
  266. package/build/_internal.d.ts +17 -0
  267. package/build/_internal.d.ts.map +1 -0
  268. package/build/_internal.js +16 -0
  269. package/build/_internal.js.map +1 -0
  270. package/build/_private/BluetoothSdkModule.d.ts +172 -0
  271. package/build/_private/BluetoothSdkModule.d.ts.map +1 -0
  272. package/build/_private/BluetoothSdkModule.js +300 -0
  273. package/build/_private/BluetoothSdkModule.js.map +1 -0
  274. package/build/_private/LocalNetworkModule.d.ts +38 -0
  275. package/build/_private/LocalNetworkModule.d.ts.map +1 -0
  276. package/build/_private/LocalNetworkModule.js +3 -0
  277. package/build/_private/LocalNetworkModule.js.map +1 -0
  278. package/build/_private/cameraRequestPayload.d.ts +4 -0
  279. package/build/_private/cameraRequestPayload.d.ts.map +1 -0
  280. package/build/_private/cameraRequestPayload.js +32 -0
  281. package/build/_private/cameraRequestPayload.js.map +1 -0
  282. package/build/_private/photoRequestPayload.d.ts +6 -0
  283. package/build/_private/photoRequestPayload.d.ts.map +1 -0
  284. package/build/_private/photoRequestPayload.js +86 -0
  285. package/build/_private/photoRequestPayload.js.map +1 -0
  286. package/build/_private/sdkOtaManifest.d.ts +11 -0
  287. package/build/_private/sdkOtaManifest.d.ts.map +1 -0
  288. package/build/_private/sdkOtaManifest.js +15 -0
  289. package/build/_private/sdkOtaManifest.js.map +1 -0
  290. package/build/changelogs.d.ts +7 -0
  291. package/build/changelogs.d.ts.map +1 -0
  292. package/build/changelogs.js +46 -0
  293. package/build/changelogs.js.map +1 -0
  294. package/build/debug.d.ts +3 -0
  295. package/build/debug.d.ts.map +1 -0
  296. package/build/debug.js +8 -0
  297. package/build/debug.js.map +1 -0
  298. package/build/generated/changelogCatalog.d.ts +9 -0
  299. package/build/generated/changelogCatalog.d.ts.map +1 -0
  300. package/build/generated/changelogCatalog.js +12 -0
  301. package/build/generated/changelogCatalog.js.map +1 -0
  302. package/build/generated/releaseMetadata.d.ts +12 -0
  303. package/build/generated/releaseMetadata.d.ts.map +1 -0
  304. package/build/generated/releaseMetadata.js +10 -0
  305. package/build/generated/releaseMetadata.js.map +1 -0
  306. package/build/index.d.ts +6 -0
  307. package/build/index.d.ts.map +1 -0
  308. package/build/index.js +171 -0
  309. package/build/index.js.map +1 -0
  310. package/build/ota-server/OtaServer.types.d.ts +14 -0
  311. package/build/ota-server/OtaServer.types.d.ts.map +1 -0
  312. package/build/ota-server/OtaServer.types.js +2 -0
  313. package/build/ota-server/OtaServer.types.js.map +1 -0
  314. package/build/ota-server/OtaServerModule.d.ts +21 -0
  315. package/build/ota-server/OtaServerModule.d.ts.map +1 -0
  316. package/build/ota-server/OtaServerModule.js +3 -0
  317. package/build/ota-server/OtaServerModule.js.map +1 -0
  318. package/build/ota-server/OtaServerModule.web.d.ts +10 -0
  319. package/build/ota-server/OtaServerModule.web.d.ts.map +1 -0
  320. package/build/ota-server/OtaServerModule.web.js +12 -0
  321. package/build/ota-server/OtaServerModule.web.js.map +1 -0
  322. package/build/ota-server/index.d.ts +3 -0
  323. package/build/ota-server/index.d.ts.map +1 -0
  324. package/build/ota-server/index.js +3 -0
  325. package/build/ota-server/index.js.map +1 -0
  326. package/build/ota-transport/index.d.ts +67 -0
  327. package/build/ota-transport/index.d.ts.map +1 -0
  328. package/build/ota-transport/index.js +58 -0
  329. package/build/ota-transport/index.js.map +1 -0
  330. package/build/photo-receiver/PhotoReceiver.types.d.ts +18 -0
  331. package/build/photo-receiver/PhotoReceiver.types.d.ts.map +1 -0
  332. package/build/photo-receiver/PhotoReceiver.types.js +2 -0
  333. package/build/photo-receiver/PhotoReceiver.types.js.map +1 -0
  334. package/build/photo-receiver/PhotoReceiverModule.d.ts +10 -0
  335. package/build/photo-receiver/PhotoReceiverModule.d.ts.map +1 -0
  336. package/build/photo-receiver/PhotoReceiverModule.js +3 -0
  337. package/build/photo-receiver/PhotoReceiverModule.js.map +1 -0
  338. package/build/photo-receiver/PhotoReceiverModule.web.d.ts +10 -0
  339. package/build/photo-receiver/PhotoReceiverModule.web.d.ts.map +1 -0
  340. package/build/photo-receiver/PhotoReceiverModule.web.js +12 -0
  341. package/build/photo-receiver/PhotoReceiverModule.web.js.map +1 -0
  342. package/build/photo-receiver/index.d.ts +3 -0
  343. package/build/photo-receiver/index.d.ts.map +1 -0
  344. package/build/photo-receiver/index.js +3 -0
  345. package/build/photo-receiver/index.js.map +1 -0
  346. package/build/react/index.d.ts +5 -0
  347. package/build/react/index.d.ts.map +1 -0
  348. package/build/react/index.js +4 -0
  349. package/build/react/index.js.map +1 -0
  350. package/build/react/useBluetooth.d.ts +100 -0
  351. package/build/react/useBluetooth.d.ts.map +1 -0
  352. package/build/react/useBluetooth.js +167 -0
  353. package/build/react/useBluetooth.js.map +1 -0
  354. package/build/react/useBluetoothEvent.d.ts +6 -0
  355. package/build/react/useBluetoothEvent.d.ts.map +1 -0
  356. package/build/react/useBluetoothEvent.js +21 -0
  357. package/build/react/useBluetoothEvent.js.map +1 -0
  358. package/build/react/useBluetoothScan.d.ts +22 -0
  359. package/build/react/useBluetoothScan.d.ts.map +1 -0
  360. package/build/react/useBluetoothScan.js +135 -0
  361. package/build/react/useBluetoothScan.js.map +1 -0
  362. package/build/react/useBluetoothStatus.d.ts +16 -0
  363. package/build/react/useBluetoothStatus.d.ts.map +1 -0
  364. package/build/react/useBluetoothStatus.js +137 -0
  365. package/build/react/useBluetoothStatus.js.map +1 -0
  366. package/build/react/useGlassesConnection.d.ts +29 -0
  367. package/build/react/useGlassesConnection.d.ts.map +1 -0
  368. package/build/react/useGlassesConnection.js +153 -0
  369. package/build/react/useGlassesConnection.js.map +1 -0
  370. package/build/types/index.d.ts +3 -0
  371. package/build/types/index.d.ts.map +1 -0
  372. package/build/types/index.js +2 -0
  373. package/build/types/index.js.map +1 -0
  374. package/expo-module.config.json +14 -0
  375. package/ios/BackgroundOtaArtifactDownloader.swift +125 -0
  376. package/ios/BluetoothSdkModule.swift +1034 -0
  377. package/ios/GlasslyBluetoothSDK.podspec +106 -0
  378. package/ios/LocalIPv4.swift +150 -0
  379. package/ios/LocalOtaServer.swift +309 -0
  380. package/ios/LocalPhotoUploadServer.swift +754 -0
  381. package/ios/OtaServerModule.swift +147 -0
  382. package/ios/Packages/CoreObjC/CoreObjC.xcodeproj/project.pbxproj +213 -0
  383. package/ios/Packages/CoreObjC/PcmConverter.h +22 -0
  384. package/ios/Packages/CoreObjC/PcmConverter.m +266 -0
  385. package/ios/Packages/CoreObjC/attdet.c +92 -0
  386. package/ios/Packages/CoreObjC/attdet.h +44 -0
  387. package/ios/Packages/CoreObjC/bits.c +375 -0
  388. package/ios/Packages/CoreObjC/bits.h +315 -0
  389. package/ios/Packages/CoreObjC/bwdet.c +129 -0
  390. package/ios/Packages/CoreObjC/bwdet.h +69 -0
  391. package/ios/Packages/CoreObjC/common.h +151 -0
  392. package/ios/Packages/CoreObjC/energy.c +70 -0
  393. package/ios/Packages/CoreObjC/energy.h +43 -0
  394. package/ios/Packages/CoreObjC/fastmath.h +158 -0
  395. package/ios/Packages/CoreObjC/include/PcmConverter.h +22 -0
  396. package/ios/Packages/CoreObjC/lc3.c +704 -0
  397. package/ios/Packages/CoreObjC/lc3.h +313 -0
  398. package/ios/Packages/CoreObjC/lc3_cpp.h +283 -0
  399. package/ios/Packages/CoreObjC/lc3_private.h +163 -0
  400. package/ios/Packages/CoreObjC/ltpf.c +905 -0
  401. package/ios/Packages/CoreObjC/ltpf.h +111 -0
  402. package/ios/Packages/CoreObjC/ltpf_arm.h +506 -0
  403. package/ios/Packages/CoreObjC/ltpf_neon.h +281 -0
  404. package/ios/Packages/CoreObjC/makefile.mk +35 -0
  405. package/ios/Packages/CoreObjC/mdct.c +469 -0
  406. package/ios/Packages/CoreObjC/mdct.h +57 -0
  407. package/ios/Packages/CoreObjC/mdct_neon.h +296 -0
  408. package/ios/Packages/CoreObjC/meson.build +61 -0
  409. package/ios/Packages/CoreObjC/plc.c +61 -0
  410. package/ios/Packages/CoreObjC/plc.h +57 -0
  411. package/ios/Packages/CoreObjC/rnnoise.h +114 -0
  412. package/ios/Packages/CoreObjC/sns.c +880 -0
  413. package/ios/Packages/CoreObjC/sns.h +103 -0
  414. package/ios/Packages/CoreObjC/spec.c +907 -0
  415. package/ios/Packages/CoreObjC/spec.h +119 -0
  416. package/ios/Packages/CoreObjC/tables.c +3457 -0
  417. package/ios/Packages/CoreObjC/tables.h +94 -0
  418. package/ios/Packages/CoreObjC/tns.c +457 -0
  419. package/ios/Packages/CoreObjC/tns.h +99 -0
  420. package/ios/Packages/SherpaOnnx/Model/joiner.onnx +0 -0
  421. package/ios/Packages/SherpaOnnx/Model/tokens.txt +502 -0
  422. package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +2383 -0
  423. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +48 -0
  424. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/c-api.h +4689 -0
  425. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/cxx-api.h +2036 -0
  426. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/libsherpa-onnx.a +0 -0
  427. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/Headers/sherpa-onnx/c-api/c-api.h +4689 -0
  428. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/Headers/sherpa-onnx/c-api/cxx-api.h +2036 -0
  429. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
  430. package/ios/Packages/libbz2/module.modulemap +5 -0
  431. package/ios/Packages/libbz2/shim.h +1 -0
  432. package/ios/PhotoReceiverModule.swift +129 -0
  433. package/ios/Source/BluetoothSDK.swift +2303 -0
  434. package/ios/Source/BluetoothSDKDebug.swift +12 -0
  435. package/ios/Source/BluetoothSdkDefaults.swift +29 -0
  436. package/ios/Source/Bridge.swift +708 -0
  437. package/ios/Source/Bridging-Header.h +16 -0
  438. package/ios/Source/DeviceManager.swift +2109 -0
  439. package/ios/Source/DeviceStore.swift +336 -0
  440. package/ios/Source/GeneratedChangelogCatalog.swift +7 -0
  441. package/ios/Source/GeneratedReleaseMetadata.swift +11 -0
  442. package/ios/Source/ObservableStore.swift +118 -0
  443. package/ios/Source/OtaManifest.swift +211 -0
  444. package/ios/Source/PrivacyInfo.xcprivacy +23 -0
  445. package/ios/Source/ReleaseChangelog.swift +65 -0
  446. package/ios/Source/Resources/G2Firmware/README.md +10 -0
  447. package/ios/Source/audio/AudioModels.swift +178 -0
  448. package/ios/Source/audio/PcmStreamPlayer.swift +410 -0
  449. package/ios/Source/camera/CameraModels.swift +866 -0
  450. package/ios/Source/connection/ScanSession.swift +27 -0
  451. package/ios/Source/controllers/ControllerManager.swift +184 -0
  452. package/ios/Source/controllers/R1.swift +829 -0
  453. package/ios/Source/errors/BluetoothSdkError.swift +19 -0
  454. package/ios/Source/events/BluetoothEvents.swift +342 -0
  455. package/ios/Source/internal/BleTraceLogger.swift +192 -0
  456. package/ios/Source/internal/BluetoothAvailability.swift +78 -0
  457. package/ios/Source/internal/BluetoothSdkAnalytics.swift +199 -0
  458. package/ios/Source/internal/ValueParsing.swift +99 -0
  459. package/ios/Source/requests/DisplayRequests.swift +82 -0
  460. package/ios/Source/services/PhoneMic.swift +662 -0
  461. package/ios/Source/sgcs/Ar99.swift +2451 -0
  462. package/ios/Source/sgcs/Frame.swift +649 -0
  463. package/ios/Source/sgcs/G1.swift +2554 -0
  464. package/ios/Source/sgcs/G2.swift +6887 -0
  465. package/ios/Source/sgcs/G2CfwClassification.swift +43 -0
  466. package/ios/Source/sgcs/G2CfwRenderer.swift +1279 -0
  467. package/ios/Source/sgcs/G2CfwTextureCache.swift +233 -0
  468. package/ios/Source/sgcs/G2FlashProtocol.swift +312 -0
  469. package/ios/Source/sgcs/G2Flasher.swift +773 -0
  470. package/ios/Source/sgcs/Mach1.swift +541 -0
  471. package/ios/Source/sgcs/MentraLive.swift +7011 -0
  472. package/ios/Source/sgcs/MentraLiveL2capChannel.swift +183 -0
  473. package/ios/Source/sgcs/MentraLivePairingAdvertisement.swift +64 -0
  474. package/ios/Source/sgcs/MentraNex.swift +3221 -0
  475. package/ios/Source/sgcs/Nimo.swift +1886 -0
  476. package/ios/Source/sgcs/SGCManager.swift +608 -0
  477. package/ios/Source/sgcs/Simulated.swift +274 -0
  478. package/ios/Source/sgcs/ar99/ota/Ar99OtaManager.swift +637 -0
  479. package/ios/Source/sgcs/glassly_ble.pb.swift +4354 -0
  480. package/ios/Source/speakerid/SpeakerIdEngine.swift +573 -0
  481. package/ios/Source/status/DeviceStatus.swift +981 -0
  482. package/ios/Source/status/RuntimeState.swift +359 -0
  483. package/ios/Source/status/WifiHotspotStatus.swift +345 -0
  484. package/ios/Source/streaming/StreamModels.swift +693 -0
  485. package/ios/Source/stt/STTTools.swift +191 -0
  486. package/ios/Source/stt/SherpaOnnxTranscriber.swift +466 -0
  487. package/ios/Source/tts/TTSTools.swift +171 -0
  488. package/ios/Source/types/DeviceModels.swift +177 -0
  489. package/ios/Source/utils/AudioSessionMonitor.swift +283 -0
  490. package/ios/Source/utils/BinaryCodec.swift +61 -0
  491. package/ios/Source/utils/BleJsonCompact.swift +405 -0
  492. package/ios/Source/utils/BleWireProtocol.swift +92 -0
  493. package/ios/Source/utils/Constants.swift +78 -0
  494. package/ios/Source/utils/Enums.swift +95 -0
  495. package/ios/Source/utils/G1Text.swift +2096 -0
  496. package/ios/Source/utils/JSCExperiment.swift +241 -0
  497. package/ios/Source/utils/MemoryMonitor.swift +44 -0
  498. package/ios/Source/utils/MessageChunkReassembler.swift +190 -0
  499. package/ios/Source/utils/MessageChunker.swift +294 -0
  500. package/ios/Source/utils/Models.swift +135 -0
  501. package/ios/Source/utils/PhoneAudioMonitor.swift +230 -0
  502. package/ios/Source/utils/TarBz2Extractor.swift +257 -0
  503. package/ios/Tests/BluetoothSDKTests/G2CfwClassificationTests.swift +78 -0
  504. package/ios/Tests/BluetoothSDKTests/G2CfwRendererTests.swift +372 -0
  505. package/ios/Tests/BluetoothSDKTests/G2CfwTextureCacheTests.swift +162 -0
  506. package/ios/Tests/BluetoothSDKTests/G2FlashProtocolTests.swift +182 -0
  507. package/ios/Tests/MentraLivePairingAdvertisementTests.swift +160 -0
  508. package/ios/Tests/ReleaseChangelogTests.swift +13 -0
  509. package/package.json +129 -0
  510. package/plugin/build/index.d.ts +10 -0
  511. package/plugin/build/index.js +12 -0
  512. package/plugin/build/withAndroid.d.ts +3 -0
  513. package/plugin/build/withAndroid.js +190 -0
  514. package/plugin/build/withIos.d.ts +5 -0
  515. package/plugin/build/withIos.js +108 -0
  516. package/scripts/inject-ios-sdk-version.mjs +65 -0
  517. package/scripts/public-ota-api.test.mjs +37 -0
  518. package/scripts/verify-release-package.mjs +45 -0
  519. package/scripts/write-release-metadata.mjs +152 -0
  520. package/scripts/write-release-metadata.test.mjs +37 -0
  521. package/src/BluetoothSdk.types.ts +1623 -0
  522. package/src/_internal.ts +16 -0
  523. package/src/_private/BluetoothSdkModule.ts +684 -0
  524. package/src/_private/LocalNetworkModule.ts +50 -0
  525. package/src/_private/cameraRequestPayload.ts +34 -0
  526. package/src/_private/photoRequestPayload.ts +90 -0
  527. package/src/_private/sdkOtaManifest.ts +18 -0
  528. package/src/changelogs.ts +46 -0
  529. package/src/debug.ts +9 -0
  530. package/src/generated/changelogCatalog.ts +13 -0
  531. package/src/generated/releaseMetadata.ts +20 -0
  532. package/src/index.ts +321 -0
  533. package/src/ota-server/OtaServer.types.ts +10 -0
  534. package/src/ota-server/OtaServerModule.ts +23 -0
  535. package/src/ota-server/OtaServerModule.web.ts +17 -0
  536. package/src/ota-server/index.ts +2 -0
  537. package/src/ota-transport/index.ts +116 -0
  538. package/src/photo-receiver/PhotoReceiver.types.ts +20 -0
  539. package/src/photo-receiver/PhotoReceiverModule.ts +11 -0
  540. package/src/photo-receiver/PhotoReceiverModule.web.ts +17 -0
  541. package/src/photo-receiver/index.ts +2 -0
  542. package/src/react/index.ts +21 -0
  543. package/src/react/useBluetooth.ts +309 -0
  544. package/src/react/useBluetoothEvent.ts +35 -0
  545. package/src/react/useBluetoothScan.ts +173 -0
  546. package/src/react/useBluetoothStatus.ts +180 -0
  547. package/src/react/useGlassesConnection.ts +202 -0
  548. package/src/types/index.ts +12 -0
@@ -0,0 +1,191 @@
1
+ import Foundation
2
+
3
+ class STTTools {
4
+ // MARK: - SherpaOnnxTranscriber / STT Model Management
5
+
6
+ /// How stale a SpeakerIdEngine match may be and still label a transcript.
7
+ private static let speakerMatchWindowMs: Int64 = 5000
8
+
9
+ /// Native-side join with SpeakerIdEngine: stamp the most recent
10
+ /// identification match onto the transcript. Fallback stays `0`/unknown
11
+ /// when the engine is off or nothing matched, so downstream schemas are
12
+ /// unchanged; the resolved name is additive.
13
+ private static func speakerFields() -> [String: Any] {
14
+ guard let match = SpeakerIdEngine.shared.recentMatch(withinMs: speakerMatchWindowMs) else {
15
+ return ["speakerId": 0]
16
+ }
17
+ return [
18
+ "speakerId": match.profileId,
19
+ "resolvedSpeakerId": match.profileId,
20
+ "resolvedSpeakerName": match.name,
21
+ ]
22
+ }
23
+
24
+ static func didReceivePartialTranscription(_ text: String) {
25
+ // Send partial result to server witgetConnectedBluetoothNameh proper formatting
26
+ let transcriptionLanguage =
27
+ UserDefaults.standard.string(forKey: "STTModelLanguageCode") ?? "en-US"
28
+ // Bridge.log("Glassly: Sending partial transcription: \(text), \(transcriptionLanguage)")
29
+ var transcription: [String: Any] = [
30
+ "type": "local_transcription",
31
+ "text": transcriptionLanguage == "en-US" ? text.lowercased() : text,
32
+ "isFinal": false,
33
+ "startTime": Int(Date().timeIntervalSince1970 * 1000) - 1000, // 1 second ago
34
+ "endTime": Int(Date().timeIntervalSince1970 * 1000),
35
+ "transcribeLanguage": transcriptionLanguage,
36
+ "provider": "sherpa-onnx",
37
+ ]
38
+ transcription.merge(speakerFields()) { _, new in new }
39
+
40
+ Bridge.sendLocalTranscription(transcription: transcription)
41
+ }
42
+
43
+ static func didReceiveFinalTranscription(_ text: String) {
44
+ // Send final result to server with proper formatting
45
+ let transcriptionLanguage =
46
+ UserDefaults.standard.string(forKey: "STTModelLanguageCode") ?? "en-US"
47
+ Bridge.log("Glassly: Sending final transcription: \(text), \(transcriptionLanguage)")
48
+ if !text.isEmpty {
49
+ var transcription: [String: Any] = [
50
+ "type": "local_transcription",
51
+ "text": transcriptionLanguage == "en-US" ? text.lowercased() : text,
52
+ "isFinal": true,
53
+ "startTime": Int(Date().timeIntervalSince1970 * 1000) - 2000, // 2 seconds ago
54
+ "endTime": Int(Date().timeIntervalSince1970 * 1000),
55
+ "transcribeLanguage": transcriptionLanguage,
56
+ "provider": "sherpa-onnx",
57
+ ]
58
+ let fields = speakerFields()
59
+ transcription.merge(fields) { _, new in new }
60
+ if let name = fields["resolvedSpeakerName"] as? String {
61
+ Bridge.log("SpeakerID: local final stamped as \(name)")
62
+ }
63
+
64
+ Bridge.sendLocalTranscription(transcription: transcription)
65
+ }
66
+ }
67
+
68
+ static func setSttModelDetails(_ path: String, _ languageCode: String) {
69
+ UserDefaults.standard.set(path, forKey: "STTModelPath")
70
+ UserDefaults.standard.set(languageCode, forKey: "STTModelLanguageCode")
71
+ UserDefaults.standard.synchronize()
72
+ }
73
+
74
+ static func getSttModelPath() -> String {
75
+ return UserDefaults.standard.string(forKey: "STTModelPath") ?? ""
76
+ }
77
+
78
+ static func checkSTTModelAvailable() -> Bool {
79
+ guard let modelPath = UserDefaults.standard.string(forKey: "STTModelPath") else {
80
+ return false
81
+ }
82
+
83
+ let fileManager = FileManager.default
84
+
85
+ // Check for tokens.txt (required for all models)
86
+ let tokensPath = (modelPath as NSString).appendingPathComponent("tokens.txt")
87
+ if !fileManager.fileExists(atPath: tokensPath) {
88
+ return false
89
+ }
90
+
91
+ // Check for CTC model
92
+ if firstExistingFile(in: modelPath, candidates: ["model.int8.onnx", "model.onnx"]) != nil {
93
+ return true
94
+ }
95
+
96
+ // Check for transducer model
97
+ let transducerFiles = [
98
+ ["encoder.onnx", "encoder.int8.onnx"],
99
+ ["decoder.onnx", "decoder.int8.onnx"],
100
+ ["joiner.onnx", "joiner.int8.onnx"],
101
+ ]
102
+ for candidates in transducerFiles {
103
+ if firstExistingFile(in: modelPath, candidates: candidates) == nil {
104
+ return false
105
+ }
106
+ }
107
+
108
+ return true
109
+ }
110
+
111
+ static func validateSTTModel(_ path: String) -> Bool {
112
+ // do {
113
+ let fileManager = FileManager.default
114
+
115
+ // Check for tokens.txt (required for all models)
116
+ let tokensPath = (path as NSString).appendingPathComponent("tokens.txt")
117
+ if !fileManager.fileExists(atPath: tokensPath) {
118
+ return false
119
+ }
120
+
121
+ // Check for CTC model
122
+ if firstExistingFile(in: path, candidates: ["model.int8.onnx", "model.onnx"]) != nil {
123
+ return true
124
+ }
125
+
126
+ // Check for transducer model
127
+ let transducerFiles = [
128
+ ["encoder.onnx", "encoder.int8.onnx"],
129
+ ["decoder.onnx", "decoder.int8.onnx"],
130
+ ["joiner.onnx", "joiner.int8.onnx"],
131
+ ]
132
+ var allTransducerFilesPresent = true
133
+
134
+ for candidates in transducerFiles {
135
+ if firstExistingFile(in: path, candidates: candidates) == nil {
136
+ allTransducerFilesPresent = false
137
+ break
138
+ }
139
+ }
140
+
141
+ return allTransducerFilesPresent
142
+ // } catch {
143
+ // Bridge.log("STT_ERROR: \(error.localizedDescription)")
144
+ // return false
145
+ // }
146
+ }
147
+
148
+ static func extractTarBz2(sourcePath: String, destinationPath: String) -> Bool {
149
+ do {
150
+ let fileManager = FileManager.default
151
+
152
+ // Create destination directory if it doesn't exist
153
+ try fileManager.createDirectory(
154
+ atPath: destinationPath,
155
+ withIntermediateDirectories: true,
156
+ attributes: nil
157
+ )
158
+
159
+ // Use the Swift TarBz2Extractor with SWCompression
160
+ var extractionError: NSError?
161
+ let success = TarBz2Extractor.extractTarBz2From(
162
+ sourcePath,
163
+ to: destinationPath,
164
+ error: &extractionError
165
+ )
166
+
167
+ if !success || extractionError != nil {
168
+ print(
169
+ "EXTRACTION_ERROR: \(extractionError?.localizedDescription ?? "Failed to extract tar.bz2")"
170
+ )
171
+ return false
172
+ }
173
+
174
+ } catch {
175
+ Bridge.log("EXTRACTION_ERROR: \(error.localizedDescription)")
176
+ return false
177
+ }
178
+ return true
179
+ }
180
+
181
+ private static func firstExistingFile(in directory: String, candidates: [String]) -> String? {
182
+ let fileManager = FileManager.default
183
+ for candidate in candidates {
184
+ let path = (directory as NSString).appendingPathComponent(candidate)
185
+ if fileManager.fileExists(atPath: path) {
186
+ return path
187
+ }
188
+ }
189
+ return nil
190
+ }
191
+ }
@@ -0,0 +1,466 @@
1
+ import Foundation
2
+ import UIKit
3
+
4
+ /**
5
+ * SherpaOnnxTranscriber handles real-time audio transcription using Sherpa-ONNX.
6
+ *
7
+ * It works fully offline and processes PCM audio in real-time to provide partial and final ASR results.
8
+ * This class runs on a background thread, processes short PCM chunks, and emits transcribed text using a delegate.
9
+ */
10
+ class SherpaOnnxTranscriber {
11
+ private static let TAG = "SherpaOnnxTranscriber"
12
+
13
+ private static let SAMPLE_RATE = 16000 // Sherpa-ONNX model's required sample rate
14
+ private static let QUEUE_CAPACITY = 100 // Max number of audio buffers to keep in queue
15
+
16
+ private let pcmQueue = DispatchQueue(label: "com.augmentos.sherpaonnx.pcmQueue", qos: .userInteractive)
17
+ private var pcmBuffers = [Data]()
18
+ private var isRunning = false
19
+ private var processingQueue: DispatchQueue?
20
+ private var processingTask: DispatchWorkItem?
21
+
22
+ /// The underlying Sherpa-ONNX objects
23
+ private var recognizer: SherpaOnnxRecognizer?
24
+
25
+ private var lastPartialResult = ""
26
+
27
+ /// Parent context
28
+ private weak var context: UIViewController?
29
+
30
+ /// Session start time for relative timestamps
31
+ private var transcriptionSessionStart: Date
32
+
33
+ /// Dynamic model path support
34
+ private static var customModelPath: String? {
35
+ guard let storedPath = UserDefaults.standard.string(forKey: "STTModelPath") else {
36
+ return nil
37
+ }
38
+
39
+ // Always resolve current Documents directory
40
+ let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
41
+
42
+ // Extract relative subpath after "Documents/"
43
+ // NOTE: Doing this because the application id changes between the development builds and files can't be found.
44
+ if let range = storedPath.range(of: "/Documents/") {
45
+ let relativePath = String(storedPath[range.upperBound...]) // e.g. "stt_models/..."
46
+ let fixedPath = documentsURL.appendingPathComponent(relativePath).path
47
+
48
+ Bridge.log("Reconstructed STTModelPath: \(fixedPath)")
49
+ return fixedPath
50
+ }
51
+
52
+ // If nothing matched, just return as-is
53
+ Bridge.log("STTModelPath (raw): \(storedPath)")
54
+ return storedPath
55
+ }
56
+
57
+ private static func firstExistingFile(in directory: String, candidates: [String]) -> String? {
58
+ let fileManager = FileManager.default
59
+ for candidate in candidates {
60
+ let path = (directory as NSString).appendingPathComponent(candidate)
61
+ if fileManager.fileExists(atPath: path) {
62
+ return path
63
+ }
64
+ }
65
+ return nil
66
+ }
67
+
68
+ /**
69
+ * Heuristically detect an NVIDIA Nemotron model directory.
70
+ *
71
+ * Nemotron is file-identical to a Zipformer transducer (encoder/decoder/joiner + tokens.txt),
72
+ * so filenames alone cannot distinguish the two. We check the on-disk directory name first โ€”
73
+ * STTModelManager names the folder after the model id โ€” and fall back to the README.md that
74
+ * ships inside every upstream archive.
75
+ *
76
+ * This is advisory only: sherpa-onnx does the authoritative dispatch from ONNX metadata. A
77
+ * false negative costs nothing but a less precise log line.
78
+ */
79
+ private static func isNemotronModelDir(_ directory: String) -> Bool {
80
+ if (directory as NSString).lastPathComponent.range(of: "nemotron", options: .caseInsensitive) != nil {
81
+ return true
82
+ }
83
+
84
+ let readmePath = (directory as NSString).appendingPathComponent("README.md")
85
+ guard let readme = try? String(contentsOfFile: readmePath, encoding: .utf8) else {
86
+ return false
87
+ }
88
+ // Archive READMEs are small; cap the scan so a malformed file can't stall startup.
89
+ return readme.prefix(8192).range(of: "nemotron", options: .caseInsensitive) != nil
90
+ }
91
+
92
+ /**
93
+ * Constructor that accepts a UIViewController to load model assets.
94
+ */
95
+ init(context: UIViewController) {
96
+ self.context = context
97
+ transcriptionSessionStart = Date()
98
+ }
99
+
100
+ deinit {
101
+ shutdown()
102
+ }
103
+
104
+ /**
105
+ * Initialize the Sherpa-ONNX recognizer.
106
+ * Loads models and configuration, sets up processing thread.
107
+ */
108
+ func initialize() {
109
+ do {
110
+ var tokensPath: String
111
+ var modelType = "unknown"
112
+ let fileManager = FileManager.default
113
+
114
+ // Check if we have a custom model path set
115
+ if let customPath = SherpaOnnxTranscriber.customModelPath {
116
+ // Detect model type based on available files
117
+ let ctcModelPath = Self.firstExistingFile(
118
+ in: customPath,
119
+ candidates: ["model.int8.onnx", "model.onnx"]
120
+ )
121
+ let transducerEncoderPath = Self.firstExistingFile(
122
+ in: customPath,
123
+ candidates: ["encoder.int8.onnx", "encoder.onnx"]
124
+ )
125
+
126
+ tokensPath = (customPath as NSString).appendingPathComponent("tokens.txt")
127
+
128
+ // Verify tokens file exists
129
+ guard fileManager.fileExists(atPath: tokensPath) else {
130
+ throw NSError(domain: "SherpaOnnxTranscriber", code: 1, userInfo: [
131
+ NSLocalizedDescriptionKey: "tokens.txt not found at path: \(customPath)",
132
+ ])
133
+ }
134
+
135
+ if let ctcModelPath {
136
+ // CTC model detected
137
+ modelType = "ctc"
138
+ Bridge.log("Detected CTC model at \(customPath)")
139
+
140
+ // Build the config and construct the recognizer inside one
141
+ // C-string scope: the config's `const char*` fields point at
142
+ // buffers owned by that scope (see toCPointer in
143
+ // SherpaOnnx.swift). The config must not escape it.
144
+ recognizer = withSherpaOnnxCStrings {
145
+ // Create CTC model config using Zipformer2Ctc
146
+ let nemoCtc = sherpaOnnxOnlineNemoCtcModelConfig(
147
+ model: ctcModelPath
148
+ )
149
+
150
+ // Create model config with CTC
151
+ let modelConfig = sherpaOnnxOnlineModelConfig(
152
+ tokens: tokensPath,
153
+ numThreads: 1,
154
+ nemoCtc: nemoCtc
155
+ )
156
+
157
+ // Configure recognizer
158
+ let featureConfig = sherpaOnnxFeatureConfig()
159
+
160
+ var config = sherpaOnnxOnlineRecognizerConfig(
161
+ featConfig: featureConfig,
162
+ modelConfig: modelConfig,
163
+ enableEndpoint: true,
164
+ rule1MinTrailingSilence: 1.2,
165
+ rule2MinTrailingSilence: 0.8,
166
+ rule3MinUtteranceLength: 10.0
167
+ )
168
+
169
+ // Create recognizer with the wrapper
170
+ return SherpaOnnxRecognizer(config: &config)
171
+ }
172
+
173
+ } else if let transducerEncoderPath {
174
+ // Transducer model detected. NVIDIA Nemotron ships the same
175
+ // encoder/decoder/joiner triplet as a Zipformer transducer and is loaded
176
+ // through this very same config โ€” sherpa-onnx sniffs the ONNX metadata and
177
+ // dispatches to its NeMo transducer implementation on its own. We detect it
178
+ // only to log it distinctly; there is no Nemotron-specific config struct.
179
+ //
180
+ // Critically, we must NOT set a modelType override for Nemotron:
181
+ // "transducer" would force the generic Zipformer path and mis-decode.
182
+ // Leaving it unset lets sherpa-onnx auto-detect.
183
+ let isNemotron = Self.isNemotronModelDir(customPath)
184
+ modelType = isNemotron ? "nemotron" : "transducer"
185
+ Bridge.log("Detected \(modelType) model at \(customPath)")
186
+
187
+ let decoderPath = Self.firstExistingFile(
188
+ in: customPath,
189
+ candidates: ["decoder.int8.onnx", "decoder.onnx"]
190
+ )
191
+ let joinerPath = Self.firstExistingFile(
192
+ in: customPath,
193
+ candidates: ["joiner.int8.onnx", "joiner.onnx"]
194
+ )
195
+
196
+ // Verify all transducer files exist
197
+ guard let decoderPath,
198
+ let joinerPath
199
+ else {
200
+ throw NSError(domain: "SherpaOnnxTranscriber", code: 1, userInfo: [
201
+ NSLocalizedDescriptionKey: "Transducer model files incomplete at path: \(customPath)",
202
+ ])
203
+ }
204
+
205
+ // Build the config and construct the recognizer inside one
206
+ // C-string scope: the config's `const char*` fields point at
207
+ // buffers owned by that scope (see toCPointer in
208
+ // SherpaOnnx.swift). The config must not escape it.
209
+ recognizer = withSherpaOnnxCStrings {
210
+ // Create Sherpa-ONNX transducer model config
211
+ let transducer = sherpaOnnxOnlineTransducerModelConfig(
212
+ encoder: transducerEncoderPath,
213
+ decoder: decoderPath,
214
+ joiner: joinerPath
215
+ )
216
+
217
+ // Create model config
218
+ let modelConfig = sherpaOnnxOnlineModelConfig(
219
+ tokens: tokensPath,
220
+ transducer: transducer,
221
+ numThreads: 1
222
+ )
223
+
224
+ // Configure recognizer
225
+ let featureConfig = sherpaOnnxFeatureConfig()
226
+
227
+ var config = sherpaOnnxOnlineRecognizerConfig(
228
+ featConfig: featureConfig,
229
+ modelConfig: modelConfig,
230
+ enableEndpoint: true,
231
+ rule1MinTrailingSilence: 1.2,
232
+ rule2MinTrailingSilence: 0.8,
233
+ rule3MinUtteranceLength: 10.0
234
+ )
235
+
236
+ // Create recognizer with the wrapper
237
+ return SherpaOnnxRecognizer(config: &config)
238
+ }
239
+
240
+ } else {
241
+ throw NSError(domain: "SherpaOnnxTranscriber", code: 1, userInfo: [
242
+ NSLocalizedDescriptionKey: "No valid model files found at path: \(customPath)",
243
+ ])
244
+ }
245
+ } else {
246
+ Bridge.log("No Sherpa ONNX model available. Transcription will be disabled.")
247
+ Bridge.log("Please download a model using the model downloader in settings.")
248
+ recognizer = nil
249
+ isRunning = false
250
+ return
251
+ }
252
+
253
+ if recognizer == nil {
254
+ throw NSError(domain: "SherpaOnnxTranscriber", code: 2, userInfo: [NSLocalizedDescriptionKey: "Failed to create recognizer"])
255
+ }
256
+
257
+ startProcessingTask()
258
+ isRunning = true
259
+
260
+ Bridge.log("Sherpa-ONNX ASR initialized successfully with \(modelType) model")
261
+
262
+ } catch {
263
+ Bridge.log("Failed to initialize Sherpa-ONNX: \(error.localizedDescription)")
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Handle transcription results - send only to delegate
269
+ */
270
+ private func handleTranscriptionResult(text: String, isFinal: Bool) {
271
+ // Forward to delegate if set
272
+ DispatchQueue.main.async { [weak self] in
273
+ if isFinal {
274
+ STTTools.didReceiveFinalTranscription(text)
275
+ } else {
276
+ STTTools.didReceivePartialTranscription(text)
277
+ }
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Feed PCM audio data (16-bit little endian) into the transcriber.
283
+ * This method should be called continuously with short chunks (e.g., 100-300ms).
284
+ *
285
+ * Audio is queued directly; microphone VAD gating is not applied in the SDK.
286
+ */
287
+ func acceptAudio(pcm16le: Data) {
288
+ guard isRunning else {
289
+ return
290
+ }
291
+
292
+ queueAudioData(pcm16le)
293
+ }
294
+
295
+ private func queueAudioData(_ pcm16le: Data) {
296
+ pcmQueue.async { [weak self] in
297
+ guard let self = self else { return }
298
+
299
+ let queueSizeBefore = self.pcmBuffers.count
300
+ self.pcmBuffers.append(pcm16le)
301
+
302
+ // Keep queue size manageable
303
+ if self.pcmBuffers.count > Self.QUEUE_CAPACITY {
304
+ let removedBuffer = self.pcmBuffers.removeFirst()
305
+ Bridge.log("โš ๏ธ Audio queue overflow - dropped buffer of \(removedBuffer.count) bytes")
306
+ }
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Start a background task to continuously consume audio and decode using Sherpa.
312
+ */
313
+ private func startProcessingTask() {
314
+ Bridge.log("๐Ÿš€ Starting Sherpa-ONNX processing task...")
315
+
316
+ processingQueue = DispatchQueue(label: "com.augmentos.sherpaonnx.processor", qos: .userInitiated)
317
+
318
+ let workItem = DispatchWorkItem { [weak self] in
319
+ self?.runLoop()
320
+ }
321
+
322
+ processingTask = workItem
323
+ processingQueue?.async(execute: workItem)
324
+ }
325
+
326
+ /**
327
+ * Main processing loop that handles transcription in real-time.
328
+ * Pulls audio from queue, feeds into Sherpa, emits partial/final results.
329
+ */
330
+ private func runLoop() {
331
+ Bridge.log("๐Ÿ”„ Sherpa-ONNX processing loop started")
332
+
333
+ while isRunning {
334
+ // Pull data from queue
335
+ var audioData: Data?
336
+
337
+ pcmQueue.sync {
338
+ if !self.pcmBuffers.isEmpty {
339
+ audioData = self.pcmBuffers.removeFirst()
340
+ }
341
+ }
342
+
343
+ if let data = audioData {
344
+ // Synchronize access to recognizer to prevent race conditions
345
+ objc_sync_enter(self)
346
+ defer { objc_sync_exit(self) }
347
+
348
+ guard let recognizer = recognizer else {
349
+ Bridge.log("โš ๏ธ Recognizer not available, skipping audio chunk")
350
+ continue
351
+ }
352
+
353
+ do {
354
+ // Convert PCM to float [-1.0, 1.0]
355
+ let floatBuf = toFloatArray(from: data)
356
+
357
+ // Pass audio data to the Sherpa-ONNX stream
358
+ recognizer.acceptWaveform(samples: floatBuf, sampleRate: Self.SAMPLE_RATE)
359
+
360
+ // Decode continuously while model is ready
361
+ var decodeCount = 0
362
+ while recognizer.isReady() {
363
+ recognizer.decode()
364
+ decodeCount += 1
365
+ }
366
+
367
+ // If utterance endpoint detected
368
+ if recognizer.isEndpoint() {
369
+ let result = recognizer.getResult()
370
+ let finalText = result.text.trimmingCharacters(in: .whitespacesAndNewlines)
371
+
372
+ if !finalText.isEmpty {
373
+ handleTranscriptionResult(text: finalText, isFinal: true)
374
+ }
375
+
376
+ recognizer.reset() // Start new utterance
377
+ lastPartialResult = ""
378
+ } else {
379
+ // Emit partial results if changed
380
+ let result = recognizer.getResult()
381
+ let partial = result.text.trimmingCharacters(in: .whitespacesAndNewlines)
382
+
383
+ if partial != lastPartialResult, !partial.isEmpty {
384
+ handleTranscriptionResult(text: partial, isFinal: false)
385
+ lastPartialResult = partial
386
+ }
387
+ }
388
+ } catch {
389
+ Bridge.log("โŒ Error processing audio: \(error.localizedDescription)")
390
+ }
391
+ } else {
392
+ // Sleep briefly to avoid tight CPU loop if no audio is available
393
+ Thread.sleep(forTimeInterval: 0.01)
394
+ }
395
+ }
396
+
397
+ Bridge.log("ASR processing thread stopped")
398
+ }
399
+
400
+ /**
401
+ * Convert 16-bit PCM byte data (little-endian) to float array [-1.0, 1.0].
402
+ */
403
+ private func toFloatArray(from pcmData: Data) -> [Float] {
404
+ let count = pcmData.count / 2
405
+ var samples = [Float](repeating: 0, count: count)
406
+
407
+ pcmData.withUnsafeBytes { (bufferPointer: UnsafeRawBufferPointer) in
408
+ if let address = bufferPointer.baseAddress {
409
+ let int16Pointer = address.bindMemory(to: Int16.self, capacity: count)
410
+
411
+ for i in 0 ..< count {
412
+ // Convert from little-endian if needed
413
+ var sample = int16Pointer[i]
414
+ if CFByteOrderGetCurrent() == CFByteOrder(CFByteOrderBigEndian.rawValue) {
415
+ sample = Int16(littleEndian: sample)
416
+ }
417
+ samples[i] = Float(sample) / 32768.0
418
+ }
419
+ }
420
+ }
421
+
422
+ return samples
423
+ }
424
+
425
+ /**
426
+ * Stop transcription processing.
427
+ * This shuts down the processing thread and releases Sherpa-ONNX resources.
428
+ */
429
+ func shutdown() {
430
+ Bridge.log("๐Ÿ›‘ Shutting down SherpaOnnxTranscriber...")
431
+
432
+ isRunning = false
433
+ processingTask?.cancel()
434
+
435
+ // Synchronize access to recognizer during shutdown
436
+ objc_sync_enter(self)
437
+ defer { objc_sync_exit(self) }
438
+
439
+ // The recognizer will be automatically cleaned up by ARC when set to nil
440
+ if recognizer != nil {
441
+ Bridge.log("๐Ÿงน Cleaning up Sherpa-ONNX recognizer")
442
+ recognizer = nil
443
+ }
444
+
445
+ // Clear any remaining audio buffers
446
+ pcmQueue.sync {
447
+ let remainingBuffers = self.pcmBuffers.count
448
+ if remainingBuffers > 0 {
449
+ Bridge.log("๐Ÿ—‘๏ธ Clearing \(remainingBuffers) remaining audio buffers")
450
+ }
451
+ self.pcmBuffers.removeAll()
452
+ }
453
+
454
+ Bridge.log("โœ… SherpaOnnxTranscriber shutdown complete")
455
+ }
456
+
457
+ /**
458
+ * Restarts the transcriber after a model change.
459
+ * Shuts down existing resources, clears buffers, and reinitializes the recognizer.
460
+ */
461
+ func restart() {
462
+ Bridge.log("โ™ป๏ธ Restarting SherpaOnnxTranscriber...")
463
+ shutdown()
464
+ initialize()
465
+ }
466
+ }