@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,1088 @@
1
+ @file:Suppress("FunctionName")
2
+
3
+ package com.glassly.bluetoothsdk
4
+
5
+ import androidx.lifecycle.Lifecycle
6
+ import androidx.lifecycle.LifecycleOwner
7
+ import com.glassly.bluetoothsdk.debug.BleTraceLogger
8
+ import com.glassly.bluetoothsdk.speakerid.SpeakerIdEngine
9
+ import com.glassly.bluetoothsdk.utils.DeviceTypes
10
+ import com.glassly.bluetoothsdk.utils.audio.PcmStreamManager
11
+ import expo.modules.kotlin.exception.CodedException
12
+ import expo.modules.kotlin.functions.Coroutine
13
+ import expo.modules.kotlin.modules.Module
14
+ import expo.modules.kotlin.modules.ModuleDefinition
15
+ import expo.modules.kotlin.modules.ModuleDefinitionBuilder
16
+ import kotlinx.coroutines.Dispatchers
17
+ import kotlinx.coroutines.withContext
18
+ import java.security.MessageDigest
19
+
20
+ // Expo has no module-level error mapper, so SDK-backed registrations translate
21
+ // core exceptions here while keeping Expo types out of the native SDK API.
22
+ private inline fun <T> withExpoSdkError(block: () -> T): T =
23
+ try {
24
+ block()
25
+ } catch (error: BluetoothSdkException) {
26
+ throw CodedException(error.code, error.message ?: error.code, error)
27
+ }
28
+
29
+ private suspend inline fun <T> withExpoSdkErrorSuspend(crossinline block: suspend () -> T): T =
30
+ try {
31
+ block()
32
+ } catch (error: BluetoothSdkException) {
33
+ throw CodedException(error.code, error.message ?: error.code, error)
34
+ }
35
+
36
+ private inline fun <reified R> ModuleDefinitionBuilder.SdkAsyncFunction(
37
+ name: String,
38
+ crossinline body: () -> R,
39
+ ) = AsyncFunction<R>(name) { withExpoSdkError { body() } }
40
+
41
+ private inline fun <reified R, reified P0> ModuleDefinitionBuilder.SdkAsyncFunction(
42
+ name: String,
43
+ crossinline body: (P0) -> R,
44
+ ) = AsyncFunction<R, P0>(name) { p0 -> withExpoSdkError { body(p0) } }
45
+
46
+ private inline fun <reified R, reified P0, reified P1> ModuleDefinitionBuilder.SdkAsyncFunction(
47
+ name: String,
48
+ crossinline body: (P0, P1) -> R,
49
+ ) = AsyncFunction<R, P0, P1>(name) { p0, p1 -> withExpoSdkError { body(p0, p1) } }
50
+
51
+ private inline fun <reified R, reified P0, reified P1, reified P2> ModuleDefinitionBuilder.SdkAsyncFunction(
52
+ name: String,
53
+ crossinline body: (P0, P1, P2) -> R,
54
+ ) = AsyncFunction<R, P0, P1, P2>(name) { p0, p1, p2 -> withExpoSdkError { body(p0, p1, p2) } }
55
+
56
+ private inline fun <reified R, reified P0, reified P1, reified P2, reified P3>
57
+ ModuleDefinitionBuilder.SdkAsyncFunction(
58
+ name: String,
59
+ crossinline body: (P0, P1, P2, P3) -> R,
60
+ ) = AsyncFunction<R, P0, P1, P2, P3>(name) { p0, p1, p2, p3 ->
61
+ withExpoSdkError { body(p0, p1, p2, p3) }
62
+ }
63
+
64
+ private inline fun <
65
+ reified R,
66
+ reified P0,
67
+ reified P1,
68
+ reified P2,
69
+ reified P3,
70
+ reified P4,
71
+ reified P5,
72
+ reified P6,
73
+ > ModuleDefinitionBuilder.SdkAsyncFunction(
74
+ name: String,
75
+ crossinline body: (P0, P1, P2, P3, P4, P5, P6) -> R,
76
+ ) = AsyncFunction<R, P0, P1, P2, P3, P4, P5, P6>(name) { p0, p1, p2, p3, p4, p5, p6 ->
77
+ withExpoSdkError { body(p0, p1, p2, p3, p4, p5, p6) }
78
+ }
79
+
80
+ private inline fun <reified R> ModuleDefinitionBuilder.SdkFunction(
81
+ name: String,
82
+ crossinline body: () -> R,
83
+ ) = Function<R>(name) { withExpoSdkError { body() } }
84
+
85
+ private inline fun <reified R, reified P0> ModuleDefinitionBuilder.SdkFunction(
86
+ name: String,
87
+ crossinline body: (P0) -> R,
88
+ ) = Function<R, P0>(name) { p0 -> withExpoSdkError { body(p0) } }
89
+
90
+ private inline fun <reified R> ModuleDefinitionBuilder.SdkCoroutineFunction(
91
+ name: String,
92
+ crossinline body: suspend () -> R,
93
+ ) = AsyncFunction(name) Coroutine { -> withExpoSdkErrorSuspend { body() } }
94
+
95
+ private inline fun <reified R, reified P0> ModuleDefinitionBuilder.SdkCoroutineFunction(
96
+ name: String,
97
+ crossinline body: suspend (P0) -> R,
98
+ ) = AsyncFunction(name) Coroutine { p0: P0 -> withExpoSdkErrorSuspend { body(p0) } }
99
+
100
+ private inline fun <reified R, reified P0, reified P1> ModuleDefinitionBuilder.SdkCoroutineFunction(
101
+ name: String,
102
+ crossinline body: suspend (P0, P1) -> R,
103
+ ) = AsyncFunction(name) Coroutine { p0: P0, p1: P1 -> withExpoSdkErrorSuspend { body(p0, p1) } }
104
+
105
+ private inline fun <reified R, reified P0, reified P1, reified P2> ModuleDefinitionBuilder.SdkCoroutineFunction(
106
+ name: String,
107
+ crossinline body: suspend (P0, P1, P2) -> R,
108
+ ) = AsyncFunction(name) Coroutine { p0: P0, p1: P1, p2: P2 -> withExpoSdkErrorSuspend { body(p0, p1, p2) } }
109
+
110
+ private inline fun <reified R, reified P0, reified P1, reified P2, reified P3>
111
+ ModuleDefinitionBuilder.SdkCoroutineFunction(
112
+ name: String,
113
+ crossinline body: suspend (P0, P1, P2, P3) -> R,
114
+ ) = AsyncFunction(name) Coroutine { p0: P0, p1: P1, p2: P2, p3: P3 ->
115
+ withExpoSdkErrorSuspend { body(p0, p1, p2, p3) }
116
+ }
117
+
118
+ private inline fun <
119
+ reified R,
120
+ reified P0,
121
+ reified P1,
122
+ reified P2,
123
+ reified P3,
124
+ reified P4,
125
+ reified P5,
126
+ reified P6,
127
+ > ModuleDefinitionBuilder.SdkCoroutineFunction(
128
+ name: String,
129
+ crossinline body: suspend (P0, P1, P2, P3, P4, P5, P6) -> R,
130
+ ) = AsyncFunction(name) Coroutine { p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6 ->
131
+ withExpoSdkErrorSuspend { body(p0, p1, p2, p3, p4, p5, p6) }
132
+ }
133
+
134
+ class BluetoothSdkModule : Module() {
135
+ private var sdk: BluetoothSdk? = null
136
+ private var deviceManager: DeviceManager? = null
137
+ private val sdkListener =
138
+ object : BluetoothSdkListener {
139
+ override fun onGlassesChanged(glasses: GlassesRuntimeState) {
140
+ sendEvent(
141
+ "glasses_status",
142
+ sdk?.getRawGlassesStatus()?.toMap()
143
+ ?: GlassesStatus.fromMap(DeviceStore.store.getCategory("glasses")).toMap()
144
+ )
145
+ }
146
+
147
+ override fun onSdkStateChanged(sdkState: PhoneSdkRuntimeState) {
148
+ sendEvent(
149
+ "bluetooth_status",
150
+ sdk?.getRawBluetoothStatus()?.toMap()
151
+ ?: BluetoothStatus.fromMap(
152
+ DeviceStore.store.getCategory(ObservableStore.BLUETOOTH_CATEGORY)
153
+ )
154
+ .toMap()
155
+ )
156
+ }
157
+
158
+ override fun onDeviceDiscovered(device: Device) {
159
+ sendEvent("device_discovered", device.toMap())
160
+ }
161
+
162
+ override fun onDefaultDeviceChanged(device: Device?) {
163
+ val event =
164
+ buildMap<String, Any> {
165
+ device?.let { put("device", it.toMap()) }
166
+ }
167
+ sendEvent("default_device_changed", event)
168
+ }
169
+
170
+ override fun onScanStopped(reason: ScanStopReason) {
171
+ if (reason == ScanStopReason.COMPLETED) {
172
+ val status = sdk?.getRawBluetoothStatus()
173
+ val deviceModel =
174
+ status?.pendingWearable?.takeIf { it.isNotBlank() }
175
+ ?: status?.defaultWearable
176
+ ?: ""
177
+ sendEvent(
178
+ "compatible_glasses_search_stop",
179
+ mapOf(
180
+ "type" to "compatible_glasses_search_stop",
181
+ "deviceModel" to deviceModel,
182
+ )
183
+ )
184
+ }
185
+ }
186
+
187
+ override fun onButtonPress(event: ButtonPressEvent) {
188
+ sendEvent(
189
+ "button_press",
190
+ mapOf(
191
+ "buttonId" to event.buttonId,
192
+ "pressType" to event.pressType,
193
+ "timestamp" to (event.timestamp ?: System.currentTimeMillis())
194
+ )
195
+ )
196
+ }
197
+
198
+ override fun onTouch(event: TouchEvent) {
199
+ sendEvent("touch_event", event.values)
200
+ }
201
+
202
+ override fun onHeadUpChanged(headUp: Boolean) {
203
+ sendEvent("head_up", mapOf("up" to headUp))
204
+ }
205
+
206
+ override fun onVoiceActivityDetectionStatus(event: VoiceActivityDetectionStatusEvent) {
207
+ sendEvent("voice_activity_detection_status", event.values)
208
+ }
209
+
210
+ override fun onSpeakingStatus(event: SpeakingStatusEvent) {
211
+ sendEvent("speaking_status", event.values)
212
+ }
213
+
214
+ override fun onBatteryStatus(event: BatteryStatusEvent) {
215
+ sendEvent("battery_status", event.values)
216
+ }
217
+
218
+ override fun onWifiStatusChanged(event: WifiStatusEvent) {
219
+ sendEvent("wifi_status_change", event.values)
220
+ }
221
+
222
+ override fun onHotspotStatusChanged(event: HotspotStatusEvent) {
223
+ sendEvent("hotspot_status_change", event.values)
224
+ }
225
+
226
+ override fun onHotspotError(event: HotspotErrorEvent) {
227
+ sendEvent("hotspot_error", event.values)
228
+ }
229
+
230
+ override fun onGalleryStatus(event: GalleryStatusEvent) {
231
+ sendEvent("gallery_status", event.values)
232
+ }
233
+
234
+ override fun onPhotoResponse(event: PhotoResponseEvent) {
235
+ sendEvent("photo_response", event.values)
236
+ }
237
+
238
+ override fun onPhotoStatus(event: PhotoStatusEvent) {
239
+ sendEvent("photo_status", event.values)
240
+ }
241
+
242
+ override fun onCameraStatus(event: CameraStatusEvent) {
243
+ sendEvent("camera_status", event.values)
244
+ }
245
+
246
+ override fun onVideoRecordingStatus(event: VideoRecordingStatusEvent) {
247
+ sendEvent("video_recording_status", event.values)
248
+ }
249
+
250
+ override fun onMediaUpload(event: MediaUploadEvent) {
251
+ sendEvent(event.type, event.values)
252
+ }
253
+
254
+ override fun onRgbLedControlResponse(event: RgbLedControlResponseEvent) {
255
+ sendEvent("rgb_led_control_response", event.values)
256
+ }
257
+
258
+ override fun onStreamStatus(event: StreamStatusEvent) {
259
+ sendEvent("stream_status", event.values)
260
+ }
261
+
262
+ override fun onKeepAliveAck(event: KeepAliveAckEvent) {
263
+ sendEvent("keep_alive_ack", event.values)
264
+ }
265
+
266
+ override fun onOtaStartAck(event: OtaStartAckEvent) {
267
+ sendEvent("ota_start_ack", event.values)
268
+ }
269
+
270
+ override fun onOtaStatus(event: OtaStatusEvent) {
271
+ sendEvent("ota_status", event.values)
272
+ }
273
+
274
+ override fun onSettingsAck(event: SettingsAckEvent) {
275
+ sendEvent("settings_ack", event.values)
276
+ }
277
+
278
+ override fun onVersionInfo(event: VersionInfoResult) {
279
+ sendEvent("version_info", event.toMap() + mapOf("type" to "version_info"))
280
+ }
281
+
282
+ override fun onMicPcm(event: MicPcmEvent) {
283
+ sendEvent("mic_pcm", event.toMap())
284
+ }
285
+
286
+ override fun onMicLc3(event: MicLc3Event) {
287
+ sendEvent("mic_lc3", event.toMap())
288
+ }
289
+
290
+ override fun onMicHealth(event: MicHealthEvent) {
291
+ sendEvent("mic_health", event.values)
292
+ }
293
+
294
+ override fun onLocalTranscription(event: LocalTranscriptionEvent) {
295
+ sendEvent("local_transcription", event.values)
296
+ }
297
+
298
+ override fun onLog(message: String) {
299
+ sendEvent("log", mapOf("message" to message))
300
+ }
301
+
302
+ override fun onError(error: BluetoothError) {
303
+ sendEvent("pair_failure", mapOf("error" to error.message))
304
+ }
305
+
306
+ override fun onRawEvent(eventName: String, values: Map<String, Any>) {
307
+ sendEvent(eventName, values)
308
+ }
309
+ }
310
+
311
+ private fun requireSdk(): BluetoothSdk =
312
+ sdk
313
+ ?: throw CodedException(
314
+ "sdk_not_initialized",
315
+ "Bluetooth SDK is not initialized.",
316
+ null,
317
+ )
318
+
319
+ override fun definition() = ModuleDefinition {
320
+ Name("BluetoothSdk")
321
+
322
+ // Define events that can be sent to JavaScript
323
+ Events(
324
+ "glasses_status",
325
+ "bluetooth_status",
326
+ "log",
327
+ "device_discovered",
328
+ "default_device_changed",
329
+ // Individual event handlers
330
+ "glasses_not_ready",
331
+ "button_press",
332
+ "touch_event",
333
+ "accel_event",
334
+ "compass_heading",
335
+ "compass_calibration",
336
+ "navigation_mode_change",
337
+ "navigation_view_change",
338
+ "head_up",
339
+ "voice_activity_detection_status",
340
+ "speaking_status",
341
+ "battery_status",
342
+ "local_transcription",
343
+ "wifi_status_change",
344
+ "wifi_scan_result",
345
+ "hotspot_status_change",
346
+ "hotspot_error",
347
+ "photo_response",
348
+ "photo_status",
349
+ "camera_status",
350
+ "video_recording_status",
351
+ "media_success",
352
+ "media_error",
353
+ "gallery_status",
354
+ "compatible_glasses_search_stop",
355
+ "heartbeat_sent",
356
+ "heartbeat_received",
357
+ "send_command_to_ble",
358
+ "receive_command_from_ble",
359
+ "swipe_volume_status",
360
+ "switch_status",
361
+ "rgb_led_control_response",
362
+ "settings_ack",
363
+ "version_info",
364
+ "pair_failure",
365
+ "pairing_info",
366
+ "entering_pairing_mode",
367
+ "owner_replaced",
368
+ "audio_pairing_needed",
369
+ "audio_connected",
370
+ "audio_disconnected",
371
+ "save_setting",
372
+ "speaker_detected",
373
+ "speaker_enroll_progress",
374
+ "speaker_enroll_result",
375
+ "phone_notification",
376
+ "phone_notification_dismissed",
377
+ "ws_text",
378
+ "ws_bin",
379
+ "mic_pcm",
380
+ "mic_lc3",
381
+ "mic_health",
382
+ "stream_status",
383
+ "keep_alive_ack",
384
+ "mtk_update_complete",
385
+ "glasses_session_changed",
386
+ "ota_progress",
387
+ "ota_start_ack",
388
+ "ota_status",
389
+ "ar99_ota_status",
390
+ "g2_firmware_flash_progress",
391
+ // Nex / BLE debug (NexEventUtils —Bridge.sendTypedMessage)
392
+ "send_command_to_ble",
393
+ "receive_command_from_ble",
394
+ "miniapp_selected",
395
+ "captions_tester_incident",
396
+ "extraction_progress",
397
+ )
398
+
399
+ OnCreate {
400
+ val context =
401
+ appContext.reactContext
402
+ ?: appContext.currentActivity
403
+ ?: throw IllegalStateException("No context available")
404
+ BleTraceLogger.logLifecycle(context, "BluetoothSdkModule", "module_create")
405
+ sdk =
406
+ BluetoothSdk.create(
407
+ context,
408
+ BluetoothSdkConfig(
409
+ analytics = BluetoothSdkAnalyticsConfig().withSurface("react_native")
410
+ ),
411
+ sdkListener,
412
+ )
413
+ deviceManager = DeviceManager.getInstance()
414
+ val activity = appContext.currentActivity
415
+ val activityIsResumed =
416
+ (activity as? LifecycleOwner)
417
+ ?.lifecycle
418
+ ?.currentState
419
+ ?.isAtLeast(Lifecycle.State.RESUMED) == true
420
+ if (activityIsResumed) {
421
+ deviceManager?.refreshForegroundServiceTypes()
422
+ }
423
+ }
424
+
425
+ OnActivityEntersForeground {
426
+ // Re-run after runtime permission dialogs and every app resume. This is the safe
427
+ // point to add Android's while-in-use location foreground-service type.
428
+ deviceManager?.refreshForegroundServiceTypes()
429
+ }
430
+
431
+ OnDestroy {
432
+ BleTraceLogger.logLifecycle(
433
+ appContext.reactContext ?: appContext.currentActivity,
434
+ "BluetoothSdkModule",
435
+ "module_destroy"
436
+ )
437
+ sdk?.close()
438
+ PcmStreamManager.abortAll()
439
+ sdk = null
440
+ deviceManager = null
441
+ }
442
+
443
+ // MARK: - Observable Store Functions
444
+
445
+ Function("getGlassesStatus") {
446
+ sdk?.getRawGlassesStatus()?.toMap()
447
+ ?: GlassesStatus.fromMap(DeviceStore.store.getCategory("glasses")).toMap()
448
+ }
449
+
450
+ Function("getBluetoothStatus") {
451
+ sdk?.getRawBluetoothStatus()?.toMap()
452
+ ?: BluetoothStatus.fromMap(DeviceStore.store.getCategory(ObservableStore.BLUETOOTH_CATEGORY))
453
+ .toMap()
454
+ }
455
+
456
+ Function("getDefaultDevice") { sdk?.getDefaultDevice()?.toMap() }
457
+
458
+ Function("set") { category: String, key: String, value: Any? ->
459
+ if (value != null) {
460
+ DeviceStore.apply(category, key, value)
461
+ }
462
+ }
463
+
464
+ Function("update") { category: String, values: Map<String, Any?> ->
465
+ val normalizedCategory = ObservableStore.normalizeCategory(category)
466
+ values.forEach { (key, value) ->
467
+ if (value != null) {
468
+ DeviceStore.apply(normalizedCategory, key, value)
469
+ }
470
+ }
471
+ // Persist core_token to SharedPreferences so MentraLive.getCoreToken() finds it
472
+ // (bridge may run this after glasses_ready; prefs survive retries and next connection)
473
+ // TODO: move this to the mantle:
474
+ // if (category == "bluetooth") {
475
+ // values["core_token"]?.let { token ->
476
+ // val len = (token as? String)?.length ?: 0
477
+ // android.util.Log.d("BluetoothSdkModule", "update(core) core_token received, len=$len")
478
+ // if (token is String && token.isNotEmpty()) {
479
+ // val ctx = appContext.reactContext ?: appContext.currentActivity
480
+ // ctx?.let {
481
+ // it.getSharedPreferences("augmentos_auth_prefs", android.content.Context.MODE_PRIVATE)
482
+ // .edit()
483
+ // .putString("core_token", token)
484
+ // .apply()
485
+ // android.util.Log.d("BluetoothSdkModule", "Persisted core_token to SharedPreferences, len=${token.length}")
486
+ // }
487
+ // }
488
+ // }
489
+ // }
490
+ }
491
+
492
+ // MARK: - Display Commands
493
+
494
+ SdkAsyncFunction("displayEvent") { params: Map<String, Any> ->
495
+ sdk?.displayEvent(DisplayEventRequest(params))
496
+ }
497
+
498
+ SdkAsyncFunction("displayText") { text: String, x: Int?, y: Int?, size: Int? ->
499
+ sdk?.displayText(
500
+ text = text,
501
+ x = x ?: 0,
502
+ y = y ?: 0,
503
+ size = size ?: 24,
504
+ )
505
+ }
506
+
507
+ SdkAsyncFunction("clearDisplay") { -> sdk?.clearDisplay() }
508
+
509
+ // MARK: - Connection Commands
510
+
511
+ SdkAsyncFunction("connectDefault") { -> sdk?.connectDefault() }
512
+
513
+ SdkAsyncFunction("connectDefaultWithOptions") { options: Map<String, Any> ->
514
+ sdk?.connectDefault(options.toConnectOptions())
515
+ }
516
+
517
+ SdkAsyncFunction("setDefaultDevice") { device: Map<String, Any>? ->
518
+ sdk?.setDefaultDevice(device.toDevice())
519
+ }
520
+
521
+ SdkAsyncFunction("clearDefaultDevice") { -> sdk?.clearDefaultDevice() }
522
+
523
+ SdkAsyncFunction("connectWithOptions") { device: Map<String, Any>, options: Map<String, Any> ->
524
+ sdk?.connect(
525
+ device.toDevice()
526
+ ?: throw IllegalArgumentException("connect requires a Device with model and name."),
527
+ options.toConnectOptions(),
528
+ )
529
+ }
530
+
531
+ SdkAsyncFunction("connectSimulated") { -> sdk?.connectSimulated() }
532
+
533
+ SdkAsyncFunction("disconnect") { -> sdk?.disconnect() }
534
+
535
+ SdkAsyncFunction("forget") { -> sdk?.forget() }
536
+
537
+ AsyncFunction("connectDefaultController") { deviceManager?.connectDefaultController() }
538
+
539
+ AsyncFunction("disconnectController") { deviceManager?.disconnectController() }
540
+
541
+ AsyncFunction("forgetController") { deviceManager?.forgetController() }
542
+
543
+ SdkAsyncFunction("startScan") { model: String ->
544
+ sdk?.startScan(DeviceModel.fromDeviceType(model))
545
+ }
546
+
547
+ SdkAsyncFunction("stopScan") { -> sdk?.stopScan() }
548
+
549
+ SdkAsyncFunction("cancelConnectionAttempt") { -> sdk?.cancelConnectionAttempt() }
550
+
551
+ SdkAsyncFunction("showDashboard") { -> sdk?.showDashboard() }
552
+
553
+ SdkAsyncFunction("toggleHeadUp") { -> sdk?.toggleHeadUp() }
554
+
555
+ SdkAsyncFunction("showNativeNotificationPanel") { -> sdk?.showNotificationsPanel() }
556
+
557
+ // Native navigation mode (glasses-rendered nav UI — G2 today). The JS layer
558
+ // feature-detects these by name (NativeNavigationService.isSupported), so the
559
+ // export names must match iOS exactly.
560
+ SdkAsyncFunction("navigationModeStart") { -> sdk?.navigationModeStart() }
561
+ SdkAsyncFunction("navigationModeStop") { arrived: Boolean -> sdk?.navigationModeStop(arrived) }
562
+ SdkAsyncFunction("navigationUpdateInfo") { params: Map<String, Any?> ->
563
+ sdk?.navigationUpdateInfo(params)
564
+ }
565
+ SdkAsyncFunction("navigationMiniMap") { params: Map<String, Any?> ->
566
+ sdk?.navigationMiniMap(params)
567
+ }
568
+ SdkAsyncFunction("navigationOverviewMap") { params: Map<String, Any?> ->
569
+ sdk?.navigationOverviewMap(params)
570
+ }
571
+
572
+ AsyncFunction("ping") { deviceManager?.ping() }
573
+
574
+ AsyncFunction("dbg1") {
575
+ deviceManager?.dbg1()
576
+ deviceManager?.sgc?.dbg1()
577
+ }
578
+ AsyncFunction("dbg2") {
579
+ deviceManager?.dbg2()
580
+ deviceManager?.sgc?.dbg2()
581
+ }
582
+
583
+ // Stub on Android — iOS uses this for the jetsam stress test.
584
+ Function("getMemoryMB") { -> 0.0 }
585
+
586
+ // MARK: - Incident Reporting
587
+
588
+ SdkAsyncFunction("sendIncidentId") { incidentId: String, apiBaseUrl: String? ->
589
+ sdk?.sendIncidentId(incidentId, apiBaseUrl)
590
+ }
591
+
592
+ // MARK: - WiFi Commands
593
+
594
+ SdkCoroutineFunction("requestWifiScan") { -> requireSdk().requestWifiScan().map { it.toMap() } }
595
+
596
+ SdkCoroutineFunction("sendWifiCredentials") { ssid: String, password: String ->
597
+ requireSdk().sendWifiCredentials(ssid, password).values
598
+ }
599
+
600
+ SdkCoroutineFunction("forgetWifiNetwork") { ssid: String ->
601
+ requireSdk().forgetWifiNetwork(ssid).values
602
+ }
603
+
604
+ SdkCoroutineFunction("setHotspotState") { enabled: Boolean ->
605
+ requireSdk().setHotspotState(enabled).values
606
+ }
607
+
608
+ SdkAsyncFunction("setWifiAdbState") { enabled: Boolean ->
609
+ sdk?.setWifiAdbState(enabled)
610
+ }
611
+
612
+ SdkAsyncFunction("setSystemTime") { timestampMs: Double ->
613
+ sdk?.setSystemTime(timestampMs.toLong())
614
+ }
615
+
616
+ // MARK: - Gallery Commands
617
+
618
+ SdkCoroutineFunction("setGalleryModeEnabled") { enabled: Boolean ->
619
+ requireSdk().setGalleryModeEnabled(enabled).values
620
+ }
621
+
622
+ SdkAsyncFunction("setVoiceActivityDetectionEnabled") { enabled: Boolean ->
623
+ sdk?.setVoiceActivityDetectionEnabled(enabled)
624
+ }
625
+
626
+ SdkAsyncFunction("setLoudnessGateEnabled") { enabled: Boolean ->
627
+ sdk?.setLoudnessGateEnabled(enabled)
628
+ }
629
+
630
+ @Suppress("DEPRECATION")
631
+ SdkCoroutineFunction("setPhotoCaptureDefaults") { params: Map<String, Any?> ->
632
+ requireSdk().setPhotoCaptureDefaults(params.toPhotoCaptureDefaults()).values
633
+ }
634
+
635
+ SdkCoroutineFunction("setVideoRecordingDefaults") { width: Int, height: Int, fps: Int ->
636
+ requireSdk().setVideoRecordingDefaults(VideoRecordingDefaults(width, height, fps)).values
637
+ }
638
+
639
+ SdkCoroutineFunction("setMaxVideoRecordingDuration") { minutes: Int ->
640
+ requireSdk().setMaxVideoRecordingDuration(minutes).values
641
+ }
642
+
643
+ SdkCoroutineFunction("setCameraFov") { fov: Map<String, Any> ->
644
+ val value = (fov["fov"] as? Number)?.toInt() ?: CameraFov.DEFAULT_FOV
645
+ val roiPosition = CameraRoiPosition.fromValue(
646
+ (fov["roiPosition"] as? Number)?.toInt()
647
+ ?: (fov["roi_position"] as? Number)?.toInt(),
648
+ )
649
+ requireSdk().setCameraFov(CameraFov(value, roiPosition)).values
650
+ }
651
+
652
+ SdkCoroutineFunction("setLegacyCameraFov") { fov: Map<String, Any> ->
653
+ val value = (fov["fov"] as? Number)?.toInt() ?: CameraFov.DEFAULT_FOV
654
+ val roiPosition = CameraRoiPosition.fromValue(
655
+ (fov["roiPosition"] as? Number)?.toInt()
656
+ ?: (fov["roi_position"] as? Number)?.toInt(),
657
+ )
658
+ requireSdk().setLegacyCameraFov(CameraFov(value, roiPosition)).values
659
+ }
660
+
661
+ SdkCoroutineFunction("restoreLegacyCameraFov") { ->
662
+ requireSdk().restoreLegacyCameraFov()
663
+ }
664
+
665
+ SdkCoroutineFunction("setCameraFovOverride") { params: Map<String, Any> ->
666
+ val leaseId = params["leaseId"] as? String ?: throw IllegalArgumentException("leaseId is required")
667
+ val value = (params["fov"] as? Number)?.toInt() ?: CameraFov.DEFAULT_FOV
668
+ val roiPosition = CameraRoiPosition.fromValue(
669
+ (params["roiPosition"] as? Number)?.toInt()
670
+ ?: (params["roi_position"] as? Number)?.toInt(),
671
+ )
672
+ val ttlMs = (params["ttlMs"] as? Number)?.toInt() ?: 300000
673
+ requireSdk().setCameraFovOverride(leaseId, CameraFov(value, roiPosition), ttlMs).values
674
+ }
675
+
676
+ SdkCoroutineFunction("releaseCameraFovOverride") { leaseId: String ->
677
+ requireSdk().releaseCameraFovOverride(leaseId).values
678
+ }
679
+
680
+ SdkCoroutineFunction("setCameraTuningConfig") { anrOn: Boolean, gainOn: Boolean ->
681
+ requireSdk().setCameraTuningConfig(anrOn, gainOn).values
682
+ }
683
+
684
+ SdkCoroutineFunction("queryGalleryStatus") { -> requireSdk().queryGalleryStatus().values }
685
+
686
+ SdkCoroutineFunction("requestPhoto") { params: Map<String, Any?> ->
687
+ // JS may pass null for optional fields; Map<String, Any> rejects null values at the bridge.
688
+ val sanitized =
689
+ params.mapNotNull { (key, value) ->
690
+ if (value == null) null else key to value
691
+ }.toMap()
692
+ val req = PhotoRequest.fromMap(sanitized)
693
+ Bridge.log(
694
+ "NATIVE: PHOTO PIPELINE [3/6] BluetoothSdk.requestPhoto requestId=${req.requestId} size=${req.size} mode=${req.mode.value} compress=${req.compress} sound=${req.sound} exposureTimeNs=${req.exposureTimeNs} iso=${req.iso}"
695
+ )
696
+ requireSdk().requestPhoto(req).values
697
+ }
698
+
699
+ SdkCoroutineFunction("warmUpCamera") { params: Map<String, Any?> ->
700
+ val requestId = params["requestId"] as? String
701
+ val size = PhotoSize.fromValue(params["size"] as? String)
702
+ val mode = PhotoMode.fromValue(params["mode"] as? String)
703
+ val exposureRaw = (params["exposureTimeNs"] as? Number)?.toDouble()
704
+ val exposureTimeNs =
705
+ if (exposureRaw != null && exposureRaw.isFinite() && exposureRaw > 0) exposureRaw.toLong() else null
706
+ val durationRaw = (params["durationMs"] as? Number)?.toInt() ?: 0
707
+ val durationMs = if (durationRaw > 0) durationRaw else 15000
708
+ val zsl = params["zsl"] as? Boolean
709
+ val mfnr = params["mfnr"] as? Boolean
710
+ requireSdk().warmUpCamera(requestId, size, mode, exposureTimeNs, durationMs, zsl, mfnr).values
711
+ }
712
+
713
+ SdkAsyncFunction("stopCameraWarmUp") { requestId: String ->
714
+ requireSdk().stopCameraWarmUp(requestId)
715
+ }
716
+
717
+ // MARK: - OTA Commands
718
+
719
+ SdkFunction("setOtaVersionUrl") { otaVersionUrl: String ->
720
+ requireSdk().setOtaVersionUrl(otaVersionUrl)
721
+ }
722
+
723
+ SdkFunction("getOtaVersionUrl") { -> requireSdk().getOtaVersionUrl() }
724
+
725
+ // Runs on Dispatchers.IO, not the shared Expo AsyncFunctionQueue:
726
+ // manifest fetches and version waits can block for several seconds.
727
+ SdkCoroutineFunction("checkForOtaUpdate") { ->
728
+ withContext(Dispatchers.IO) { requireSdk().checkForOtaUpdate() }
729
+ }
730
+
731
+ SdkCoroutineFunction("startOtaUpdate") { otaVersionUrl: String? ->
732
+ val sdk = requireSdk()
733
+ if (otaVersionUrl.isNullOrBlank()) {
734
+ sdk.startOtaUpdate().values
735
+ } else {
736
+ sdk.startOtaUpdate(otaVersionUrl).values
737
+ }
738
+ }
739
+
740
+ SdkCoroutineFunction("sendOtaQueryStatus") { -> requireSdk().sendOtaQueryStatus().values }
741
+
742
+ AsyncFunction("startAr99OtaFromFile") { path: String -> requireSdk().startAr99OtaFromFile(path) }
743
+
744
+ AsyncFunction("cancelAr99Ota") { requireSdk().cancelAr99Ota() }
745
+
746
+ AsyncFunction("sendAr99FactoryReset") { requireSdk().sendAr99FactoryReset() }
747
+
748
+
749
+ Function("buildAr99OtaSignature") { secret: String, appName: String, currentVersion: String, serialNumber: String, nonce: String ->
750
+ val raw = secret + appName + "juxinOTA" + currentVersion + serialNumber.trim() + nonce
751
+ val digest = MessageDigest.getInstance("MD5").digest(raw.toByteArray(Charsets.UTF_8))
752
+ digest.joinToString("") { "%02x".format(it.toInt() and 0xff) }
753
+ }
754
+ // MARK: - Version Info Commands
755
+
756
+ SdkCoroutineFunction("requestVersionInfo") { -> requireSdk().requestVersionInfo().toMap() }
757
+
758
+ SdkAsyncFunction("availableG2FirmwareArtifacts") { ->
759
+ requireSdk().availableG2FirmwareArtifacts()
760
+ }
761
+
762
+ SdkCoroutineFunction("startG2FirmwareFlash") { target: String ->
763
+ withContext(Dispatchers.IO) { requireSdk().startG2FirmwareFlash(target) }
764
+ }
765
+
766
+ // MARK: - Power Control Commands
767
+
768
+ SdkAsyncFunction("sendShutdown") { -> sdk?.sendShutdown() }
769
+
770
+ SdkAsyncFunction("sendReboot") { -> sdk?.sendReboot() }
771
+
772
+ // MARK: - Video Recording Commands
773
+
774
+ SdkCoroutineFunction("startVideoRecording") {
775
+ requestId: String,
776
+ save: Boolean,
777
+ sound: Boolean,
778
+ settings: Map<String, Any?>? ->
779
+ // Optional per-recording {width,height,fps}. Absent fields stay 0, which
780
+ // the glasses treat as "use the saved button-video default". JS numbers
781
+ // arrive as Double across the bridge, so coerce to Int.
782
+ fun dim(key: String): Int = (settings?.get(key) as? Number)?.toInt() ?: 0
783
+ requireSdk().startVideoRecording(
784
+ VideoRecordingRequest(
785
+ requestId,
786
+ save,
787
+ sound,
788
+ dim("width"),
789
+ dim("height"),
790
+ dim("fps"),
791
+ dim("maxRecordingTimeMinutes"),
792
+ )
793
+ ).values
794
+ }
795
+
796
+ // webhookUrl/authToken are supplied at stop (not start) so the token is
797
+ // fresh when the upload runs. Empty/null webhook = keep on device.
798
+ SdkCoroutineFunction("stopVideoRecording") {
799
+ requestId: String,
800
+ webhookUrl: String?,
801
+ authToken: String? ->
802
+ requireSdk().stopVideoRecording(requestId, webhookUrl, authToken).values
803
+ }
804
+
805
+ SdkCoroutineFunction("queryVideoRecordingStatus") { requestId: String ->
806
+ requireSdk().queryVideoRecordingStatus(requestId).values
807
+ }
808
+
809
+ // MARK: - Stream Commands
810
+
811
+ SdkCoroutineFunction("startStream") { params: Map<String, Any> ->
812
+ requireSdk().startStream(StreamRequest.fromMap(params)).values
813
+ }
814
+
815
+ SdkCoroutineFunction("startExternallyManagedStream") { params: Map<String, Any> ->
816
+ requireSdk().startExternallyManagedStream(StreamRequest.fromMap(params)).values
817
+ }
818
+
819
+ SdkCoroutineFunction("stopStream") { -> requireSdk().stopStream().values }
820
+
821
+ SdkAsyncFunction("sendExternallyManagedStreamKeepAlive") { params: Map<String, Any> ->
822
+ sdk?.sendExternallyManagedStreamKeepAlive(StreamKeepAliveRequest.fromMap(params))
823
+ }
824
+
825
+ // MARK: - Microphone Commands
826
+
827
+ SdkAsyncFunction("setMicState") {
828
+ enabled: Boolean,
829
+ useGlassesMic: Boolean?,
830
+ sendTranscript: Boolean?,
831
+ sendLc3Data: Boolean? ->
832
+ sdk?.setMicState(
833
+ enabled = enabled,
834
+ useGlassesMic = useGlassesMic ?: true,
835
+ sendTranscript = sendTranscript ?: false,
836
+ sendLc3Data = sendLc3Data ?: false,
837
+ )
838
+ }
839
+
840
+ // Runs on Dispatchers.IO, not the shared Expo AsyncFunctionQueue: restart()
841
+ // does a synchronous JNI model reload that would otherwise block every other
842
+ // native call in the app until it completes.
843
+ AsyncFunction("restartTranscriber") Coroutine { ->
844
+ withContext(Dispatchers.IO) { deviceManager?.restartTranscriber() }
845
+ }
846
+
847
+ // MARK: - Speaker Identification
848
+
849
+ AsyncFunction("setSpeakerIdEnabled") { enabled: Boolean ->
850
+ deviceManager?.setSpeakerIdEnabled(enabled)
851
+ }
852
+
853
+ AsyncFunction("setSpeakerIdModelPath") { path: String ->
854
+ deviceManager?.setSpeakerIdModelPath(path)
855
+ }
856
+
857
+ AsyncFunction("checkSpeakerIdModelAvailable") { ->
858
+ SpeakerIdEngine.isModelAvailable()
859
+ }
860
+
861
+ AsyncFunction("setSpeakerProfiles") { profiles: List<Map<String, Any?>> ->
862
+ deviceManager?.setSpeakerProfiles(profiles)
863
+ }
864
+
865
+ AsyncFunction("startSpeakerEnrollment") { params: Map<String, Any?> ->
866
+ val target = (params["targetSpeechSeconds"] as? Number)?.toDouble() ?: 20.0
867
+ deviceManager?.startSpeakerEnrollment(target)
868
+ }
869
+
870
+ AsyncFunction("cancelSpeakerEnrollment") { ->
871
+ deviceManager?.cancelSpeakerEnrollment()
872
+ }
873
+
874
+ // MARK: - Audio Playback Monitoring
875
+
876
+ SdkAsyncFunction("setOwnAppAudioPlaying") { playing: Boolean ->
877
+ sdk?.setOwnAppAudioPlaying(playing)
878
+ }
879
+
880
+ // MARK: - Live PCM output stream (miniapp speaker.createStream)
881
+ //
882
+ // Glassly-internal. 16-bit LE PCM chunks into a streaming AudioTrack
883
+ // (USAGE_MEDIA → follows the media route, e.g. A2DP to glasses).
884
+ // write/close run *blocking on Dispatchers.IO*, not the shared Expo
885
+ // AsyncFunctionQueue: write intentionally blocks for backpressure and
886
+ // close blocks until the backlog drains — either would otherwise stall
887
+ // every other native call queued behind them.
888
+
889
+ AsyncFunction("pcmStreamOpen") { streamId: String, sampleRate: Int, channels: Int, volume: Double ->
890
+ PcmStreamManager.open(streamId, sampleRate, channels, volume.toFloat())
891
+ }
892
+
893
+ AsyncFunction("pcmStreamWrite") Coroutine { streamId: String, base64: String ->
894
+ withContext(Dispatchers.IO) {
895
+ mapOf("bufferedMs" to PcmStreamManager.write(streamId, base64))
896
+ }
897
+ }
898
+
899
+ AsyncFunction("pcmStreamClose") Coroutine { streamId: String ->
900
+ withContext(Dispatchers.IO) {
901
+ mapOf("durationMs" to PcmStreamManager.close(streamId))
902
+ }
903
+ }
904
+
905
+ AsyncFunction("pcmStreamAbort") { streamId: String ->
906
+ PcmStreamManager.abort(streamId)
907
+ }
908
+
909
+ // *Blocking on Dispatchers.IO, not the shared AsyncFunctionQueue: these wait on
910
+ // a CountDownLatch (up to 5s) for a BLE round-trip, which would otherwise stall
911
+ // every other native call queued behind them.
912
+ AsyncFunction("getGlassesMediaVolume") Coroutine { ->
913
+ val cm = deviceManager ?: throw IllegalStateException("device_manager_null")
914
+ withContext(Dispatchers.IO) { cm.getGlassesMediaVolumeBlocking() }
915
+ }
916
+
917
+ AsyncFunction("setGlassesMediaVolume") Coroutine { level: Int ->
918
+ val cm = deviceManager ?: throw IllegalStateException("device_manager_null")
919
+ withContext(Dispatchers.IO) { cm.setGlassesMediaVolumeBlocking(level) }
920
+ }
921
+
922
+ // MARK: - RGB LED Control
923
+
924
+ SdkCoroutineFunction("rgbLedControl") {
925
+ requestId: String,
926
+ packageName: String?,
927
+ action: String,
928
+ color: String?,
929
+ onDurationMs: Int,
930
+ offDurationMs: Int,
931
+ count: Int ->
932
+ requireSdk().rgbLedControl(
933
+ RgbLedRequest(
934
+ requestId = requestId,
935
+ packageName = packageName,
936
+ action = RgbLedAction.fromValue(action),
937
+ color = RgbLedColor.fromValue(color),
938
+ onDurationMs = onDurationMs,
939
+ offDurationMs = offDurationMs,
940
+ count = count,
941
+ )
942
+ ).values
943
+ }
944
+
945
+ // MARK: - STT Commands
946
+
947
+ AsyncFunction("setSttModelDetails") { path: String, languageCode: String ->
948
+ val context =
949
+ appContext.reactContext
950
+ ?: appContext.currentActivity
951
+ ?: throw IllegalStateException("No context available")
952
+ com.glassly.bluetoothsdk.stt.STTTools.setSttModelDetails(context, path, languageCode)
953
+ }
954
+
955
+ AsyncFunction("getSttModelPath") { ->
956
+ val context =
957
+ appContext.reactContext
958
+ ?: appContext.currentActivity
959
+ ?: throw IllegalStateException("No context available")
960
+ com.glassly.bluetoothsdk.stt.STTTools.getSttModelPath(context)
961
+ }
962
+
963
+ AsyncFunction("checkSttModelAvailable") { ->
964
+ val context =
965
+ appContext.reactContext
966
+ ?: appContext.currentActivity
967
+ ?: throw IllegalStateException("No context available")
968
+ com.glassly.bluetoothsdk.stt.STTTools.checkSTTModelAvailable(context)
969
+ }
970
+
971
+ AsyncFunction("validateSttModel") { path: String ->
972
+ com.glassly.bluetoothsdk.stt.STTTools.validateSTTModel(path)
973
+ }
974
+
975
+ // Runs on Dispatchers.IO, not the shared Expo AsyncFunctionQueue: bz2/tar
976
+ // extraction of the 100—50MB model is a multi-minute, CPU-bound job. On the
977
+ // shared queue it froze every other native call in the app until it finished.
978
+ AsyncFunction("extractTarBz2") Coroutine { sourcePath: String, destinationPath: String ->
979
+ withContext(Dispatchers.IO) {
980
+ com.glassly.bluetoothsdk.stt.STTTools.extractTarBz2(sourcePath, destinationPath)
981
+ }
982
+ }
983
+
984
+ // MARK: - TTS Commands
985
+
986
+ AsyncFunction("setTtsModelDetails") { path: String, languageCode: String ->
987
+ val context =
988
+ appContext.reactContext
989
+ ?: appContext.currentActivity
990
+ ?: throw IllegalStateException("No context available")
991
+ com.glassly.core.tts.TTSTools.setTtsModelDetails(context, path, languageCode)
992
+ }
993
+
994
+ AsyncFunction("getTtsModelPath") { ->
995
+ val context =
996
+ appContext.reactContext
997
+ ?: appContext.currentActivity
998
+ ?: throw IllegalStateException("No context available")
999
+ com.glassly.core.tts.TTSTools.getTtsModelPath(context)
1000
+ }
1001
+
1002
+ AsyncFunction("getTtsModelLanguage") { ->
1003
+ val context =
1004
+ appContext.reactContext
1005
+ ?: appContext.currentActivity
1006
+ ?: throw IllegalStateException("No context available")
1007
+ com.glassly.core.tts.TTSTools.getTtsModelLanguage(context)
1008
+ }
1009
+
1010
+ AsyncFunction("checkTtsModelAvailable") { ->
1011
+ val context =
1012
+ appContext.reactContext
1013
+ ?: appContext.currentActivity
1014
+ ?: throw IllegalStateException("No context available")
1015
+ com.glassly.core.tts.TTSTools.checkTTSModelAvailable(context)
1016
+ }
1017
+
1018
+ AsyncFunction("validateTtsModel") { path: String ->
1019
+ com.glassly.core.tts.TTSTools.validateTTSModel(path)
1020
+ }
1021
+
1022
+ // Runs on Dispatchers.IO, not the shared Expo AsyncFunctionQueue: TTS synthesis
1023
+ // is a synchronous JNI call that would otherwise block other native calls.
1024
+ AsyncFunction("generateTtsAudio") Coroutine {
1025
+ text: String,
1026
+ modelPath: String,
1027
+ outputPath: String,
1028
+ speakerId: Int,
1029
+ speed: Double ->
1030
+ val context =
1031
+ appContext.reactContext
1032
+ ?: appContext.currentActivity
1033
+ ?: throw IllegalStateException("No context available")
1034
+ withContext(Dispatchers.IO) {
1035
+ com.glassly.core.tts.TTSTools.generateTtsAudio(
1036
+ context,
1037
+ text,
1038
+ modelPath,
1039
+ outputPath,
1040
+ speakerId,
1041
+ speed.toFloat()
1042
+ )
1043
+ }
1044
+ }
1045
+ }
1046
+ }
1047
+
1048
+ private fun Map<String, Any>?.toDevice(): Device? {
1049
+ val values = this ?: return null
1050
+ val model = values["model"] as? String ?: return null
1051
+ val name = values["name"] as? String ?: return null
1052
+ val address = values["address"] as? String
1053
+ val projectName = values["projectName"] as? String
1054
+ val rssi = (values["rssi"] as? Number)?.toInt()
1055
+ val id = values["id"] as? String
1056
+ return Device(
1057
+ model = DeviceModel.fromDeviceType(model),
1058
+ name = name,
1059
+ address = address?.takeIf { it.isNotBlank() },
1060
+ projectName = projectName?.takeIf { it.isNotBlank() },
1061
+ rssi = rssi,
1062
+ id = id?.takeIf { it.isNotBlank() } ?: address?.takeIf { it.isNotBlank() } ?: "$model:$name",
1063
+ )
1064
+ }
1065
+
1066
+ private fun Map<String, Any?>.toPhotoCaptureDefaults(): PhotoCaptureDefaults =
1067
+ PhotoCaptureDefaults(
1068
+ size = (this["size"] as? String)?.let { PhotoSize.fromValue(it) },
1069
+ mfnr = this["mfnr"] as? Boolean,
1070
+ zsl = this["zsl"] as? Boolean,
1071
+ noiseReduction = this["noiseReduction"] as? Boolean,
1072
+ edgeEnhancement = this["edgeEnhancement"] as? Boolean,
1073
+ ispDigitalGain = (this["ispDigitalGain"] as? Number)?.toInt(),
1074
+ ispAnalogGain = this["ispAnalogGain"] as? String,
1075
+ aeExposureDivisor = (this["aeExposureDivisor"] as? Number)?.toInt(),
1076
+ isoCap = (this["isoCap"] as? Number)?.toInt(),
1077
+ compress = this["compress"] as? String,
1078
+ sound = this["sound"] as? Boolean,
1079
+ resetCaptureTuning = this["resetCaptureTuning"] as? Boolean == true,
1080
+ )
1081
+
1082
+ private fun Map<String, Any>?.toConnectOptions(): ConnectOptions {
1083
+ val values = this ?: return ConnectOptions()
1084
+ return ConnectOptions(
1085
+ saveAsDefault = values["saveAsDefault"] as? Boolean ?: true,
1086
+ cancelExistingConnectionAttempt = values["cancelExistingConnectionAttempt"] as? Boolean ?: true,
1087
+ )
1088
+ }