@glassly/bluetooth-sdk 0.1.0-dev.100

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 (553) 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/assets/G2Firmware/g2-glassly-cfw-2.2.9.22.evenota.bin +0 -0
  139. package/android/src/main/assets/G2Firmware/g2-stock-2.2.9.22.evenota.bin +0 -0
  140. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdk.kt +2321 -0
  141. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkAnalytics.kt +216 -0
  142. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkDebug.kt +14 -0
  143. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkDefaults.kt +7 -0
  144. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkModule.kt +1087 -0
  145. package/android/src/main/java/com/glassly/bluetoothsdk/Bridge.kt +953 -0
  146. package/android/src/main/java/com/glassly/bluetoothsdk/DeviceManager.kt +2472 -0
  147. package/android/src/main/java/com/glassly/bluetoothsdk/DeviceStore.kt +359 -0
  148. package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedChangelogCatalog.kt +9 -0
  149. package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedReleaseMetadata.kt +11 -0
  150. package/android/src/main/java/com/glassly/bluetoothsdk/LocalNetworkModule.kt +414 -0
  151. package/android/src/main/java/com/glassly/bluetoothsdk/ObservableStore.kt +88 -0
  152. package/android/src/main/java/com/glassly/bluetoothsdk/OtaManifest.kt +191 -0
  153. package/android/src/main/java/com/glassly/bluetoothsdk/ReleaseChangelog.kt +61 -0
  154. package/android/src/main/java/com/glassly/bluetoothsdk/ScopedNetworkReadiness.kt +17 -0
  155. package/android/src/main/java/com/glassly/bluetoothsdk/audio/AudioModels.kt +144 -0
  156. package/android/src/main/java/com/glassly/bluetoothsdk/camera/CameraModels.kt +486 -0
  157. package/android/src/main/java/com/glassly/bluetoothsdk/connection/ConnectionModels.kt +78 -0
  158. package/android/src/main/java/com/glassly/bluetoothsdk/controllers/ControllerManager.kt +158 -0
  159. package/android/src/main/java/com/glassly/bluetoothsdk/controllers/R1.kt +1057 -0
  160. package/android/src/main/java/com/glassly/bluetoothsdk/debug/BleTraceLogger.kt +165 -0
  161. package/android/src/main/java/com/glassly/bluetoothsdk/events/BluetoothEvents.kt +178 -0
  162. package/android/src/main/java/com/glassly/bluetoothsdk/internal/MapParsing.kt +140 -0
  163. package/android/src/main/java/com/glassly/bluetoothsdk/net/LocalIpv4.kt +57 -0
  164. package/android/src/main/java/com/glassly/bluetoothsdk/otaserver/LocalOtaServer.kt +304 -0
  165. package/android/src/main/java/com/glassly/bluetoothsdk/otaserver/OtaServerModule.kt +120 -0
  166. package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistry.java +108 -0
  167. package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoUploadServer.kt +622 -0
  168. package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/PhotoReceiverModule.kt +156 -0
  169. package/android/src/main/java/com/glassly/bluetoothsdk/requests/DisplayRequests.kt +56 -0
  170. package/android/src/main/java/com/glassly/bluetoothsdk/services/Foreground.kt +272 -0
  171. package/android/src/main/java/com/glassly/bluetoothsdk/services/PhoneMic.kt +1195 -0
  172. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Ar99.java +2653 -0
  173. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/BesOtaHeartbeatGuard.kt +49 -0
  174. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/BesOtaProgressMapper.kt +27 -0
  175. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G1.kt +3837 -0
  176. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G1TextSanitizer.kt +38 -0
  177. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2.kt +6457 -0
  178. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwClassification.kt +49 -0
  179. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwRenderer.kt +1253 -0
  180. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwTextureCache.kt +270 -0
  181. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2FlashProtocol.kt +291 -0
  182. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2Flasher.kt +411 -0
  183. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/GlasslyBle.java +43189 -0
  184. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Mach1.kt +1267 -0
  185. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLive.kt +10742 -0
  186. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLiveL2capChannel.kt +274 -0
  187. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLivePairingAdvertisement.kt +54 -0
  188. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraNex.kt +2008 -0
  189. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Nimo.kt +2532 -0
  190. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/SGCManager.kt +470 -0
  191. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Simulated.kt +228 -0
  192. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/Ar99OtaManager.java +566 -0
  193. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaByteUtils.java +18 -0
  194. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaCommandConstants.java +35 -0
  195. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaCrc32Util.java +13 -0
  196. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaGattTransport.java +11 -0
  197. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaProtocol.java +92 -0
  198. package/android/src/main/java/com/glassly/bluetoothsdk/speakerid/SpeakerIdEngine.kt +525 -0
  199. package/android/src/main/java/com/glassly/bluetoothsdk/status/DeviceStatus.kt +669 -0
  200. package/android/src/main/java/com/glassly/bluetoothsdk/status/RuntimeState.kt +201 -0
  201. package/android/src/main/java/com/glassly/bluetoothsdk/status/WifiHotspotStatus.kt +189 -0
  202. package/android/src/main/java/com/glassly/bluetoothsdk/streaming/StreamModels.kt +518 -0
  203. package/android/src/main/java/com/glassly/bluetoothsdk/stt/STTTools.kt +391 -0
  204. package/android/src/main/java/com/glassly/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +518 -0
  205. package/android/src/main/java/com/glassly/bluetoothsdk/stt/VadGateSpeechPolicy.kt +227 -0
  206. package/android/src/main/java/com/glassly/bluetoothsdk/tts/TTSTools.kt +248 -0
  207. package/android/src/main/java/com/glassly/bluetoothsdk/types/DeviceModels.kt +96 -0
  208. package/android/src/main/java/com/glassly/bluetoothsdk/utils/AES.java +106 -0
  209. package/android/src/main/java/com/glassly/bluetoothsdk/utils/AudioSessionMonitor.kt +189 -0
  210. package/android/src/main/java/com/glassly/bluetoothsdk/utils/AvifExifStripper.java +573 -0
  211. package/android/src/main/java/com/glassly/bluetoothsdk/utils/BitmapJavaUtils.java +169 -0
  212. package/android/src/main/java/com/glassly/bluetoothsdk/utils/BleJsonCompact.java +496 -0
  213. package/android/src/main/java/com/glassly/bluetoothsdk/utils/BlePhotoUploadService.java +677 -0
  214. package/android/src/main/java/com/glassly/bluetoothsdk/utils/BleWireProtocol.java +108 -0
  215. package/android/src/main/java/com/glassly/bluetoothsdk/utils/Constants.kt +46 -0
  216. package/android/src/main/java/com/glassly/bluetoothsdk/utils/G1Text.kt +436 -0
  217. package/android/src/main/java/com/glassly/bluetoothsdk/utils/HeifExifTagReader.java +199 -0
  218. package/android/src/main/java/com/glassly/bluetoothsdk/utils/IncidentLogBleRelayNaming.java +29 -0
  219. package/android/src/main/java/com/glassly/bluetoothsdk/utils/IncidentLogBleUploadService.java +77 -0
  220. package/android/src/main/java/com/glassly/bluetoothsdk/utils/K900LengthCodec.java +115 -0
  221. package/android/src/main/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtils.java +827 -0
  222. package/android/src/main/java/com/glassly/bluetoothsdk/utils/MessageChunkReassembler.java +228 -0
  223. package/android/src/main/java/com/glassly/bluetoothsdk/utils/MessageChunker.java +325 -0
  224. package/android/src/main/java/com/glassly/bluetoothsdk/utils/NexSGCUtils.kt +698 -0
  225. package/android/src/main/java/com/glassly/bluetoothsdk/utils/PhoneAudioMonitor.kt +348 -0
  226. package/android/src/main/java/com/glassly/bluetoothsdk/utils/SmartGlassesConnectionState.java +9 -0
  227. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/Ar99OpusPcmDecoder.java +398 -0
  228. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/ByteUtilAudioPlayer.java +655 -0
  229. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/Lc3Player.java +441 -0
  230. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/PCMAudioPlayer.java +431 -0
  231. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/PcmStreamPlayer.kt +328 -0
  232. package/android/src/main/res/values/strings.xml +4 -0
  233. package/android/src/test/java/com/glassly/bluetoothsdk/BluetoothSdkExceptionTest.kt +18 -0
  234. package/android/src/test/java/com/glassly/bluetoothsdk/OtaManifestDowngradeTest.kt +86 -0
  235. package/android/src/test/java/com/glassly/bluetoothsdk/OtaStartResponsePolicyTest.kt +30 -0
  236. package/android/src/test/java/com/glassly/bluetoothsdk/ReleaseChangelogTest.kt +13 -0
  237. package/android/src/test/java/com/glassly/bluetoothsdk/ScopedNetworkReadinessTest.kt +39 -0
  238. package/android/src/test/java/com/glassly/bluetoothsdk/StreamStatusEventTest.kt +29 -0
  239. package/android/src/test/java/com/glassly/bluetoothsdk/camera/PhotoRequestTest.kt +141 -0
  240. package/android/src/test/java/com/glassly/bluetoothsdk/otaserver/LocalOtaServerTest.kt +82 -0
  241. package/android/src/test/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistryTest.java +75 -0
  242. package/android/src/test/java/com/glassly/bluetoothsdk/services/ForegroundServiceTypeTest.kt +69 -0
  243. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/Ar99AdvertisementMatcherTest.java +22 -0
  244. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/BesOtaHeartbeatGuardTest.kt +73 -0
  245. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/BesOtaProgressMapperTest.kt +67 -0
  246. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/EvenRleTest.kt +63 -0
  247. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G1TextSanitizerTest.kt +31 -0
  248. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwClassificationTest.kt +89 -0
  249. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwRendererTest.kt +344 -0
  250. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwTextureCacheTest.kt +200 -0
  251. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2FlashProtocolTest.kt +131 -0
  252. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/MentraLiveGattCharacteristicsTest.kt +39 -0
  253. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/MentraLivePairingAdvertisementParserTest.kt +133 -0
  254. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/NimoProtocolTest.kt +333 -0
  255. package/android/src/test/java/com/glassly/bluetoothsdk/utils/AvifExifStripperTest.java +46 -0
  256. package/android/src/test/java/com/glassly/bluetoothsdk/utils/BinaryMessageChunkerTest.java +84 -0
  257. package/android/src/test/java/com/glassly/bluetoothsdk/utils/BleJsonCompactTest.java +319 -0
  258. package/android/src/test/java/com/glassly/bluetoothsdk/utils/BlePhotoUploadServiceTest.java +107 -0
  259. package/android/src/test/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtilsEndiannessTest.java +172 -0
  260. package/android/src/test/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtilsTest.java +24 -0
  261. package/android/src/test/java/com/glassly/bluetoothsdk/utils/PhoneAudioMonitorTest.kt +45 -0
  262. package/android/src/test/resources/avif_with_exif.avif +0 -0
  263. package/app.plugin.js +3 -0
  264. package/build/BluetoothSdk.types.d.ts +1390 -0
  265. package/build/BluetoothSdk.types.d.ts.map +1 -0
  266. package/build/BluetoothSdk.types.js +41 -0
  267. package/build/BluetoothSdk.types.js.map +1 -0
  268. package/build/_internal.d.ts +17 -0
  269. package/build/_internal.d.ts.map +1 -0
  270. package/build/_internal.js +16 -0
  271. package/build/_internal.js.map +1 -0
  272. package/build/_private/BluetoothSdkModule.d.ts +171 -0
  273. package/build/_private/BluetoothSdkModule.d.ts.map +1 -0
  274. package/build/_private/BluetoothSdkModule.js +300 -0
  275. package/build/_private/BluetoothSdkModule.js.map +1 -0
  276. package/build/_private/LocalNetworkModule.d.ts +38 -0
  277. package/build/_private/LocalNetworkModule.d.ts.map +1 -0
  278. package/build/_private/LocalNetworkModule.js +3 -0
  279. package/build/_private/LocalNetworkModule.js.map +1 -0
  280. package/build/_private/cameraRequestPayload.d.ts +4 -0
  281. package/build/_private/cameraRequestPayload.d.ts.map +1 -0
  282. package/build/_private/cameraRequestPayload.js +32 -0
  283. package/build/_private/cameraRequestPayload.js.map +1 -0
  284. package/build/_private/photoRequestPayload.d.ts +6 -0
  285. package/build/_private/photoRequestPayload.d.ts.map +1 -0
  286. package/build/_private/photoRequestPayload.js +86 -0
  287. package/build/_private/photoRequestPayload.js.map +1 -0
  288. package/build/_private/sdkOtaManifest.d.ts +11 -0
  289. package/build/_private/sdkOtaManifest.d.ts.map +1 -0
  290. package/build/_private/sdkOtaManifest.js +15 -0
  291. package/build/_private/sdkOtaManifest.js.map +1 -0
  292. package/build/changelogs.d.ts +7 -0
  293. package/build/changelogs.d.ts.map +1 -0
  294. package/build/changelogs.js +46 -0
  295. package/build/changelogs.js.map +1 -0
  296. package/build/debug.d.ts +3 -0
  297. package/build/debug.d.ts.map +1 -0
  298. package/build/debug.js +8 -0
  299. package/build/debug.js.map +1 -0
  300. package/build/generated/changelogCatalog.d.ts +12 -0
  301. package/build/generated/changelogCatalog.d.ts.map +1 -0
  302. package/build/generated/changelogCatalog.js +16 -0
  303. package/build/generated/changelogCatalog.js.map +1 -0
  304. package/build/generated/releaseMetadata.d.ts +12 -0
  305. package/build/generated/releaseMetadata.d.ts.map +1 -0
  306. package/build/generated/releaseMetadata.js +10 -0
  307. package/build/generated/releaseMetadata.js.map +1 -0
  308. package/build/index.d.ts +6 -0
  309. package/build/index.d.ts.map +1 -0
  310. package/build/index.js +170 -0
  311. package/build/index.js.map +1 -0
  312. package/build/ota-server/OtaServer.types.d.ts +14 -0
  313. package/build/ota-server/OtaServer.types.d.ts.map +1 -0
  314. package/build/ota-server/OtaServer.types.js +2 -0
  315. package/build/ota-server/OtaServer.types.js.map +1 -0
  316. package/build/ota-server/OtaServerModule.d.ts +21 -0
  317. package/build/ota-server/OtaServerModule.d.ts.map +1 -0
  318. package/build/ota-server/OtaServerModule.js +3 -0
  319. package/build/ota-server/OtaServerModule.js.map +1 -0
  320. package/build/ota-server/OtaServerModule.web.d.ts +10 -0
  321. package/build/ota-server/OtaServerModule.web.d.ts.map +1 -0
  322. package/build/ota-server/OtaServerModule.web.js +12 -0
  323. package/build/ota-server/OtaServerModule.web.js.map +1 -0
  324. package/build/ota-server/index.d.ts +3 -0
  325. package/build/ota-server/index.d.ts.map +1 -0
  326. package/build/ota-server/index.js +3 -0
  327. package/build/ota-server/index.js.map +1 -0
  328. package/build/ota-transport/index.d.ts +67 -0
  329. package/build/ota-transport/index.d.ts.map +1 -0
  330. package/build/ota-transport/index.js +58 -0
  331. package/build/ota-transport/index.js.map +1 -0
  332. package/build/photo-receiver/PhotoReceiver.types.d.ts +18 -0
  333. package/build/photo-receiver/PhotoReceiver.types.d.ts.map +1 -0
  334. package/build/photo-receiver/PhotoReceiver.types.js +2 -0
  335. package/build/photo-receiver/PhotoReceiver.types.js.map +1 -0
  336. package/build/photo-receiver/PhotoReceiverModule.d.ts +10 -0
  337. package/build/photo-receiver/PhotoReceiverModule.d.ts.map +1 -0
  338. package/build/photo-receiver/PhotoReceiverModule.js +3 -0
  339. package/build/photo-receiver/PhotoReceiverModule.js.map +1 -0
  340. package/build/photo-receiver/PhotoReceiverModule.web.d.ts +10 -0
  341. package/build/photo-receiver/PhotoReceiverModule.web.d.ts.map +1 -0
  342. package/build/photo-receiver/PhotoReceiverModule.web.js +12 -0
  343. package/build/photo-receiver/PhotoReceiverModule.web.js.map +1 -0
  344. package/build/photo-receiver/index.d.ts +3 -0
  345. package/build/photo-receiver/index.d.ts.map +1 -0
  346. package/build/photo-receiver/index.js +3 -0
  347. package/build/photo-receiver/index.js.map +1 -0
  348. package/build/react/index.d.ts +5 -0
  349. package/build/react/index.d.ts.map +1 -0
  350. package/build/react/index.js +4 -0
  351. package/build/react/index.js.map +1 -0
  352. package/build/react/useBluetooth.d.ts +100 -0
  353. package/build/react/useBluetooth.d.ts.map +1 -0
  354. package/build/react/useBluetooth.js +167 -0
  355. package/build/react/useBluetooth.js.map +1 -0
  356. package/build/react/useBluetoothEvent.d.ts +6 -0
  357. package/build/react/useBluetoothEvent.d.ts.map +1 -0
  358. package/build/react/useBluetoothEvent.js +21 -0
  359. package/build/react/useBluetoothEvent.js.map +1 -0
  360. package/build/react/useBluetoothScan.d.ts +22 -0
  361. package/build/react/useBluetoothScan.d.ts.map +1 -0
  362. package/build/react/useBluetoothScan.js +135 -0
  363. package/build/react/useBluetoothScan.js.map +1 -0
  364. package/build/react/useBluetoothStatus.d.ts +16 -0
  365. package/build/react/useBluetoothStatus.d.ts.map +1 -0
  366. package/build/react/useBluetoothStatus.js +137 -0
  367. package/build/react/useBluetoothStatus.js.map +1 -0
  368. package/build/react/useGlassesConnection.d.ts +29 -0
  369. package/build/react/useGlassesConnection.d.ts.map +1 -0
  370. package/build/react/useGlassesConnection.js +153 -0
  371. package/build/react/useGlassesConnection.js.map +1 -0
  372. package/build/types/index.d.ts +3 -0
  373. package/build/types/index.d.ts.map +1 -0
  374. package/build/types/index.js +2 -0
  375. package/build/types/index.js.map +1 -0
  376. package/expo-module.config.json +14 -0
  377. package/ios/BackgroundOtaArtifactDownloader.swift +125 -0
  378. package/ios/BluetoothSdkModule.swift +1028 -0
  379. package/ios/GlasslyBluetoothSDK.podspec +106 -0
  380. package/ios/LocalIPv4.swift +150 -0
  381. package/ios/LocalOtaServer.swift +309 -0
  382. package/ios/LocalPhotoUploadServer.swift +754 -0
  383. package/ios/OtaServerModule.swift +147 -0
  384. package/ios/Packages/CoreObjC/CoreObjC.xcodeproj/project.pbxproj +213 -0
  385. package/ios/Packages/CoreObjC/PcmConverter.h +22 -0
  386. package/ios/Packages/CoreObjC/PcmConverter.m +266 -0
  387. package/ios/Packages/CoreObjC/attdet.c +92 -0
  388. package/ios/Packages/CoreObjC/attdet.h +44 -0
  389. package/ios/Packages/CoreObjC/bits.c +375 -0
  390. package/ios/Packages/CoreObjC/bits.h +315 -0
  391. package/ios/Packages/CoreObjC/bwdet.c +129 -0
  392. package/ios/Packages/CoreObjC/bwdet.h +69 -0
  393. package/ios/Packages/CoreObjC/common.h +151 -0
  394. package/ios/Packages/CoreObjC/energy.c +70 -0
  395. package/ios/Packages/CoreObjC/energy.h +43 -0
  396. package/ios/Packages/CoreObjC/fastmath.h +158 -0
  397. package/ios/Packages/CoreObjC/include/PcmConverter.h +22 -0
  398. package/ios/Packages/CoreObjC/lc3.c +704 -0
  399. package/ios/Packages/CoreObjC/lc3.h +313 -0
  400. package/ios/Packages/CoreObjC/lc3_cpp.h +283 -0
  401. package/ios/Packages/CoreObjC/lc3_private.h +163 -0
  402. package/ios/Packages/CoreObjC/ltpf.c +905 -0
  403. package/ios/Packages/CoreObjC/ltpf.h +111 -0
  404. package/ios/Packages/CoreObjC/ltpf_arm.h +506 -0
  405. package/ios/Packages/CoreObjC/ltpf_neon.h +281 -0
  406. package/ios/Packages/CoreObjC/makefile.mk +35 -0
  407. package/ios/Packages/CoreObjC/mdct.c +469 -0
  408. package/ios/Packages/CoreObjC/mdct.h +57 -0
  409. package/ios/Packages/CoreObjC/mdct_neon.h +296 -0
  410. package/ios/Packages/CoreObjC/meson.build +61 -0
  411. package/ios/Packages/CoreObjC/plc.c +61 -0
  412. package/ios/Packages/CoreObjC/plc.h +57 -0
  413. package/ios/Packages/CoreObjC/rnnoise.h +114 -0
  414. package/ios/Packages/CoreObjC/sns.c +880 -0
  415. package/ios/Packages/CoreObjC/sns.h +103 -0
  416. package/ios/Packages/CoreObjC/spec.c +907 -0
  417. package/ios/Packages/CoreObjC/spec.h +119 -0
  418. package/ios/Packages/CoreObjC/tables.c +3457 -0
  419. package/ios/Packages/CoreObjC/tables.h +94 -0
  420. package/ios/Packages/CoreObjC/tns.c +457 -0
  421. package/ios/Packages/CoreObjC/tns.h +99 -0
  422. package/ios/Packages/SherpaOnnx/Model/joiner.onnx +0 -0
  423. package/ios/Packages/SherpaOnnx/Model/tokens.txt +502 -0
  424. package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +2383 -0
  425. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +48 -0
  426. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/c-api.h +4689 -0
  427. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/cxx-api.h +2036 -0
  428. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/libsherpa-onnx.a +0 -0
  429. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/Headers/sherpa-onnx/c-api/c-api.h +4689 -0
  430. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/Headers/sherpa-onnx/c-api/cxx-api.h +2036 -0
  431. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
  432. package/ios/Packages/libbz2/module.modulemap +5 -0
  433. package/ios/Packages/libbz2/shim.h +1 -0
  434. package/ios/PhotoReceiverModule.swift +129 -0
  435. package/ios/Source/BluetoothSDK.swift +2299 -0
  436. package/ios/Source/BluetoothSDKDebug.swift +12 -0
  437. package/ios/Source/BluetoothSdkDefaults.swift +29 -0
  438. package/ios/Source/Bridge.swift +708 -0
  439. package/ios/Source/Bridging-Header.h +16 -0
  440. package/ios/Source/DeviceManager.swift +2054 -0
  441. package/ios/Source/DeviceStore.swift +350 -0
  442. package/ios/Source/GeneratedChangelogCatalog.swift +8 -0
  443. package/ios/Source/GeneratedReleaseMetadata.swift +11 -0
  444. package/ios/Source/ObservableStore.swift +118 -0
  445. package/ios/Source/OtaManifest.swift +211 -0
  446. package/ios/Source/PrivacyInfo.xcprivacy +23 -0
  447. package/ios/Source/ReleaseChangelog.swift +65 -0
  448. package/ios/Source/Resources/G2Firmware/README.md +10 -0
  449. package/ios/Source/Resources/G2Firmware/g2-glassly-cfw-2.2.9.22.evenota.bin +0 -0
  450. package/ios/Source/Resources/G2Firmware/g2-stock-2.2.9.22.evenota.bin +0 -0
  451. package/ios/Source/audio/AudioModels.swift +178 -0
  452. package/ios/Source/audio/PcmStreamPlayer.swift +410 -0
  453. package/ios/Source/camera/CameraModels.swift +866 -0
  454. package/ios/Source/connection/ScanSession.swift +27 -0
  455. package/ios/Source/controllers/ControllerManager.swift +184 -0
  456. package/ios/Source/controllers/R1.swift +925 -0
  457. package/ios/Source/errors/BluetoothSdkError.swift +19 -0
  458. package/ios/Source/events/BluetoothEvents.swift +342 -0
  459. package/ios/Source/internal/BleTraceLogger.swift +192 -0
  460. package/ios/Source/internal/BluetoothAvailability.swift +78 -0
  461. package/ios/Source/internal/BluetoothSdkAnalytics.swift +199 -0
  462. package/ios/Source/internal/ValueParsing.swift +99 -0
  463. package/ios/Source/requests/DisplayRequests.swift +82 -0
  464. package/ios/Source/services/PhoneMic.swift +662 -0
  465. package/ios/Source/sgcs/Ar99.swift +2451 -0
  466. package/ios/Source/sgcs/G1.swift +2554 -0
  467. package/ios/Source/sgcs/G2.swift +7142 -0
  468. package/ios/Source/sgcs/G2CfwClassification.swift +43 -0
  469. package/ios/Source/sgcs/G2CfwRenderer.swift +1295 -0
  470. package/ios/Source/sgcs/G2CfwTextureCache.swift +233 -0
  471. package/ios/Source/sgcs/G2FlashProtocol.swift +312 -0
  472. package/ios/Source/sgcs/G2Flasher.swift +773 -0
  473. package/ios/Source/sgcs/Mach1.swift +541 -0
  474. package/ios/Source/sgcs/MentraLive.swift +7011 -0
  475. package/ios/Source/sgcs/MentraLiveL2capChannel.swift +183 -0
  476. package/ios/Source/sgcs/MentraLivePairingAdvertisement.swift +64 -0
  477. package/ios/Source/sgcs/MentraNex.swift +3220 -0
  478. package/ios/Source/sgcs/Nimo.swift +1886 -0
  479. package/ios/Source/sgcs/SGCManager.swift +621 -0
  480. package/ios/Source/sgcs/Simulated.swift +274 -0
  481. package/ios/Source/sgcs/ar99/ota/Ar99OtaManager.swift +637 -0
  482. package/ios/Source/sgcs/glassly_ble.pb.swift +4354 -0
  483. package/ios/Source/speakerid/SpeakerIdEngine.swift +573 -0
  484. package/ios/Source/status/DeviceStatus.swift +981 -0
  485. package/ios/Source/status/RuntimeState.swift +359 -0
  486. package/ios/Source/status/WifiHotspotStatus.swift +345 -0
  487. package/ios/Source/streaming/StreamModels.swift +693 -0
  488. package/ios/Source/stt/STTTools.swift +191 -0
  489. package/ios/Source/stt/SherpaOnnxTranscriber.swift +466 -0
  490. package/ios/Source/tts/TTSTools.swift +167 -0
  491. package/ios/Source/types/DeviceModels.swift +177 -0
  492. package/ios/Source/utils/AudioSessionMonitor.swift +283 -0
  493. package/ios/Source/utils/BinaryCodec.swift +61 -0
  494. package/ios/Source/utils/BleJsonCompact.swift +405 -0
  495. package/ios/Source/utils/BleWireProtocol.swift +92 -0
  496. package/ios/Source/utils/Constants.swift +78 -0
  497. package/ios/Source/utils/Enums.swift +95 -0
  498. package/ios/Source/utils/G1Text.swift +2096 -0
  499. package/ios/Source/utils/G2NotifyFile.swift +116 -0
  500. package/ios/Source/utils/JSCExperiment.swift +241 -0
  501. package/ios/Source/utils/MemoryMonitor.swift +44 -0
  502. package/ios/Source/utils/MessageChunkReassembler.swift +190 -0
  503. package/ios/Source/utils/MessageChunker.swift +294 -0
  504. package/ios/Source/utils/Models.swift +135 -0
  505. package/ios/Source/utils/PhoneAudioMonitor.swift +230 -0
  506. package/ios/Source/utils/TarBz2Extractor.swift +257 -0
  507. package/ios/Tests/BluetoothSDKTests/G2CfwClassificationTests.swift +78 -0
  508. package/ios/Tests/BluetoothSDKTests/G2CfwRendererTests.swift +372 -0
  509. package/ios/Tests/BluetoothSDKTests/G2CfwTextureCacheTests.swift +162 -0
  510. package/ios/Tests/BluetoothSDKTests/G2FlashProtocolTests.swift +182 -0
  511. package/ios/Tests/BluetoothSDKTests/G2NotifyFileTests.swift +91 -0
  512. package/ios/Tests/MentraLivePairingAdvertisementTests.swift +160 -0
  513. package/ios/Tests/ReleaseChangelogTests.swift +13 -0
  514. package/package.json +129 -0
  515. package/plugin/build/index.d.ts +10 -0
  516. package/plugin/build/index.js +12 -0
  517. package/plugin/build/withAndroid.d.ts +3 -0
  518. package/plugin/build/withAndroid.js +190 -0
  519. package/plugin/build/withIos.d.ts +5 -0
  520. package/plugin/build/withIos.js +108 -0
  521. package/scripts/inject-ios-sdk-version.mjs +65 -0
  522. package/scripts/public-ota-api.test.mjs +37 -0
  523. package/scripts/verify-release-package.mjs +46 -0
  524. package/scripts/write-release-metadata.mjs +154 -0
  525. package/scripts/write-release-metadata.test.mjs +37 -0
  526. package/src/BluetoothSdk.types.ts +1659 -0
  527. package/src/_internal.ts +16 -0
  528. package/src/_private/BluetoothSdkModule.ts +683 -0
  529. package/src/_private/LocalNetworkModule.ts +50 -0
  530. package/src/_private/cameraRequestPayload.ts +34 -0
  531. package/src/_private/photoRequestPayload.ts +90 -0
  532. package/src/_private/sdkOtaManifest.ts +18 -0
  533. package/src/changelogs.ts +46 -0
  534. package/src/debug.ts +9 -0
  535. package/src/generated/changelogCatalog.ts +17 -0
  536. package/src/generated/releaseMetadata.ts +20 -0
  537. package/src/index.ts +320 -0
  538. package/src/ota-server/OtaServer.types.ts +10 -0
  539. package/src/ota-server/OtaServerModule.ts +23 -0
  540. package/src/ota-server/OtaServerModule.web.ts +17 -0
  541. package/src/ota-server/index.ts +2 -0
  542. package/src/ota-transport/index.ts +116 -0
  543. package/src/photo-receiver/PhotoReceiver.types.ts +20 -0
  544. package/src/photo-receiver/PhotoReceiverModule.ts +11 -0
  545. package/src/photo-receiver/PhotoReceiverModule.web.ts +17 -0
  546. package/src/photo-receiver/index.ts +2 -0
  547. package/src/react/index.ts +21 -0
  548. package/src/react/useBluetooth.ts +309 -0
  549. package/src/react/useBluetoothEvent.ts +35 -0
  550. package/src/react/useBluetoothScan.ts +173 -0
  551. package/src/react/useBluetoothStatus.ts +180 -0
  552. package/src/react/useGlassesConnection.ts +202 -0
  553. package/src/types/index.ts +12 -0
