@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,708 @@
1
+ //
2
+ // Bridge.swift
3
+ // AOS
4
+ //
5
+ // Created by Matthew Fosse on 3/4/25.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ /// Bridge for Bluetooth SDK communication between Expo modules and native iOS code
11
+ /// Has commands for the Bluetooth SDK to use to send messages to JavaScript
12
+ class Bridge {
13
+ private static let micSampleRate = 16000
14
+ private static let pcmBitsPerSample = 16
15
+ private static let micChannels = 1
16
+ private static let lc3FrameDurationMs = 10
17
+ private static let defaultLc3FrameSizeBytes = 60
18
+ private static let audioTraceMetadataKeys = [
19
+ "sampleRate",
20
+ "bitsPerSample",
21
+ "channels",
22
+ "encoding",
23
+ "frameDurationMs",
24
+ "frameSizeBytes",
25
+ "bitrate",
26
+ "packetizedFromGlasses",
27
+ "voiceActivityDetectionEnabled",
28
+ ]
29
+ private static let eventSinkLock = NSLock()
30
+ private static let defaultEventSinkId = "default"
31
+ private static var eventSinks: [String: (String, [String: Any]) -> Void] = [:]
32
+
33
+ static func initialize(callback: @escaping (String, [String: Any]) -> Void) {
34
+ setEventSink(defaultEventSinkId, callback)
35
+ }
36
+
37
+ static func addEventSink(callback: @escaping (String, [String: Any]) -> Void) -> String {
38
+ let id = UUID().uuidString
39
+ setEventSink(id, callback)
40
+ return id
41
+ }
42
+
43
+ static func removeEventSink(_ id: String) {
44
+ eventSinkLock.lock()
45
+ eventSinks.removeValue(forKey: id)
46
+ eventSinkLock.unlock()
47
+ }
48
+
49
+ private static func setEventSink(_ id: String, _ callback: @escaping (String, [String: Any]) -> Void) {
50
+ eventSinkLock.lock()
51
+ eventSinks[id] = callback
52
+ eventSinkLock.unlock()
53
+ }
54
+
55
+ private static func currentEventSinks() -> [(String, [String: Any]) -> Void] {
56
+ eventSinkLock.lock()
57
+ let sinks = Array(eventSinks.values)
58
+ eventSinkLock.unlock()
59
+ return sinks
60
+ }
61
+
62
+ /// Thread-safe event dispatch - ensures callback is invoked on main thread
63
+ /// to avoid React Native bridge threading issues that can cause EXC_BREAKPOINT
64
+ private static func dispatchEvent(_ eventName: String, _ data: [String: Any]) {
65
+ let sinks = currentEventSinks()
66
+ guard !sinks.isEmpty else { return }
67
+ if Thread.isMainThread {
68
+ sinks.forEach { $0(eventName, data) }
69
+ } else {
70
+ DispatchQueue.main.async {
71
+ sinks.forEach { $0(eventName, data) }
72
+ }
73
+ }
74
+ }
75
+
76
+ static func log(_ message: String) {
77
+ let data = ["message": message]
78
+ Bridge.sendTypedMessage("log", body: data)
79
+ }
80
+
81
+ /// Report tar.bz2 extraction progress to JavaScript.
82
+ static func sendExtractionProgress(percentage: Int, bytesRead: Int64, totalBytes: Int64) {
83
+ let body: [String: Any] = [
84
+ "percentage": percentage,
85
+ "bytesRead": bytesRead,
86
+ "totalBytes": totalBytes,
87
+ ]
88
+ Bridge.sendTypedMessage("extraction_progress", body: body)
89
+ }
90
+
91
+ static func sendHeadUp(_ isUp: Bool) {
92
+ let data = ["up": isUp]
93
+ Bridge.sendTypedMessage("head_up", body: data)
94
+ }
95
+
96
+ static func sendPairFailureEvent(_ error: String) {
97
+ let data = ["error": error]
98
+ Bridge.sendTypedMessage("pair_failure", body: data)
99
+ }
100
+
101
+ static func sendPairingInfo(
102
+ hadPreviousBond: Bool,
103
+ pairingCode: String? = nil,
104
+ classicBondReady: Bool = false,
105
+ securePairingCapable: Bool = true,
106
+ protocolVersion: Int = 1
107
+ ) {
108
+ var body: [String: Any] = [
109
+ "had_previous_bond": hadPreviousBond,
110
+ "classic_bond_ready": classicBondReady,
111
+ "secure_pairing_capable": securePairingCapable,
112
+ "protocol_version": protocolVersion,
113
+ ]
114
+ if let pairingCode { body["pairing_code"] = pairingCode }
115
+ Bridge.sendTypedMessage("pairing_info", body: body)
116
+ }
117
+
118
+ @MainActor
119
+ static func sendMicPcm(_ data: Data) {
120
+ Bridge.sendTypedMessage("mic_pcm", body: micPcmEventBody(data))
121
+ }
122
+
123
+ @MainActor
124
+ static func sendMicLc3(_ data: Data) {
125
+ Bridge.sendTypedMessage("mic_lc3", body: micLc3EventBody(data))
126
+ }
127
+
128
+ @MainActor
129
+ static func sendMicHealth(_ health: MicHealth, reason: String) {
130
+ var body = health.dictionary
131
+ body["reason"] = reason
132
+ body["timestamp"] = Int64(Date().timeIntervalSince1970 * 1000)
133
+ Bridge.sendTypedMessage("mic_health", body: body)
134
+ }
135
+
136
+ @MainActor
137
+ private static func micPcmEventBody(_ data: Data) -> [String: Any] {
138
+ let voiceActivityDetectionEnabled =
139
+ DeviceStore.shared.get("glasses", "voiceActivityDetectionEnabled") as? Bool
140
+ ?? BluetoothSdkDefaults.voiceActivityDetectionEnabled
141
+ return [
142
+ "pcm": data,
143
+ "sampleRate": micSampleRate,
144
+ "bitsPerSample": pcmBitsPerSample,
145
+ "channels": micChannels,
146
+ "encoding": "pcm_s16le",
147
+ "voiceActivityDetectionEnabled": voiceActivityDetectionEnabled,
148
+ ]
149
+ }
150
+
151
+ @MainActor
152
+ private static func micLc3EventBody(_ data: Data) -> [String: Any] {
153
+ let voiceActivityDetectionEnabled =
154
+ DeviceStore.shared.get("glasses", "voiceActivityDetectionEnabled") as? Bool
155
+ ?? BluetoothSdkDefaults.voiceActivityDetectionEnabled
156
+ // NSNumber coercion: the JS bridge stores numbers as Double, so `as? Int`
157
+ // would silently fall back to the default.
158
+ let frameSizeBytes =
159
+ (DeviceStore.shared.get("bluetooth", "lc3_frame_size") as? NSNumber)?.intValue ?? defaultLc3FrameSizeBytes
160
+ return [
161
+ "lc3": data,
162
+ "sampleRate": micSampleRate,
163
+ "channels": micChannels,
164
+ "encoding": "lc3",
165
+ "frameDurationMs": lc3FrameDurationMs,
166
+ "frameSizeBytes": frameSizeBytes,
167
+ "bitrate": frameSizeBytes * 8 * (1000 / lc3FrameDurationMs),
168
+ "packetizedFromGlasses": false,
169
+ "voiceActivityDetectionEnabled": voiceActivityDetectionEnabled,
170
+ ]
171
+ }
172
+
173
+ // MARK: - Speaker identification
174
+
175
+ /// One identification window from SpeakerIdEngine. `speakerId`/`name` are
176
+ /// omitted for an unknown (unenrolled) voice.
177
+ static func sendSpeakerDetected(speakerId: String?, name: String?, similarity: Double, startMs: Int64, endMs: Int64) {
178
+ var body: [String: Any] = [
179
+ "similarity": similarity,
180
+ "startMs": startMs,
181
+ "endMs": endMs,
182
+ ]
183
+ if let speakerId {
184
+ body["speakerId"] = speakerId
185
+ }
186
+ if let name {
187
+ body["name"] = name
188
+ }
189
+ Bridge.sendTypedMessage("speaker_detected", body: body)
190
+ }
191
+
192
+ static func sendSpeakerEnrollProgress(voicedSeconds: Double, targetSeconds: Double, level: Double) {
193
+ let body: [String: Any] = [
194
+ "voicedSeconds": voicedSeconds,
195
+ "targetSeconds": targetSeconds,
196
+ "level": level,
197
+ ]
198
+ Bridge.sendTypedMessage("speaker_enroll_progress", body: body)
199
+ }
200
+
201
+ /// Enrollment outcome. Embeddings are base64 Float32Arrays — raw audio is
202
+ /// already discarded by the time this fires.
203
+ static func sendSpeakerEnrollResult(ok: Bool, reason: String?, embeddings: [String], dim: Int, source: String) {
204
+ var body: [String: Any] = [
205
+ "ok": ok,
206
+ "source": source,
207
+ ]
208
+ if let reason {
209
+ body["reason"] = reason
210
+ }
211
+ if ok {
212
+ body["embeddings"] = embeddings
213
+ body["dim"] = dim
214
+ }
215
+ Bridge.sendTypedMessage("speaker_enroll_result", body: body)
216
+ }
217
+
218
+ static func saveSetting(_ key: String, _ value: Any) {
219
+ let body = ["key": key, "value": value]
220
+ Bridge.sendTypedMessage("save_setting", body: body)
221
+ }
222
+
223
+ @MainActor
224
+ static func sendVoiceActivityDetectionStatus(_ enabled: Bool) {
225
+ DeviceStore.shared.set("glasses", "voiceActivityDetectionEnabled", enabled)
226
+ let body: [String: Any] = [
227
+ "voiceActivityDetectionEnabled": enabled,
228
+ ]
229
+ Bridge.sendTypedMessage("voice_activity_detection_status", body: body)
230
+ }
231
+
232
+ static func sendSpeakingStatus(_ speaking: Bool) {
233
+ let body: [String: Any] = [
234
+ "speaking": speaking,
235
+ "timestamp": Int(Date().timeIntervalSince1970 * 1000),
236
+ ]
237
+ Bridge.sendTypedMessage("speaking_status", body: body)
238
+ }
239
+
240
+ static func sendBatteryStatus(level: Int, charging: Bool) {
241
+ let body: [String: Any] = [
242
+ "level": level,
243
+ "charging": charging,
244
+ "timestamp": Date().timeIntervalSince1970 * 1000,
245
+ ]
246
+ Bridge.sendTypedMessage("battery_status", body: body)
247
+ }
248
+
249
+ static func sendDiscoveredDevice(
250
+ _ deviceModel: String,
251
+ _ deviceName: String,
252
+ deviceAddress: String = "",
253
+ rssi: Int? = nil,
254
+ projectName: String? = nil,
255
+ pairingMode: Bool? = nil,
256
+ pairingCode: String? = nil,
257
+ securePairingCapable: Bool? = nil
258
+ ) {
259
+ Task {
260
+ await MainActor.run {
261
+ let searchResults = DeviceStore.shared.get("bluetooth", "searchResults") as? [[String: Any]] ?? []
262
+ let id = [deviceModel, projectName?.isEmpty == false ? projectName! : nil, deviceName]
263
+ .compactMap { $0 }
264
+ .joined(separator: ":")
265
+ var newResult: [String: Any] = [
266
+ "id": id,
267
+ "model": deviceModel,
268
+ "name": deviceName,
269
+ ]
270
+ if !deviceAddress.isEmpty {
271
+ newResult["address"] = deviceAddress
272
+ }
273
+ if let projectName, !projectName.isEmpty {
274
+ newResult["projectName"] = projectName
275
+ }
276
+ if let rssi {
277
+ newResult["rssi"] = rssi
278
+ }
279
+ if let pairingMode {
280
+ newResult["pairingMode"] = pairingMode
281
+ }
282
+ if let pairingCode, !pairingCode.isEmpty {
283
+ newResult["pairingCode"] = pairingCode
284
+ }
285
+ if let securePairingCapable {
286
+ newResult["securePairingCapable"] = securePairingCapable
287
+ }
288
+ // Keep the public searchResults array stable as glasses are added or removed.
289
+ // Duplicate discoveries refresh their existing row; only new glasses append.
290
+ let uniqueResults = mergeStableSearchResults(
291
+ searchResults,
292
+ newResult: newResult,
293
+ fallbackModel: deviceModel
294
+ )
295
+ DeviceStore.shared.set("bluetooth", "searchResults", uniqueResults)
296
+ }
297
+ }
298
+ }
299
+
300
+ private static func mergeStableSearchResults(
301
+ _ currentResults: [[String: Any]],
302
+ newResult: [String: Any],
303
+ fallbackModel: String
304
+ ) -> [[String: Any]] {
305
+ guard let newKey = searchResultKey(newResult, fallbackModel: fallbackModel) else {
306
+ return currentResults
307
+ }
308
+ var nextResults = currentResults
309
+ if let existingIndex = nextResults.firstIndex(where: {
310
+ searchResultKey($0, fallbackModel: fallbackModel) == newKey
311
+ }) {
312
+ nextResults[existingIndex] = newResult
313
+ } else {
314
+ nextResults.append(newResult)
315
+ }
316
+ return nextResults
317
+ }
318
+
319
+ private static func searchResultKey(_ result: [String: Any], fallbackModel: String) -> String? {
320
+ if let id = result["id"] as? String, !id.isEmpty {
321
+ return id
322
+ }
323
+ let model = result["model"] as? String ?? fallbackModel
324
+ guard let name = result["name"] as? String else {
325
+ return nil
326
+ }
327
+ return "\(model):\(name)"
328
+ }
329
+
330
+ // MARK: - Hardware Events
331
+
332
+ static func sendButtonPress(buttonId: String, pressType: String) {
333
+ // Send as typed message so it gets handled locally by MantleBridge.tsx
334
+ // This allows the React Native layer to process it before forwarding to server
335
+ let body: [String: Any] = [
336
+ "buttonId": buttonId,
337
+ "pressType": pressType,
338
+ "timestamp": Int(Date().timeIntervalSince1970 * 1000),
339
+ ]
340
+ Bridge.sendTypedMessage("button_press", body: body)
341
+ }
342
+
343
+ static func sendTouchEvent(deviceModel: String, gestureName: String, timestamp: Int64, source: Int32? = nil) {
344
+ var body: [String: Any] = [
345
+ "type": "touch_event",
346
+ "deviceModel": deviceModel,
347
+ "gestureName": gestureName,
348
+ "timestamp": timestamp,
349
+ ]
350
+ if let source {
351
+ body["source"] = source
352
+ }
353
+ Bridge.sendTypedMessage("touch_event", body: body)
354
+ }
355
+
356
+ static func sendAccelEvent(x: Float, y: Float, z: Float, timestamp: Int64) {
357
+ let body: [String: Any] = [
358
+ "x": x,
359
+ "y": y,
360
+ "z": z,
361
+ "timestamp": timestamp,
362
+ ]
363
+ Bridge.sendTypedMessage("accel_event", body: body)
364
+ }
365
+
366
+ static func sendSwipeVolumeStatus(enabled: Bool, timestamp: Int64) {
367
+ let body: [String: Any] = [
368
+ "enabled": enabled,
369
+ "timestamp": timestamp,
370
+ ]
371
+ Bridge.sendTypedMessage("swipe_volume_status", body: body)
372
+ }
373
+
374
+ static func sendSwitchStatus(switchType: Int, value: Int, timestamp: Int64) {
375
+ let body: [String: Any] = [
376
+ "switchType": switchType,
377
+ "switchValue": value,
378
+ "timestamp": timestamp,
379
+ ]
380
+ Bridge.sendTypedMessage("switch_status", body: body)
381
+ }
382
+
383
+ static func sendRgbLedControlResponse(requestId: String, success: Bool, error: String?) {
384
+ guard !requestId.isEmpty else { return }
385
+ var body: [String: Any] = [
386
+ "type": "rgb_led_control_response",
387
+ "requestId": requestId,
388
+ "state": success ? "success" : "error",
389
+ ]
390
+ if !success {
391
+ body["errorCode"] = error ?? "unknown_error"
392
+ }
393
+ Bridge.sendTypedMessage("rgb_led_control_response", body: body)
394
+ }
395
+
396
+ static func sendSettingsAck(_ values: [String: Any]) {
397
+ var body = values
398
+ body["type"] = "settings_ack"
399
+ Bridge.sendTypedMessage("settings_ack", body: body)
400
+ }
401
+
402
+ static func sendVideoRecordingStatus(_ values: [String: Any]) {
403
+ var body = values
404
+ body["type"] = "video_recording_status"
405
+ Bridge.sendTypedMessage("video_recording_status", body: body)
406
+ }
407
+
408
+ static func sendMediaUploadEvent(type: String, values: [String: Any]) {
409
+ var body = values
410
+ body["type"] = type
411
+ Bridge.sendTypedMessage(type, body: body)
412
+ }
413
+
414
+ static func sendVersionInfo(_ values: [String: Any]) {
415
+ var body: [String: Any] = [
416
+ "type": "version_info",
417
+ "androidVersion": stringValue(values, "androidVersion", "android_version") ?? "",
418
+ "firmwareVersion": stringValue(values, "firmwareVersion", "firmware_version") ?? "",
419
+ "besFirmwareVersion": stringValue(values, "besFirmwareVersion", "bes_fw_version") ?? "",
420
+ "mtkFirmwareVersion": stringValue(values, "mtkFirmwareVersion", "mtk_fw_version") ?? "",
421
+ "buildNumber": stringValue(values, "buildNumber", "build_number") ?? "",
422
+ "otaVersionUrl": stringValue(values, "otaVersionUrl", "ota_version_url") ?? "",
423
+ "appVersion": stringValue(values, "appVersion", "app_version") ?? "",
424
+ ]
425
+ if let systemTimeMs = intValue(values["systemTimeMs"]) ?? intValue(values["system_time_ms"]) {
426
+ body["systemTimeMs"] = systemTimeMs
427
+ }
428
+ if let hotspotOtaVersion = intValue(values["hotspotOtaVersion"])
429
+ ?? intValue(values["hotspot_ota_version"])
430
+ {
431
+ body["hotspotOtaVersion"] = hotspotOtaVersion
432
+ }
433
+ Bridge.sendTypedMessage("version_info", body: body)
434
+ }
435
+
436
+ static func sendPhotoError(requestId: String, errorCode: String, errorMessage: String) {
437
+ let timestamp = Int(Date().timeIntervalSince1970 * 1000)
438
+ var event: [String: Any] = [
439
+ "type": "photo_response",
440
+ "state": "error",
441
+ "requestId": requestId,
442
+ "timestamp": timestamp,
443
+ ]
444
+ if !errorCode.isEmpty {
445
+ event["errorCode"] = errorCode
446
+ }
447
+ if !errorMessage.isEmpty {
448
+ event["errorMessage"] = errorMessage
449
+ }
450
+ Bridge.sendTypedMessage("photo_response", body: event)
451
+ }
452
+
453
+ static func sendPhotoStatus(_ status: [String: Any]) {
454
+ Bridge.sendTypedMessage("photo_status", body: status)
455
+ }
456
+
457
+ static func sendCameraStatus(_ status: [String: Any]) {
458
+ Bridge.sendTypedMessage("camera_status", body: status)
459
+ }
460
+
461
+ static func sendPhotoResponse(_ response: [String: Any]) {
462
+ Bridge.sendTypedMessage("photo_response", body: response)
463
+ }
464
+
465
+ static func sendMiniappSelected(packageName: String) {
466
+ let event: [String: Any] = [
467
+ "packageName": packageName,
468
+ ]
469
+ Bridge.sendTypedMessage("miniapp_selected", body: event)
470
+ }
471
+
472
+ /**
473
+ * Send transcription result to server
474
+ * Used by AOSManager to send pre-formatted transcription results
475
+ * Matches the Java ServerComms structure exactly
476
+ */
477
+ static func sendLocalTranscription(transcription: [String: Any]) {
478
+ guard let text = transcription["text"] as? String, !text.isEmpty else {
479
+ Bridge.log("Skipping empty transcription result")
480
+ return
481
+ }
482
+
483
+ Bridge.sendTypedMessage("local_transcription", body: transcription)
484
+ }
485
+
486
+ // Bluetooth SDK bridge funcs:
487
+
488
+ static func sendserialNumber(_ serialNumber: String, style: String, color: String) {
489
+ let body = [
490
+ "glasses_serial_number": [
491
+ "serial_number": serialNumber,
492
+ "style": style,
493
+ "color": color,
494
+ ],
495
+ ]
496
+ Bridge.sendTypedMessage("glasses_serial_number", body: body)
497
+ }
498
+
499
+ /// `error` is the glasses' provisioning failure reason (e.g. "connect_timeout",
500
+ /// "connected_to_other_network") when this status is the verdict of a failed
501
+ /// connect attempt; nil for routine link-state updates.
502
+ static func sendWifiStatusChange(connected: Bool, ssid: String?, localIp: String?, error: String? = nil) {
503
+ guard let status = WifiStatus.fromStoreFields(
504
+ connected: connected,
505
+ ssid: ssid,
506
+ localIp: localIp
507
+ ) else {
508
+ return
509
+ }
510
+ var body = status.values
511
+ if let error {
512
+ body["error"] = error
513
+ }
514
+ Bridge.sendTypedMessage("wifi_status_change", body: body)
515
+ }
516
+
517
+ /// Claim the WiFi scan-results store for a newly requested scan. Called by the
518
+ /// SDK when it generates the scanId, BEFORE the scan command goes out: store
519
+ /// ownership is decided at request time, not by whichever chunk arrives first,
520
+ /// so a delayed chunk from an older, abandoned scan can never reset or clobber
521
+ /// the current scan's accumulator.
522
+ @MainActor
523
+ static func claimWifiScanResults(scanId: String) {
524
+ DeviceStore.shared.apply("bluetooth", "wifiScanActiveScanId", scanId)
525
+ }
526
+
527
+ static func updateWifiScanResults(
528
+ _ networks: [[String: Any]],
529
+ scanComplete: Bool,
530
+ scanId: String? = nil
531
+ ) {
532
+ // Correlated scans accumulate chunks until the terminal scan_complete, so
533
+ // chunks must reach the SDK in receive order. A Task per message can reach
534
+ // the MainActor out of creation order; DispatchQueue.main keeps the FIFO
535
+ // order of the serial bluetooth queue that delivers these.
536
+ DispatchQueue.main.async {
537
+ MainActor.assumeIsolated {
538
+ // Only chunks echoing the active scanId claimed at request time may
539
+ // mutate the store; foreign chunks are still forwarded to the SDK
540
+ // sink, which drops stale ids itself. Scan-id-less chunks (old
541
+ // firmware) keep the legacy accumulate-forever store behavior.
542
+ let ownsStore: Bool
543
+ if let scanId {
544
+ ownsStore =
545
+ scanId == DeviceStore.shared.get("bluetooth", "wifiScanActiveScanId") as? String
546
+ } else {
547
+ ownsStore = true
548
+ }
549
+ var updatedNetworks: [[String: Any]] = networks
550
+ if ownsStore {
551
+ var storedNetworks: [[String: Any]] =
552
+ DeviceStore.shared.get("bluetooth", "wifiScanResults") as? [[String: Any]] ?? []
553
+ if let scanId,
554
+ scanId != DeviceStore.shared.get("bluetooth", "wifiScanResultsScanId") as? String
555
+ {
556
+ // First chunk of a new scan: drop networks accumulated for a previous scan
557
+ // so stale entries never carry over into this scan's store.
558
+ storedNetworks = []
559
+ DeviceStore.shared.apply("bluetooth", "wifiScanResultsScanId", scanId)
560
+ }
561
+ // add the networks to the storedNetworks array, removing duplicates by ssid
562
+ for network in networks {
563
+ if !storedNetworks.contains(where: {
564
+ $0["ssid"] as? String == network["ssid"] as? String
565
+ }) {
566
+ storedNetworks.append(network)
567
+ }
568
+ }
569
+ DeviceStore.shared.apply("bluetooth", "wifiScanResults", storedNetworks)
570
+ updatedNetworks = storedNetworks
571
+ }
572
+ // Correlated scans: the SDK accumulates and dedupes chunks per scanId itself,
573
+ // so forward only this chunk; the merged store list is for UI consumers.
574
+ var body: [String: Any] = [
575
+ "networks": scanId != nil ? networks : updatedNetworks,
576
+ "scanComplete": scanComplete,
577
+ ]
578
+ if let scanId {
579
+ body["scanId"] = scanId
580
+ }
581
+ Bridge.sendTypedMessage("wifi_scan_result", body: body)
582
+ }
583
+ }
584
+ }
585
+
586
+ static func sendMtkUpdateComplete(message: String, timestamp: Int64) {
587
+ let eventBody: [String: Any] = [
588
+ "message": message,
589
+ "timestamp": timestamp,
590
+ ]
591
+ Bridge.sendTypedMessage("mtk_update_complete", body: eventBody)
592
+ }
593
+
594
+ /// Send ota_start_ack —glasses confirmed receipt of ota_start command
595
+ static func sendOtaStartAck() {
596
+ let eventBody: [String: Any] = [
597
+ "timestamp": Int64(Date().timeIntervalSince1970 * 1000),
598
+ ]
599
+ Bridge.sendTypedMessage("ota_start_ack", body: eventBody)
600
+ }
601
+
602
+ static func sendOtaStatus(
603
+ sessionId: String,
604
+ totalSteps: Int,
605
+ currentStep: Int,
606
+ stepType: String,
607
+ phase: String,
608
+ stepPercent: Int,
609
+ overallPercent: Int,
610
+ status: String,
611
+ errorMessage: String?,
612
+ glassesTimeMs: Int64? = nil
613
+ ) {
614
+ var eventBody: [String: Any] = [
615
+ "session_id": sessionId,
616
+ "total_steps": totalSteps,
617
+ "current_step": currentStep,
618
+ "step_type": stepType,
619
+ "phase": phase,
620
+ "step_percent": stepPercent,
621
+ "overall_percent": overallPercent,
622
+ "status": status,
623
+ ]
624
+ if let error = errorMessage {
625
+ eventBody["error_message"] = error
626
+ }
627
+ if let glassesTimeMs, glassesTimeMs > 0 {
628
+ eventBody["glasses_time_ms"] = glassesTimeMs
629
+ }
630
+ Bridge.sendTypedMessage("ota_status", body: eventBody)
631
+ }
632
+
633
+ /// Arbitrary WS Comms (dont use these, make a dedicated function for your use case):
634
+ static func sendWSText(_ msg: String) {
635
+ let data = ["text": msg]
636
+ Bridge.sendTypedMessage("ws_text", body: data)
637
+ }
638
+
639
+ static func sendWSBinary(_ data: Data) {
640
+ let base64String = data.base64EncodedString()
641
+ let body = ["base64": base64String]
642
+ Bridge.sendTypedMessage("ws_bin", body: body)
643
+ }
644
+
645
+ /// don't call this function directly, instead
646
+ /// make a function above that calls this function:
647
+ static func sendTypedMessage(_ type: String, body: [String: Any]) {
648
+ var body = body
649
+ body["type"] = type
650
+ if let tracePayload = tracePayloadForTypedMessage(type, body: body) {
651
+ BleTraceLogger.logMap(
652
+ direction: "phone_to_app",
653
+ layer: "sdk_event_dispatch",
654
+ type: type,
655
+ payload: tracePayload
656
+ )
657
+ }
658
+ // Send directly using type as event name - no JSON serialization
659
+ dispatchEvent(type, body)
660
+ }
661
+
662
+ private static func tracePayloadForTypedMessage(_ type: String, body: [String: Any]) -> [String: Any]? {
663
+ if type == "log" {
664
+ return nil
665
+ }
666
+ if isAudioPayloadEvent(type) {
667
+ return audioTracePayload(type, body: body)
668
+ }
669
+ return body
670
+ }
671
+
672
+ private static func isAudioPayloadEvent(_ type: String) -> Bool {
673
+ type == "mic_pcm" || type == "mic_lc3"
674
+ }
675
+
676
+ private static func audioTracePayload(_ type: String, body: [String: Any]) -> [String: Any] {
677
+ var payload: [String: Any] = [
678
+ "type": type,
679
+ "timestamp": Int(Date().timeIntervalSince1970 * 1000),
680
+ "payloadOmitted": true,
681
+ "payloadOmittedReason": "audio",
682
+ ]
683
+
684
+ switch type {
685
+ case "mic_pcm":
686
+ if let data = body["pcm"] as? Data {
687
+ payload["audioBytes"] = data.count
688
+ }
689
+ case "mic_lc3":
690
+ if let data = body["lc3"] as? Data {
691
+ payload["audioBytes"] = data.count
692
+ }
693
+ default:
694
+ break
695
+ }
696
+
697
+ for key in audioTraceMetadataKeys {
698
+ if let value = body[key] {
699
+ payload[key] = value
700
+ }
701
+ }
702
+
703
+ return payload
704
+ }
705
+ }
706
+
707
+
708
+