@@ -0,0 +1,1087 @@
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
+
554
+ SdkAsyncFunction("showNativeNotificationPanel") { -> sdk?.showNotificationsPanel() }
555
+
556
+ // Native navigation mode (glasses-rendered nav UI — G2 today). The JS layer
557
+ // feature-detects these by name (NativeNavigationService.isSupported), so the
558
+ // export names must match iOS exactly.
559
+ SdkAsyncFunction("navigationModeStart") { -> sdk?.navigationModeStart() }
560
+ SdkAsyncFunction("navigationModeStop") { arrived: Boolean -> sdk?.navigationModeStop(arrived) }
561
+ SdkAsyncFunction("navigationUpdateInfo") { params: Map<String, Any?> ->
562
+ sdk?.navigationUpdateInfo(params)
563
+ }
564
+ SdkAsyncFunction("navigationMiniMap") { params: Map<String, Any?> ->
565
+ sdk?.navigationMiniMap(params)
566
+ }
567
+ SdkAsyncFunction("navigationOverviewMap") { params: Map<String, Any?> ->
568
+ sdk?.navigationOverviewMap(params)
569
+ }
570
+
571
+ AsyncFunction("ping") { deviceManager?.ping() }
572
+
573
+ AsyncFunction("dbg1") {
574
+ deviceManager?.dbg1()
575
+ deviceManager?.sgc?.dbg1()
576
+ }
577
+ AsyncFunction("dbg2") {
578
+ deviceManager?.dbg2()
579
+ deviceManager?.sgc?.dbg2()
580
+ }
581
+
582
+ // Stub on Android — iOS uses this for the jetsam stress test.
583
+ Function("getMemoryMB") { -> 0.0 }
584
+
585
+ // MARK: - Incident Reporting
586
+
587
+ SdkAsyncFunction("sendIncidentId") { incidentId: String, apiBaseUrl: String? ->
588
+ sdk?.sendIncidentId(incidentId, apiBaseUrl)
589
+ }
590
+
591
+ // MARK: - WiFi Commands
592
+
593
+ SdkCoroutineFunction("requestWifiScan") { -> requireSdk().requestWifiScan().map { it.toMap() } }
594
+
595
+ SdkCoroutineFunction("sendWifiCredentials") { ssid: String, password: String ->
596
+ requireSdk().sendWifiCredentials(ssid, password).values
597
+ }
598
+
599
+ SdkCoroutineFunction("forgetWifiNetwork") { ssid: String ->
600
+ requireSdk().forgetWifiNetwork(ssid).values
601
+ }
602
+
603
+ SdkCoroutineFunction("setHotspotState") { enabled: Boolean ->
604
+ requireSdk().setHotspotState(enabled).values
605
+ }
606
+
607
+ SdkAsyncFunction("setWifiAdbState") { enabled: Boolean ->
608
+ sdk?.setWifiAdbState(enabled)
609
+ }
610
+
611
+ SdkAsyncFunction("setSystemTime") { timestampMs: Double ->
612
+ sdk?.setSystemTime(timestampMs.toLong())
613
+ }
614
+
615
+ // MARK: - Gallery Commands
616
+
617
+ SdkCoroutineFunction("setGalleryModeEnabled") { enabled: Boolean ->
618
+ requireSdk().setGalleryModeEnabled(enabled).values
619
+ }
620
+
621
+ SdkAsyncFunction("setVoiceActivityDetectionEnabled") { enabled: Boolean ->
622
+ sdk?.setVoiceActivityDetectionEnabled(enabled)
623
+ }
624
+
625
+ SdkAsyncFunction("setLoudnessGateEnabled") { enabled: Boolean ->
626
+ sdk?.setLoudnessGateEnabled(enabled)
627
+ }
628
+
629
+ @Suppress("DEPRECATION")
630
+ SdkCoroutineFunction("setPhotoCaptureDefaults") { params: Map<String, Any?> ->
631
+ requireSdk().setPhotoCaptureDefaults(params.toPhotoCaptureDefaults()).values
632
+ }
633
+
634
+ SdkCoroutineFunction("setVideoRecordingDefaults") { width: Int, height: Int, fps: Int ->
635
+ requireSdk().setVideoRecordingDefaults(VideoRecordingDefaults(width, height, fps)).values
636
+ }
637
+
638
+ SdkCoroutineFunction("setMaxVideoRecordingDuration") { minutes: Int ->
639
+ requireSdk().setMaxVideoRecordingDuration(minutes).values
640
+ }
641
+
642
+ SdkCoroutineFunction("setCameraFov") { fov: Map<String, Any> ->
643
+ val value = (fov["fov"] as? Number)?.toInt() ?: CameraFov.DEFAULT_FOV
644
+ val roiPosition = CameraRoiPosition.fromValue(
645
+ (fov["roiPosition"] as? Number)?.toInt()
646
+ ?: (fov["roi_position"] as? Number)?.toInt(),
647
+ )
648
+ requireSdk().setCameraFov(CameraFov(value, roiPosition)).values
649
+ }
650
+
651
+ SdkCoroutineFunction("setLegacyCameraFov") { fov: Map<String, Any> ->
652
+ val value = (fov["fov"] as? Number)?.toInt() ?: CameraFov.DEFAULT_FOV
653
+ val roiPosition = CameraRoiPosition.fromValue(
654
+ (fov["roiPosition"] as? Number)?.toInt()
655
+ ?: (fov["roi_position"] as? Number)?.toInt(),
656
+ )
657
+ requireSdk().setLegacyCameraFov(CameraFov(value, roiPosition)).values
658
+ }
659
+
660
+ SdkCoroutineFunction("restoreLegacyCameraFov") { ->
661
+ requireSdk().restoreLegacyCameraFov()
662
+ }
663
+
664
+ SdkCoroutineFunction("setCameraFovOverride") { params: Map<String, Any> ->
665
+ val leaseId = params["leaseId"] as? String ?: throw IllegalArgumentException("leaseId is required")
666
+ val value = (params["fov"] as? Number)?.toInt() ?: CameraFov.DEFAULT_FOV
667
+ val roiPosition = CameraRoiPosition.fromValue(
668
+ (params["roiPosition"] as? Number)?.toInt()
669
+ ?: (params["roi_position"] as? Number)?.toInt(),
670
+ )
671
+ val ttlMs = (params["ttlMs"] as? Number)?.toInt() ?: 300000
672
+ requireSdk().setCameraFovOverride(leaseId, CameraFov(value, roiPosition), ttlMs).values
673
+ }
674
+
675
+ SdkCoroutineFunction("releaseCameraFovOverride") { leaseId: String ->
676
+ requireSdk().releaseCameraFovOverride(leaseId).values
677
+ }
678
+
679
+ SdkCoroutineFunction("setCameraTuningConfig") { anrOn: Boolean, gainOn: Boolean ->
680
+ requireSdk().setCameraTuningConfig(anrOn, gainOn).values
681
+ }
682
+
683
+ SdkCoroutineFunction("queryGalleryStatus") { -> requireSdk().queryGalleryStatus().values }
684
+
685
+ SdkCoroutineFunction("requestPhoto") { params: Map<String, Any?> ->
686
+ // JS may pass null for optional fields; Map<String, Any> rejects null values at the bridge.
687
+ val sanitized =
688
+ params.mapNotNull { (key, value) ->
689
+ if (value == null) null else key to value
690
+ }.toMap()
691
+ val req = PhotoRequest.fromMap(sanitized)
692
+ Bridge.log(
693
+ "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}"
694
+ )
695
+ requireSdk().requestPhoto(req).values
696
+ }
697
+
698
+ SdkCoroutineFunction("warmUpCamera") { params: Map<String, Any?> ->
699
+ val requestId = params["requestId"] as? String
700
+ val size = PhotoSize.fromValue(params["size"] as? String)
701
+ val mode = PhotoMode.fromValue(params["mode"] as? String)
702
+ val exposureRaw = (params["exposureTimeNs"] as? Number)?.toDouble()
703
+ val exposureTimeNs =
704
+ if (exposureRaw != null && exposureRaw.isFinite() && exposureRaw > 0) exposureRaw.toLong() else null
705
+ val durationRaw = (params["durationMs"] as? Number)?.toInt() ?: 0
706
+ val durationMs = if (durationRaw > 0) durationRaw else 15000
707
+ val zsl = params["zsl"] as? Boolean
708
+ val mfnr = params["mfnr"] as? Boolean
709
+ requireSdk().warmUpCamera(requestId, size, mode, exposureTimeNs, durationMs, zsl, mfnr).values
710
+ }
711
+
712
+ SdkAsyncFunction("stopCameraWarmUp") { requestId: String ->
713
+ requireSdk().stopCameraWarmUp(requestId)
714
+ }
715
+
716
+ // MARK: - OTA Commands
717
+
718
+ SdkFunction("setOtaVersionUrl") { otaVersionUrl: String ->
719
+ requireSdk().setOtaVersionUrl(otaVersionUrl)
720
+ }
721
+
722
+ SdkFunction("getOtaVersionUrl") { -> requireSdk().getOtaVersionUrl() }
723
+
724
+ // Runs on Dispatchers.IO, not the shared Expo AsyncFunctionQueue:
725
+ // manifest fetches and version waits can block for several seconds.
726
+ SdkCoroutineFunction("checkForOtaUpdate") { ->
727
+ withContext(Dispatchers.IO) { requireSdk().checkForOtaUpdate() }
728
+ }
729
+
730
+ SdkCoroutineFunction("startOtaUpdate") { otaVersionUrl: String? ->
731
+ val sdk = requireSdk()
732
+ if (otaVersionUrl.isNullOrBlank()) {
733
+ sdk.startOtaUpdate().values
734
+ } else {
735
+ sdk.startOtaUpdate(otaVersionUrl).values
736
+ }
737
+ }
738
+
739
+ SdkCoroutineFunction("sendOtaQueryStatus") { -> requireSdk().sendOtaQueryStatus().values }
740
+
741
+ AsyncFunction("startAr99OtaFromFile") { path: String -> requireSdk().startAr99OtaFromFile(path) }
742
+
743
+ AsyncFunction("cancelAr99Ota") { requireSdk().cancelAr99Ota() }
744
+
745
+ AsyncFunction("sendAr99FactoryReset") { requireSdk().sendAr99FactoryReset() }
746
+
747
+
748
+ Function("buildAr99OtaSignature") { secret: String, appName: String, currentVersion: String, serialNumber: String, nonce: String ->
749
+ val raw = secret + appName + "juxinOTA" + currentVersion + serialNumber.trim() + nonce
750
+ val digest = MessageDigest.getInstance("MD5").digest(raw.toByteArray(Charsets.UTF_8))
751
+ digest.joinToString("") { "%02x".format(it.toInt() and 0xff) }
752
+ }
753
+ // MARK: - Version Info Commands
754
+
755
+ SdkCoroutineFunction("requestVersionInfo") { -> requireSdk().requestVersionInfo().toMap() }
756
+
757
+ SdkAsyncFunction("availableG2FirmwareArtifacts") { ->
758
+ requireSdk().availableG2FirmwareArtifacts()
759
+ }
760
+
761
+ SdkCoroutineFunction("startG2FirmwareFlash") { target: String ->
762
+ withContext(Dispatchers.IO) { requireSdk().startG2FirmwareFlash(target) }
763
+ }
764
+
765
+ // MARK: - Power Control Commands
766
+
767
+ SdkAsyncFunction("sendShutdown") { -> sdk?.sendShutdown() }
768
+
769
+ SdkAsyncFunction("sendReboot") { -> sdk?.sendReboot() }
770
+
771
+ // MARK: - Video Recording Commands
772
+
773
+ SdkCoroutineFunction("startVideoRecording") {
774
+ requestId: String,
775
+ save: Boolean,
776
+ sound: Boolean,
777
+ settings: Map<String, Any?>? ->
778
+ // Optional per-recording {width,height,fps}. Absent fields stay 0, which
779
+ // the glasses treat as "use the saved button-video default". JS numbers
780
+ // arrive as Double across the bridge, so coerce to Int.
781
+ fun dim(key: String): Int = (settings?.get(key) as? Number)?.toInt() ?: 0
782
+ requireSdk().startVideoRecording(
783
+ VideoRecordingRequest(
784
+ requestId,
785
+ save,
786
+ sound,
787
+ dim("width"),
788
+ dim("height"),
789
+ dim("fps"),
790
+ dim("maxRecordingTimeMinutes"),
791
+ )
792
+ ).values
793
+ }
794
+
795
+ // webhookUrl/authToken are supplied at stop (not start) so the token is
796
+ // fresh when the upload runs. Empty/null webhook = keep on device.
797
+ SdkCoroutineFunction("stopVideoRecording") {
798
+ requestId: String,
799
+ webhookUrl: String?,
800
+ authToken: String? ->
801
+ requireSdk().stopVideoRecording(requestId, webhookUrl, authToken).values
802
+ }
803
+
804
+ SdkCoroutineFunction("queryVideoRecordingStatus") { requestId: String ->
805
+ requireSdk().queryVideoRecordingStatus(requestId).values
806
+ }
807
+
808
+ // MARK: - Stream Commands
809
+
810
+ SdkCoroutineFunction("startStream") { params: Map<String, Any> ->
811
+ requireSdk().startStream(StreamRequest.fromMap(params)).values
812
+ }
813
+
814
+ SdkCoroutineFunction("startExternallyManagedStream") { params: Map<String, Any> ->
815
+ requireSdk().startExternallyManagedStream(StreamRequest.fromMap(params)).values
816
+ }
817
+
818
+ SdkCoroutineFunction("stopStream") { -> requireSdk().stopStream().values }
819
+
820
+ SdkAsyncFunction("sendExternallyManagedStreamKeepAlive") { params: Map<String, Any> ->
821
+ sdk?.sendExternallyManagedStreamKeepAlive(StreamKeepAliveRequest.fromMap(params))
822
+ }
823
+
824
+ // MARK: - Microphone Commands
825
+
826
+ SdkAsyncFunction("setMicState") {
827
+ enabled: Boolean,
828
+ useGlassesMic: Boolean?,
829
+ sendTranscript: Boolean?,
830
+ sendLc3Data: Boolean? ->
831
+ sdk?.setMicState(
832
+ enabled = enabled,
833
+ useGlassesMic = useGlassesMic ?: true,
834
+ sendTranscript = sendTranscript ?: false,
835
+ sendLc3Data = sendLc3Data ?: false,
836
+ )
837
+ }
838
+
839
+ // Runs on Dispatchers.IO, not the shared Expo AsyncFunctionQueue: restart()
840
+ // does a synchronous JNI model reload that would otherwise block every other
841
+ // native call in the app until it completes.
842
+ AsyncFunction("restartTranscriber") Coroutine { ->
843
+ withContext(Dispatchers.IO) { deviceManager?.restartTranscriber() }
844
+ }
845
+
846
+ // MARK: - Speaker Identification
847
+
848
+ AsyncFunction("setSpeakerIdEnabled") { enabled: Boolean ->
849
+ deviceManager?.setSpeakerIdEnabled(enabled)
850
+ }
851
+
852
+ AsyncFunction("setSpeakerIdModelPath") { path: String ->
853
+ deviceManager?.setSpeakerIdModelPath(path)
854
+ }
855
+
856
+ AsyncFunction("checkSpeakerIdModelAvailable") { ->
857
+ SpeakerIdEngine.isModelAvailable()
858
+ }
859
+
860
+ AsyncFunction("setSpeakerProfiles") { profiles: List<Map<String, Any?>> ->
861
+ deviceManager?.setSpeakerProfiles(profiles)
862
+ }
863
+
864
+ AsyncFunction("startSpeakerEnrollment") { params: Map<String, Any?> ->
865
+ val target = (params["targetSpeechSeconds"] as? Number)?.toDouble() ?: 20.0
866
+ deviceManager?.startSpeakerEnrollment(target)
867
+ }
868
+
869
+ AsyncFunction("cancelSpeakerEnrollment") { ->
870
+ deviceManager?.cancelSpeakerEnrollment()
871
+ }
872
+
873
+ // MARK: - Audio Playback Monitoring
874
+
875
+ SdkAsyncFunction("setOwnAppAudioPlaying") { playing: Boolean ->
876
+ sdk?.setOwnAppAudioPlaying(playing)
877
+ }
878
+
879
+ // MARK: - Live PCM output stream (miniapp speaker.createStream)
880
+ //
881
+ // Glassly-internal. 16-bit LE PCM chunks into a streaming AudioTrack
882
+ // (USAGE_MEDIA → follows the media route, e.g. A2DP to glasses).
883
+ // write/close run *blocking on Dispatchers.IO*, not the shared Expo
884
+ // AsyncFunctionQueue: write intentionally blocks for backpressure and
885
+ // close blocks until the backlog drains — either would otherwise stall
886
+ // every other native call queued behind them.
887
+
888
+ AsyncFunction("pcmStreamOpen") { streamId: String, sampleRate: Int, channels: Int, volume: Double ->
889
+ PcmStreamManager.open(streamId, sampleRate, channels, volume.toFloat())
890
+ }
891
+
892
+ AsyncFunction("pcmStreamWrite") Coroutine { streamId: String, base64: String ->
893
+ withContext(Dispatchers.IO) {
894
+ mapOf("bufferedMs" to PcmStreamManager.write(streamId, base64))
895
+ }
896
+ }
897
+
898
+ AsyncFunction("pcmStreamClose") Coroutine { streamId: String ->
899
+ withContext(Dispatchers.IO) {
900
+ mapOf("durationMs" to PcmStreamManager.close(streamId))
901
+ }
902
+ }
903
+
904
+ AsyncFunction("pcmStreamAbort") { streamId: String ->
905
+ PcmStreamManager.abort(streamId)
906
+ }
907
+
908
+ // *Blocking on Dispatchers.IO, not the shared AsyncFunctionQueue: these wait on
909
+ // a CountDownLatch (up to 5s) for a BLE round-trip, which would otherwise stall
910
+ // every other native call queued behind them.
911
+ AsyncFunction("getGlassesMediaVolume") Coroutine { ->
912
+ val cm = deviceManager ?: throw IllegalStateException("device_manager_null")
913
+ withContext(Dispatchers.IO) { cm.getGlassesMediaVolumeBlocking() }
914
+ }
915
+
916
+ AsyncFunction("setGlassesMediaVolume") Coroutine { level: Int ->
917
+ val cm = deviceManager ?: throw IllegalStateException("device_manager_null")
918
+ withContext(Dispatchers.IO) { cm.setGlassesMediaVolumeBlocking(level) }
919
+ }
920
+
921
+ // MARK: - RGB LED Control
922
+
923
+ SdkCoroutineFunction("rgbLedControl") {
924
+ requestId: String,
925
+ packageName: String?,
926
+ action: String,
927
+ color: String?,
928
+ onDurationMs: Int,
929
+ offDurationMs: Int,
930
+ count: Int ->
931
+ requireSdk().rgbLedControl(
932
+ RgbLedRequest(
933
+ requestId = requestId,
934
+ packageName = packageName,
935
+ action = RgbLedAction.fromValue(action),
936
+ color = RgbLedColor.fromValue(color),
937
+ onDurationMs = onDurationMs,
938
+ offDurationMs = offDurationMs,
939
+ count = count,
940
+ )
941
+ ).values
942
+ }
943
+
944
+ // MARK: - STT Commands
945
+
946
+ AsyncFunction("setSttModelDetails") { path: String, languageCode: String ->
947
+ val context =
948
+ appContext.reactContext
949
+ ?: appContext.currentActivity
950
+ ?: throw IllegalStateException("No context available")
951
+ com.glassly.bluetoothsdk.stt.STTTools.setSttModelDetails(context, path, languageCode)
952
+ }
953
+
954
+ AsyncFunction("getSttModelPath") { ->
955
+ val context =
956
+ appContext.reactContext
957
+ ?: appContext.currentActivity
958
+ ?: throw IllegalStateException("No context available")
959
+ com.glassly.bluetoothsdk.stt.STTTools.getSttModelPath(context)
960
+ }
961
+
962
+ AsyncFunction("checkSttModelAvailable") { ->
963
+ val context =
964
+ appContext.reactContext
965
+ ?: appContext.currentActivity
966
+ ?: throw IllegalStateException("No context available")
967
+ com.glassly.bluetoothsdk.stt.STTTools.checkSTTModelAvailable(context)
968
+ }
969
+
970
+ AsyncFunction("validateSttModel") { path: String ->
971
+ com.glassly.bluetoothsdk.stt.STTTools.validateSTTModel(path)
972
+ }
973
+
974
+ // Runs on Dispatchers.IO, not the shared Expo AsyncFunctionQueue: bz2/tar
975
+ // extraction of the 100—50MB model is a multi-minute, CPU-bound job. On the
976
+ // shared queue it froze every other native call in the app until it finished.
977
+ AsyncFunction("extractTarBz2") Coroutine { sourcePath: String, destinationPath: String ->
978
+ withContext(Dispatchers.IO) {
979
+ com.glassly.bluetoothsdk.stt.STTTools.extractTarBz2(sourcePath, destinationPath)
980
+ }
981
+ }
982
+
983
+ // MARK: - TTS Commands
984
+
985
+ AsyncFunction("setTtsModelDetails") { path: String, languageCode: String ->
986
+ val context =
987
+ appContext.reactContext
988
+ ?: appContext.currentActivity
989
+ ?: throw IllegalStateException("No context available")
990
+ com.glassly.core.tts.TTSTools.setTtsModelDetails(context, path, languageCode)
991
+ }
992
+
993
+ AsyncFunction("getTtsModelPath") { ->
994
+ val context =
995
+ appContext.reactContext
996
+ ?: appContext.currentActivity
997
+ ?: throw IllegalStateException("No context available")
998
+ com.glassly.core.tts.TTSTools.getTtsModelPath(context)
999
+ }
1000
+
1001
+ AsyncFunction("getTtsModelLanguage") { ->
1002
+ val context =
1003
+ appContext.reactContext
1004
+ ?: appContext.currentActivity
1005
+ ?: throw IllegalStateException("No context available")
1006
+ com.glassly.core.tts.TTSTools.getTtsModelLanguage(context)
1007
+ }
1008
+
1009
+ AsyncFunction("checkTtsModelAvailable") { ->
1010
+ val context =
1011
+ appContext.reactContext
1012
+ ?: appContext.currentActivity
1013
+ ?: throw IllegalStateException("No context available")
1014
+ com.glassly.core.tts.TTSTools.checkTTSModelAvailable(context)
1015
+ }
1016
+
1017
+ AsyncFunction("validateTtsModel") { path: String ->
1018
+ com.glassly.core.tts.TTSTools.validateTTSModel(path)
1019
+ }
1020
+
1021
+ // Runs on Dispatchers.IO, not the shared Expo AsyncFunctionQueue: TTS synthesis
1022
+ // is a synchronous JNI call that would otherwise block other native calls.
1023
+ AsyncFunction("generateTtsAudio") Coroutine {
1024
+ text: String,
1025
+ modelPath: String,
1026
+ outputPath: String,
1027
+ speakerId: Int,
1028
+ speed: Double ->
1029
+ val context =
1030
+ appContext.reactContext
1031
+ ?: appContext.currentActivity
1032
+ ?: throw IllegalStateException("No context available")
1033
+ withContext(Dispatchers.IO) {
1034
+ com.glassly.core.tts.TTSTools.generateTtsAudio(
1035
+ context,
1036
+ text,
1037
+ modelPath,
1038
+ outputPath,
1039
+ speakerId,
1040
+ speed.toFloat()
1041
+ )
1042
+ }
1043
+ }
1044
+ }
1045
+ }
1046
+
1047
+ private fun Map<String, Any>?.toDevice(): Device? {
1048
+ val values = this ?: return null
1049
+ val model = values["model"] as? String ?: return null
1050
+ val name = values["name"] as? String ?: return null
1051
+ val address = values["address"] as? String
1052
+ val projectName = values["projectName"] as? String
1053
+ val rssi = (values["rssi"] as? Number)?.toInt()
1054
+ val id = values["id"] as? String
1055
+ return Device(
1056
+ model = DeviceModel.fromDeviceType(model),
1057
+ name = name,
1058
+ address = address?.takeIf { it.isNotBlank() },
1059
+ projectName = projectName?.takeIf { it.isNotBlank() },
1060
+ rssi = rssi,
1061
+ id = id?.takeIf { it.isNotBlank() } ?: address?.takeIf { it.isNotBlank() } ?: "$model:$name",
1062
+ )
1063
+ }
1064
+
1065
+ private fun Map<String, Any?>.toPhotoCaptureDefaults(): PhotoCaptureDefaults =
1066
+ PhotoCaptureDefaults(
1067
+ size = (this["size"] as? String)?.let { PhotoSize.fromValue(it) },
1068
+ mfnr = this["mfnr"] as? Boolean,
1069
+ zsl = this["zsl"] as? Boolean,
1070
+ noiseReduction = this["noiseReduction"] as? Boolean,
1071
+ edgeEnhancement = this["edgeEnhancement"] as? Boolean,
1072
+ ispDigitalGain = (this["ispDigitalGain"] as? Number)?.toInt(),
1073
+ ispAnalogGain = this["ispAnalogGain"] as? String,
1074
+ aeExposureDivisor = (this["aeExposureDivisor"] as? Number)?.toInt(),
1075
+ isoCap = (this["isoCap"] as? Number)?.toInt(),
1076
+ compress = this["compress"] as? String,
1077
+ sound = this["sound"] as? Boolean,
1078
+ resetCaptureTuning = this["resetCaptureTuning"] as? Boolean == true,
1079
+ )
1080
+
1081
+ private fun Map<String, Any>?.toConnectOptions(): ConnectOptions {
1082
+ val values = this ?: return ConnectOptions()
1083
+ return ConnectOptions(
1084
+ saveAsDefault = values["saveAsDefault"] as? Boolean ?: true,
1085
+ cancelExistingConnectionAttempt = values["cancelExistingConnectionAttempt"] as? Boolean ?: true,
1086
+ )
1087
+ }