@mentra/bluetooth-sdk 0.1.0

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 (278) hide show
  1. package/README.md +278 -0
  2. package/android/build.gradle +167 -0
  3. package/android/lc3Lib/CMakeLists.txt +6 -0
  4. package/android/lc3Lib/build.gradle +109 -0
  5. package/android/lc3Lib/proguard-rules.pro +33 -0
  6. package/android/lc3Lib/src/main/AndroidManifest.xml +2 -0
  7. package/android/lc3Lib/src/main/cpp/CMakeLists.txt +8 -0
  8. package/android/lc3Lib/src/main/cpp/google_opus_stuff/CMakeLists.txt +30 -0
  9. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/CMakeLists.txt +7 -0
  10. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.cc +96 -0
  11. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.h +53 -0
  12. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/Makefile.am +6 -0
  13. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h +26 -0
  14. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h.in +26 -0
  15. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/ogg.h +209 -0
  16. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/os_types.h +158 -0
  17. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus.h +981 -0
  18. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_custom.h +342 -0
  19. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_defines.h +799 -0
  20. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_multistream.h +660 -0
  21. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_projection.h +568 -0
  22. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_types.h +166 -0
  23. package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.cc +268 -0
  24. package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.h +115 -0
  25. package/android/lc3Lib/src/main/cpp/google_opus_stuff/opus_tools/opus_header.h +59 -0
  26. package/android/lc3Lib/src/main/cpp/liblc3/CMakeLists.txt +38 -0
  27. package/android/lc3Lib/src/main/cpp/liblc3/include/lc3.h +309 -0
  28. package/android/lc3Lib/src/main/cpp/liblc3/include/lc3_private.h +162 -0
  29. package/android/lc3Lib/src/main/cpp/liblc3/include/rnnoise.h +114 -0
  30. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/CMakeLists.txt +19 -0
  31. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.c +92 -0
  32. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.h +44 -0
  33. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.c +375 -0
  34. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.h +315 -0
  35. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.c +129 -0
  36. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.h +69 -0
  37. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/common.h +148 -0
  38. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.c +70 -0
  39. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.h +43 -0
  40. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/fastmath.h +158 -0
  41. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/lc3.c +702 -0
  42. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.c +893 -0
  43. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.h +111 -0
  44. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_arm.h +506 -0
  45. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_neon.h +281 -0
  46. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/makefile.mk +35 -0
  47. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.c +452 -0
  48. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.h +57 -0
  49. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct_neon.h +296 -0
  50. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/meson.build +46 -0
  51. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.c +61 -0
  52. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.h +57 -0
  53. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.c +880 -0
  54. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.h +103 -0
  55. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.c +904 -0
  56. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.h +119 -0
  57. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.c +3457 -0
  58. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.h +94 -0
  59. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.c +457 -0
  60. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.h +99 -0
  61. package/android/lc3Lib/src/main/cpp/liblc3/liblc3.cpp +159 -0
  62. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/_kiss_fft_guts.h +182 -0
  63. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/arch.h +261 -0
  64. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.c +279 -0
  65. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.h +59 -0
  66. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/common.h +48 -0
  67. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/compile.sh +3 -0
  68. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/denoise.c +646 -0
  69. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.c +601 -0
  70. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.h +203 -0
  71. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/opus_types.h +159 -0
  72. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.c +526 -0
  73. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.h +149 -0
  74. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.c +178 -0
  75. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.h +69 -0
  76. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.c +11051 -0
  77. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.h +34 -0
  78. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_reader.c +168 -0
  79. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_train.py +66 -0
  80. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/tansig_table.h +45 -0
  81. package/android/lc3Lib/src/main/java/com/mentra/lc3Lib/Lc3Cpp.java +38 -0
  82. package/android/lc3Lib/third_party/CMakeLists.txt +23 -0
  83. package/android/lc3Lib/third_party/CMakeLists_libogg.txt +18 -0
  84. package/android/lc3Lib/third_party/CMakeLists_libopus.txt +18 -0
  85. package/android/lc3Lib/third_party/CMakeLists_opus-tools.txt +23 -0
  86. package/android/lc3Lib/third_party/opus_tools/src/AUTHORS +5 -0
  87. package/android/lc3Lib/third_party/opus_tools/src/CMakeLists.txt +4 -0
  88. package/android/lc3Lib/third_party/opus_tools/src/COPYING +371 -0
  89. package/android/lc3Lib/third_party/opus_tools/src/ChangeLog +3 -0
  90. package/android/lc3Lib/third_party/opus_tools/src/Makefile.am +42 -0
  91. package/android/lc3Lib/third_party/opus_tools/src/Makefile.unix +23 -0
  92. package/android/lc3Lib/third_party/opus_tools/src/NEWS +0 -0
  93. package/android/lc3Lib/third_party/opus_tools/src/README +0 -0
  94. package/android/lc3Lib/third_party/opus_tools/src/autogen.sh +115 -0
  95. package/android/lc3Lib/third_party/opus_tools/src/configure.ac +293 -0
  96. package/android/lc3Lib/third_party/opus_tools/src/src/arch.h +239 -0
  97. package/android/lc3Lib/third_party/opus_tools/src/src/audio-in.c +1046 -0
  98. package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.c +245 -0
  99. package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.h +28 -0
  100. package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.c +320 -0
  101. package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.h +51 -0
  102. package/android/lc3Lib/third_party/opus_tools/src/src/lpc.c +157 -0
  103. package/android/lc3Lib/third_party/opus_tools/src/src/lpc.h +27 -0
  104. package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.c +286 -0
  105. package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.h +59 -0
  106. package/android/lc3Lib/third_party/opus_tools/src/src/opusdec.c +884 -0
  107. package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.c +1021 -0
  108. package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.h +101 -0
  109. package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.c +639 -0
  110. package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.h +51 -0
  111. package/android/lc3Lib/third_party/opus_tools/src/src/os_support.h +167 -0
  112. package/android/lc3Lib/third_party/opus_tools/src/src/resample.c +1137 -0
  113. package/android/lc3Lib/third_party/opus_tools/src/src/speex_resampler.h +344 -0
  114. package/android/lc3Lib/third_party/opus_tools/src/src/stack_alloc.h +115 -0
  115. package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.c +125 -0
  116. package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.h +62 -0
  117. package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.c +223 -0
  118. package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.h +60 -0
  119. package/android/settings.gradle +1 -0
  120. package/android/src/main/AndroidManifest.xml +40 -0
  121. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +528 -0
  122. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +610 -0
  123. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +1616 -0
  124. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +314 -0
  125. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +1710 -0
  126. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +554 -0
  127. package/android/src/main/java/com/mentra/bluetoothsdk/ObservableStore.kt +68 -0
  128. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +158 -0
  129. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +934 -0
  130. package/android/src/main/java/com/mentra/bluetoothsdk/services/Foreground.kt +175 -0
  131. package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +1109 -0
  132. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +3974 -0
  133. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3551 -0
  134. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1327 -0
  135. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +6959 -0
  136. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1655 -0
  137. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraosBle.java +53675 -0
  138. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +202 -0
  139. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +224 -0
  140. package/android/src/main/java/com/mentra/bluetoothsdk/stt/STTTools.kt +340 -0
  141. package/android/src/main/java/com/mentra/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +465 -0
  142. package/android/src/main/java/com/mentra/bluetoothsdk/stt/VadGateSpeechPolicy.kt +221 -0
  143. package/android/src/main/java/com/mentra/bluetoothsdk/utils/AES.java +106 -0
  144. package/android/src/main/java/com/mentra/bluetoothsdk/utils/AudioSessionMonitor.kt +189 -0
  145. package/android/src/main/java/com/mentra/bluetoothsdk/utils/BitmapJavaUtils.java +169 -0
  146. package/android/src/main/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadService.java +179 -0
  147. package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +44 -0
  148. package/android/src/main/java/com/mentra/bluetoothsdk/utils/G1Text.kt +436 -0
  149. package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleRelayNaming.java +29 -0
  150. package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleUploadService.java +76 -0
  151. package/android/src/main/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtils.java +791 -0
  152. package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunker.java +186 -0
  153. package/android/src/main/java/com/mentra/bluetoothsdk/utils/NexSGCUtils.kt +589 -0
  154. package/android/src/main/java/com/mentra/bluetoothsdk/utils/PhoneAudioMonitor.kt +303 -0
  155. package/android/src/main/java/com/mentra/bluetoothsdk/utils/SmartGlassesConnectionState.java +9 -0
  156. package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/ByteUtilAudioPlayer.java +655 -0
  157. package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/Lc3Player.java +441 -0
  158. package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/PCMAudioPlayer.java +431 -0
  159. package/android/src/main/res/values/strings.xml +4 -0
  160. package/app.plugin.js +1 -0
  161. package/build/BluetoothSdk.types.d.ts +498 -0
  162. package/build/BluetoothSdk.types.d.ts.map +1 -0
  163. package/build/BluetoothSdk.types.js +23 -0
  164. package/build/BluetoothSdk.types.js.map +1 -0
  165. package/build/BluetoothSdkModule.d.ts +71 -0
  166. package/build/BluetoothSdkModule.d.ts.map +1 -0
  167. package/build/BluetoothSdkModule.js +106 -0
  168. package/build/BluetoothSdkModule.js.map +1 -0
  169. package/build/index.d.ts +3 -0
  170. package/build/index.d.ts.map +1 -0
  171. package/build/index.js +5 -0
  172. package/build/index.js.map +1 -0
  173. package/expo-module.config.json +9 -0
  174. package/ios/BluetoothSdkModule.swift +665 -0
  175. package/ios/MentraBluetoothSDK.podspec +77 -0
  176. package/ios/Packages/CoreObjC/CoreObjC.xcodeproj/project.pbxproj +213 -0
  177. package/ios/Packages/CoreObjC/PcmConverter.h +22 -0
  178. package/ios/Packages/CoreObjC/PcmConverter.m +266 -0
  179. package/ios/Packages/CoreObjC/attdet.c +92 -0
  180. package/ios/Packages/CoreObjC/attdet.h +44 -0
  181. package/ios/Packages/CoreObjC/bits.c +375 -0
  182. package/ios/Packages/CoreObjC/bits.h +315 -0
  183. package/ios/Packages/CoreObjC/bwdet.c +129 -0
  184. package/ios/Packages/CoreObjC/bwdet.h +69 -0
  185. package/ios/Packages/CoreObjC/common.h +151 -0
  186. package/ios/Packages/CoreObjC/energy.c +70 -0
  187. package/ios/Packages/CoreObjC/energy.h +43 -0
  188. package/ios/Packages/CoreObjC/fastmath.h +158 -0
  189. package/ios/Packages/CoreObjC/lc3.c +704 -0
  190. package/ios/Packages/CoreObjC/lc3.h +313 -0
  191. package/ios/Packages/CoreObjC/lc3_cpp.h +283 -0
  192. package/ios/Packages/CoreObjC/lc3_private.h +163 -0
  193. package/ios/Packages/CoreObjC/ltpf.c +905 -0
  194. package/ios/Packages/CoreObjC/ltpf.h +111 -0
  195. package/ios/Packages/CoreObjC/ltpf_arm.h +506 -0
  196. package/ios/Packages/CoreObjC/ltpf_neon.h +281 -0
  197. package/ios/Packages/CoreObjC/makefile.mk +35 -0
  198. package/ios/Packages/CoreObjC/mdct.c +469 -0
  199. package/ios/Packages/CoreObjC/mdct.h +57 -0
  200. package/ios/Packages/CoreObjC/mdct_neon.h +296 -0
  201. package/ios/Packages/CoreObjC/meson.build +61 -0
  202. package/ios/Packages/CoreObjC/plc.c +61 -0
  203. package/ios/Packages/CoreObjC/plc.h +57 -0
  204. package/ios/Packages/CoreObjC/rnnoise.h +114 -0
  205. package/ios/Packages/CoreObjC/sns.c +880 -0
  206. package/ios/Packages/CoreObjC/sns.h +103 -0
  207. package/ios/Packages/CoreObjC/spec.c +907 -0
  208. package/ios/Packages/CoreObjC/spec.h +119 -0
  209. package/ios/Packages/CoreObjC/tables.c +3457 -0
  210. package/ios/Packages/CoreObjC/tables.h +94 -0
  211. package/ios/Packages/CoreObjC/tns.c +457 -0
  212. package/ios/Packages/CoreObjC/tns.h +99 -0
  213. package/ios/Packages/SherpaOnnx/Model/joiner.onnx +0 -0
  214. package/ios/Packages/SherpaOnnx/Model/tokens.txt +502 -0
  215. package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +1659 -0
  216. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/cargs.h +162 -0
  217. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/c-api.h +1852 -0
  218. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/cxx-api.h +674 -0
  219. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +44 -0
  220. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/libsherpa-onnx.a +0 -0
  221. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/sherpa-onnx.a +0 -0
  222. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
  223. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/sherpa-onnx.a +0 -0
  224. package/ios/Packages/VAD/Common/VAD/VADQuality.swift +41 -0
  225. package/ios/Packages/VAD/Common/VAD/VADState.swift +26 -0
  226. package/ios/Packages/VAD/Common/VAD/VADStrategy.swift +29 -0
  227. package/ios/Packages/VAD/Common/VAD/VADType.swift +14 -0
  228. package/ios/Packages/VAD/Data/Configuration.swift +68 -0
  229. package/ios/Packages/VAD/Data/FrameSize.swift +39 -0
  230. package/ios/Packages/VAD/Data/Record.swift +13 -0
  231. package/ios/Packages/VAD/Data/Result.swift +22 -0
  232. package/ios/Packages/VAD/Data/SampleRate.swift +48 -0
  233. package/ios/Packages/VAD/Silero/Model/silero_vad.onnx +0 -0
  234. package/ios/Packages/VAD/Silero/SileroVAD.swift +284 -0
  235. package/ios/Packages/VAD/Silero/SileroVADStrategy.swift +64 -0
  236. package/ios/Packages/libbz2/module.modulemap +5 -0
  237. package/ios/Packages/libbz2/shim.h +1 -0
  238. package/ios/Source/Bridge.swift +353 -0
  239. package/ios/Source/Bridging-Header.h +16 -0
  240. package/ios/Source/DeviceManager.swift +1478 -0
  241. package/ios/Source/DeviceStore.swift +295 -0
  242. package/ios/Source/MentraBluetoothSDK.swift +2439 -0
  243. package/ios/Source/ObservableStore.swift +88 -0
  244. package/ios/Source/PrivacyInfo.xcprivacy +23 -0
  245. package/ios/Source/controllers/ControllerManager.swift +187 -0
  246. package/ios/Source/controllers/R1.swift +827 -0
  247. package/ios/Source/services/PhoneMic.swift +662 -0
  248. package/ios/Source/sgcs/Frame.swift +651 -0
  249. package/ios/Source/sgcs/G1.swift +2505 -0
  250. package/ios/Source/sgcs/G2.swift +3730 -0
  251. package/ios/Source/sgcs/Mach1.swift +543 -0
  252. package/ios/Source/sgcs/MentraLive.swift +4708 -0
  253. package/ios/Source/sgcs/MentraNex.swift +2479 -0
  254. package/ios/Source/sgcs/SGCManager.swift +243 -0
  255. package/ios/Source/sgcs/Simulated.swift +270 -0
  256. package/ios/Source/sgcs/mentraos_ble.pb.swift +3811 -0
  257. package/ios/Source/stt/STTTools.swift +154 -0
  258. package/ios/Source/stt/SherpaOnnxTranscriber.swift +401 -0
  259. package/ios/Source/utils/AudioSessionMonitor.swift +283 -0
  260. package/ios/Source/utils/Constants.swift +74 -0
  261. package/ios/Source/utils/Enums.swift +95 -0
  262. package/ios/Source/utils/G1Text.swift +2067 -0
  263. package/ios/Source/utils/JSCExperiment.swift +241 -0
  264. package/ios/Source/utils/MemoryMonitor.swift +44 -0
  265. package/ios/Source/utils/MessageChunker.swift +164 -0
  266. package/ios/Source/utils/Models.swift +135 -0
  267. package/ios/Source/utils/PhoneAudioMonitor.swift +226 -0
  268. package/ios/Source/utils/TarBz2Extractor.swift +206 -0
  269. package/package.json +78 -0
  270. package/plugin/build/index.d.ts +6 -0
  271. package/plugin/build/index.js +12 -0
  272. package/plugin/build/withAndroid.d.ts +4 -0
  273. package/plugin/build/withAndroid.js +80 -0
  274. package/plugin/build/withIos.d.ts +4 -0
  275. package/plugin/build/withIos.js +64 -0
  276. package/src/BluetoothSdk.types.ts +581 -0
  277. package/src/BluetoothSdkModule.ts +259 -0
  278. package/src/index.ts +4 -0
@@ -0,0 +1,436 @@
1
+ package com.mentra.bluetoothsdk.utils
2
+
3
+ class G1Text {
4
+ companion object {
5
+ // Constants for text wall display
6
+ private const val TEXT_COMMAND: Byte = 0x4E // Text command
7
+ private const val DISPLAY_WIDTH = 488
8
+ private const val DISPLAY_USE_WIDTH = 488 // How much of the display to use
9
+ private const val FONT_MULTIPLIER: Float = 1 / 50.0f
10
+ private const val OLD_FONT_SIZE = 21 // Font size
11
+ private const val FONT_DIVIDER: Float = 2.0f
12
+ private const val LINES_PER_SCREEN = 5 // Lines per screen
13
+ private const val MAX_CHUNK_SIZE = 176 // Maximum chunk size for BLE packets
14
+ }
15
+
16
+ private var textSeqNum = 0 // Sequence number for text packets
17
+ private val fontLoader = G1FontLoaderKt()
18
+
19
+ // Calculate text width in pixels
20
+ fun calculateTextWidth(text: String): Int {
21
+ var width = 0
22
+ for (char in text) {
23
+ val glyph = fontLoader.getGlyph(char)
24
+ width += glyph.width + 1 // Add 1 pixel per character for spacing
25
+ }
26
+ return width * 2
27
+ }
28
+
29
+ private fun calculateSubstringWidth(text: String, start: Int, end: Int): Int {
30
+ val substring = text.substring(start, end)
31
+ return calculateTextWidth(substring)
32
+ }
33
+
34
+ private fun calculateSpacesForAlignment(currentWidth: Int, targetPosition: Int, spaceWidth: Int): Int {
35
+ // Calculate space needed in pixels
36
+ val pixelsNeeded = targetPosition - currentWidth
37
+
38
+ // Calculate spaces needed (with minimum of 1 space for separation)
39
+ if (pixelsNeeded <= 0) {
40
+ return 1 // Ensure at least one space between columns
41
+ }
42
+
43
+ // Calculate the exact number of spaces needed
44
+ val spaces = Math.ceil(pixelsNeeded.toDouble() / spaceWidth.toDouble()).toInt()
45
+
46
+ // Cap at a reasonable maximum
47
+ return Math.min(spaces, 100)
48
+ }
49
+
50
+ fun splitIntoLines(text: String, maxDisplayWidth: Int): List<String> {
51
+ // Replace specific symbols
52
+ val processedText = text.replace("⬆", "^").replace("⟶", "-")
53
+
54
+ val lines = mutableListOf<String>()
55
+
56
+ // Handle empty or single space case
57
+ if (processedText.isEmpty() || processedText == " ") {
58
+ lines.add(processedText)
59
+ return lines
60
+ }
61
+
62
+ // Split by newlines first
63
+ val rawLines = processedText.split("\n")
64
+
65
+ for (rawLine in rawLines) {
66
+ // Add empty lines for newlines
67
+ if (rawLine.isEmpty()) {
68
+ lines.add("")
69
+ continue
70
+ }
71
+
72
+ val lineLength = rawLine.length
73
+ var startIndex = 0
74
+
75
+ while (startIndex < lineLength) {
76
+ // Get maximum possible end index
77
+ val endIndex = lineLength
78
+
79
+ // Calculate width of the entire remaining text
80
+ val lineWidth = calculateSubstringWidth(rawLine, startIndex, endIndex)
81
+
82
+ // If entire line fits, add it and move to next line
83
+ if (lineWidth <= maxDisplayWidth) {
84
+ lines.add(rawLine.substring(startIndex))
85
+ break
86
+ }
87
+
88
+ // Binary search to find the maximum number of characters that fit
89
+ var left = startIndex + 1
90
+ var right = lineLength
91
+ var bestSplitIndex = startIndex + 1
92
+
93
+ while (left <= right) {
94
+ val mid = left + (right - left) / 2
95
+ val width = calculateSubstringWidth(rawLine, startIndex, mid)
96
+
97
+ if (width <= maxDisplayWidth) {
98
+ bestSplitIndex = mid
99
+ left = mid + 1
100
+ } else {
101
+ right = mid - 1
102
+ }
103
+ }
104
+
105
+ // Now find a good place to break (preferably at a space)
106
+ var splitIndex = bestSplitIndex
107
+
108
+ // Look for a space to break at
109
+ var foundSpace = false
110
+ for (i in bestSplitIndex downTo startIndex + 1) {
111
+ if (i > 0 && rawLine[i - 1] == ' ') {
112
+ splitIndex = i
113
+ foundSpace = true
114
+ break
115
+ }
116
+ }
117
+
118
+ // If we couldn't find a space in a reasonable range, use the calculated split point
119
+ if (!foundSpace && bestSplitIndex - startIndex > 2) {
120
+ splitIndex = bestSplitIndex
121
+ }
122
+
123
+ // Add the line
124
+ val line = rawLine.substring(startIndex, splitIndex).trim()
125
+ lines.add(line)
126
+
127
+ // Skip any spaces at the beginning of the next line
128
+ var newStartIndex = splitIndex
129
+ while (newStartIndex < lineLength && rawLine[newStartIndex] == ' ') {
130
+ newStartIndex++
131
+ }
132
+
133
+ startIndex = newStartIndex
134
+ }
135
+ }
136
+
137
+ return lines
138
+ }
139
+
140
+ fun createTextWallChunks(text: String): List<ByteArray> {
141
+ val margin = 5
142
+
143
+ // Get width of single space character
144
+ val spaceWidth = calculateTextWidth(" ")
145
+
146
+ // Calculate effective display width after accounting for left and right margins in spaces
147
+ val marginWidth = margin * spaceWidth // Width of left margin in pixels
148
+ val effectiveWidth = DISPLAY_WIDTH - (2 * marginWidth) // Subtract left and right margins
149
+
150
+ // Split text into lines based on effective display width
151
+ val lines = splitIntoLines(text, effectiveWidth)
152
+
153
+ // Calculate total pages (hard set to 1 - 1PAGECHANGE)
154
+ val totalPages = 1
155
+
156
+ val allChunks = mutableListOf<ByteArray>()
157
+
158
+ // Process each page
159
+ for (page in 0 until totalPages) {
160
+ // Get lines for current page
161
+ val startLine = page * LINES_PER_SCREEN
162
+ val endLine = Math.min(startLine + LINES_PER_SCREEN, lines.size)
163
+ val pageLines = lines.subList(startLine, endLine)
164
+
165
+ // Combine lines for this page with proper indentation
166
+ val pageText = StringBuilder()
167
+
168
+ for (line in pageLines) {
169
+ // Add the exact number of spaces for indentation
170
+ val indentation = " ".repeat(margin)
171
+ pageText.append("$indentation$line\n")
172
+ }
173
+
174
+ val textBytes = pageText.toString().toByteArray(Charsets.UTF_8)
175
+ val totalChunks = Math.ceil(textBytes.size.toDouble() / MAX_CHUNK_SIZE.toDouble()).toInt()
176
+
177
+ // Create chunks for this page
178
+ for (i in 0 until totalChunks) {
179
+ val start = i * MAX_CHUNK_SIZE
180
+ val end = Math.min(start + MAX_CHUNK_SIZE, textBytes.size)
181
+ val payloadChunk = textBytes.copyOfRange(start, end)
182
+
183
+ // Create header with protocol specifications
184
+ val screenStatus: Byte = 0x71 // New content (0x01) + Text Show (0x70)
185
+ val header = byteArrayOf(
186
+ TEXT_COMMAND, // Command type
187
+ textSeqNum.toByte(), // Sequence number
188
+ totalChunks.toByte(), // Total packages
189
+ i.toByte(), // Current package number
190
+ screenStatus, // Screen status
191
+ 0x00, // new_char_pos0 (high)
192
+ 0x00, // new_char_pos1 (low)
193
+ page.toByte(), // Current page number
194
+ totalPages.toByte() // Max page number
195
+ )
196
+
197
+ // Combine header and payload
198
+ val chunk = header + payloadChunk
199
+
200
+ allChunks.add(chunk)
201
+ }
202
+
203
+ // Increment sequence number for next page
204
+ textSeqNum = (textSeqNum + 1) % 256
205
+ break // Hard set to 1 - 1PAGECHANGE
206
+ }
207
+
208
+ return allChunks
209
+ }
210
+
211
+ /**
212
+ * Creates BLE chunks for pre-composed double text wall.
213
+ *
214
+ * NOTE: DisplayProcessor now composes double_text_wall into a single text_wall
215
+ * with pixel-precise column alignment using ColumnComposer. This method may
216
+ * not be called anymore for new flows, but is kept for backwards compatibility.
217
+ *
218
+ * Column composition is handled by DisplayProcessor in React Native.
219
+ * This method is a "dumb pipe" - it just combines and chunks the text.
220
+ *
221
+ * @param textTop Pre-composed left/top column text
222
+ * @param textBottom Pre-composed right/bottom column text
223
+ * @return List of BLE chunks ready for transmission
224
+ */
225
+ fun createDoubleTextWallChunks(textTop: String, textBottom: String): List<ByteArray> {
226
+ // Text is already composed by DisplayProcessor's ColumnComposer
227
+ // Just combine and chunk for transmission - no custom wrapping logic needed
228
+ val combinedText = "$textTop\n$textBottom"
229
+ return chunkTextForTransmission(combinedText)
230
+ }
231
+
232
+ private fun chunkTextForTransmission(text: String): List<ByteArray> {
233
+ val textBytes = text.toByteArray(Charsets.UTF_8)
234
+ val totalChunks = Math.ceil(textBytes.size.toDouble() / MAX_CHUNK_SIZE.toDouble()).toInt()
235
+
236
+ val allChunks = mutableListOf<ByteArray>()
237
+ for (i in 0 until totalChunks) {
238
+ val start = i * MAX_CHUNK_SIZE
239
+ val end = Math.min(start + MAX_CHUNK_SIZE, textBytes.size)
240
+ val payloadChunk = textBytes.copyOfRange(start, end)
241
+
242
+ // Create header with protocol specifications
243
+ val screenStatus: Byte = 0x71 // New content (0x01) + Text Show (0x70)
244
+ val header = byteArrayOf(
245
+ TEXT_COMMAND, // Command type
246
+ textSeqNum.toByte(), // Sequence number
247
+ totalChunks.toByte(), // Total packages
248
+ i.toByte(), // Current package number
249
+ screenStatus, // Screen status
250
+ 0x00, // new_char_pos0 (high)
251
+ 0x00, // new_char_pos1 (low)
252
+ 0x00, // Current page number (always 0 for now)
253
+ 0x01 // Max page number (always 1)
254
+ )
255
+
256
+ // Combine header and payload
257
+ val chunk = header + payloadChunk
258
+
259
+ allChunks.add(chunk)
260
+ }
261
+
262
+ // Increment sequence number for next page
263
+ textSeqNum = (textSeqNum + 1) % 256
264
+
265
+ return allChunks
266
+ }
267
+ }
268
+
269
+ // Font loader with hardcoded font data
270
+ class G1FontLoaderKt {
271
+ private val fontMap: MutableMap<Char, FontGlyph> = mutableMapOf()
272
+
273
+ init {
274
+ loadHardcodedFontData()
275
+ }
276
+
277
+ private fun loadHardcodedFontData() {
278
+ // Hardcoded font data based on the Swift implementation
279
+ val hardcodedGlyphs = listOf(
280
+ GlyphData(32, ' ', 2, 26),
281
+ GlyphData(33, '!', 1, 26),
282
+ GlyphData(34, '"', 2, 26),
283
+ GlyphData(35, '#', 6, 26),
284
+ GlyphData(36, '$', 5, 26),
285
+ GlyphData(37, '%', 6, 26),
286
+ GlyphData(38, '&', 7, 26),
287
+ GlyphData(39, '\'', 1, 26),
288
+ GlyphData(40, '(', 2, 26),
289
+ GlyphData(41, ')', 2, 26),
290
+ GlyphData(42, '*', 3, 26),
291
+ GlyphData(43, '+', 4, 26),
292
+ GlyphData(44, ',', 1, 26),
293
+ GlyphData(45, '-', 4, 26),
294
+ GlyphData(46, '.', 1, 26),
295
+ GlyphData(47, '/', 3, 26),
296
+ GlyphData(48, '0', 5, 26),
297
+ GlyphData(49, '1', 3, 26),
298
+ GlyphData(50, '2', 5, 26),
299
+ GlyphData(51, '3', 5, 26),
300
+ GlyphData(52, '4', 5, 26),
301
+ GlyphData(53, '5', 5, 26),
302
+ GlyphData(54, '6', 5, 26),
303
+ GlyphData(55, '7', 5, 26),
304
+ GlyphData(56, '8', 5, 26),
305
+ GlyphData(57, '9', 5, 26),
306
+ GlyphData(58, ':', 1, 26),
307
+ GlyphData(59, ';', 1, 26),
308
+ GlyphData(60, '<', 4, 26),
309
+ GlyphData(61, '=', 4, 26),
310
+ GlyphData(62, '>', 4, 26),
311
+ GlyphData(63, '?', 5, 26),
312
+ GlyphData(64, '@', 7, 26),
313
+ GlyphData(65, 'A', 6, 26),
314
+ GlyphData(66, 'B', 5, 26),
315
+ GlyphData(67, 'C', 5, 26),
316
+ GlyphData(68, 'D', 5, 26),
317
+ GlyphData(69, 'E', 4, 26),
318
+ GlyphData(70, 'F', 4, 26),
319
+ GlyphData(71, 'G', 5, 26),
320
+ GlyphData(72, 'H', 5, 26),
321
+ GlyphData(73, 'I', 2, 26),
322
+ GlyphData(74, 'J', 3, 26),
323
+ GlyphData(75, 'K', 5, 26),
324
+ GlyphData(76, 'L', 4, 26),
325
+ GlyphData(77, 'M', 7, 26),
326
+ GlyphData(78, 'N', 5, 26),
327
+ GlyphData(79, 'O', 5, 26),
328
+ GlyphData(80, 'P', 5, 26),
329
+ GlyphData(81, 'Q', 5, 26),
330
+ GlyphData(82, 'R', 5, 26),
331
+ GlyphData(83, 'S', 5, 26),
332
+ GlyphData(84, 'T', 5, 26),
333
+ GlyphData(85, 'U', 5, 26),
334
+ GlyphData(86, 'V', 6, 26),
335
+ GlyphData(87, 'W', 7, 26),
336
+ GlyphData(88, 'X', 6, 26),
337
+ GlyphData(89, 'Y', 6, 26),
338
+ GlyphData(90, 'Z', 5, 26),
339
+ GlyphData(91, '[', 2, 26),
340
+ GlyphData(92, '\\', 3, 26),
341
+ GlyphData(93, ']', 2, 26),
342
+ GlyphData(94, '^', 4, 26),
343
+ GlyphData(95, '_', 3, 26),
344
+ GlyphData(96, '`', 2, 26),
345
+ GlyphData(97, 'a', 5, 26),
346
+ GlyphData(98, 'b', 4, 26),
347
+ GlyphData(99, 'c', 4, 26),
348
+ GlyphData(100, 'd', 4, 26),
349
+ GlyphData(101, 'e', 4, 26),
350
+ GlyphData(102, 'f', 4, 26),
351
+ GlyphData(103, 'g', 4, 26),
352
+ GlyphData(104, 'h', 4, 26),
353
+ GlyphData(105, 'i', 1, 26),
354
+ GlyphData(106, 'j', 2, 26),
355
+ GlyphData(107, 'k', 4, 26),
356
+ GlyphData(108, 'l', 1, 26),
357
+ GlyphData(109, 'm', 7, 26),
358
+ GlyphData(110, 'n', 4, 26),
359
+ GlyphData(111, 'o', 4, 26),
360
+ GlyphData(112, 'p', 4, 26),
361
+ GlyphData(113, 'q', 4, 26),
362
+ GlyphData(114, 'r', 3, 26),
363
+ GlyphData(115, 's', 4, 26),
364
+ GlyphData(116, 't', 3, 26),
365
+ GlyphData(117, 'u', 5, 26),
366
+ GlyphData(118, 'v', 5, 26),
367
+ GlyphData(119, 'w', 7, 26),
368
+ GlyphData(120, 'x', 5, 26),
369
+ GlyphData(121, 'y', 5, 26),
370
+ GlyphData(122, 'z', 4, 26),
371
+ GlyphData(123, '{', 3, 26),
372
+ GlyphData(124, '|', 1, 26),
373
+ GlyphData(125, '}', 3, 26),
374
+ GlyphData(126, '~', 7, 26),
375
+ GlyphData(192, 'À', 6, 26),
376
+ GlyphData(194, 'Â', 6, 26),
377
+ GlyphData(199, 'Ç', 5, 26),
378
+ GlyphData(200, 'È', 4, 26),
379
+ GlyphData(201, 'É', 4, 26),
380
+ GlyphData(202, 'Ê', 4, 26),
381
+ GlyphData(203, 'Ë', 4, 26),
382
+ GlyphData(206, 'Î', 3, 26),
383
+ GlyphData(207, 'Ï', 3, 26),
384
+ GlyphData(212, 'Ô', 5, 26),
385
+ GlyphData(217, 'Ù', 5, 26),
386
+ GlyphData(219, 'Û', 5, 26),
387
+ GlyphData(220, 'Ü', 5, 26),
388
+ GlyphData(224, 'à', 5, 26),
389
+ GlyphData(231, 'ç', 4, 26),
390
+ GlyphData(232, 'è', 4, 26),
391
+ GlyphData(233, 'é', 4, 26),
392
+ GlyphData(234, 'ê', 4, 26),
393
+ GlyphData(235, 'ë', 4, 26),
394
+ GlyphData(238, 'î', 3, 26),
395
+ GlyphData(239, 'ï', 3, 26),
396
+ GlyphData(244, 'ô', 4, 26),
397
+ GlyphData(249, 'ù', 5, 26),
398
+ GlyphData(251, 'û', 5, 26),
399
+ GlyphData(252, 'ü', 5, 26),
400
+ GlyphData(255, 'ÿ', 5, 26),
401
+ GlyphData(376, 'Ÿ', 6, 26),
402
+ GlyphData(196, 'Ä', 6, 26),
403
+ GlyphData(228, 'ä', 5, 26),
404
+ GlyphData(214, 'Ö', 5, 26),
405
+ GlyphData(246, 'ö', 4, 26),
406
+ GlyphData(223, 'ß', 4, 26),
407
+ GlyphData(7838, 'ẞ', 5, 26),
408
+ GlyphData(226, 'â', 5, 26),
409
+ GlyphData(193, 'Á', 6, 26),
410
+ GlyphData(225, 'á', 5, 26),
411
+ GlyphData(205, 'Í', 2, 26),
412
+ GlyphData(237, 'í', 2, 26),
413
+ GlyphData(209, 'Ñ', 5, 26),
414
+ GlyphData(241, 'ñ', 4, 26),
415
+ GlyphData(250, 'ú', 5, 26),
416
+ GlyphData(211, 'Ó', 5, 26),
417
+ GlyphData(243, 'ó', 4, 26),
418
+ GlyphData(218, 'Ú', 5, 26)
419
+ )
420
+
421
+ // Map characters directly to FontGlyph objects
422
+ for (glyph in hardcodedGlyphs) {
423
+ fontMap[glyph.char] = FontGlyph(glyph.width, glyph.height)
424
+ }
425
+
426
+ println("Hardcoded font data loaded successfully! ${fontMap.size} glyphs mapped.")
427
+ }
428
+
429
+ fun getGlyph(character: Char): FontGlyph {
430
+ return fontMap[character] ?: FontGlyph(6, 26) // Default width=6, height=26
431
+ }
432
+
433
+ data class FontGlyph(val width: Int, val height: Int)
434
+
435
+ private data class GlyphData(val codePoint: Int, val char: Char, val width: Int, val height: Int)
436
+ }
@@ -0,0 +1,29 @@
1
+ package com.mentra.bluetoothsdk.utils;
2
+
3
+ import java.util.Locale;
4
+
5
+ /**
6
+ * 16-byte K900 file name for incident log payloads relayed over BLE (must match ASG
7
+ * {@code IncidentLogBleRelayNaming}).
8
+ */
9
+ public final class IncidentLogBleRelayNaming {
10
+
11
+ private static final int SUFFIX_LEN = 15;
12
+
13
+ private IncidentLogBleRelayNaming() {}
14
+
15
+ public static String bleFileBaseName(String incidentId, char prefix) {
16
+ if (incidentId == null || incidentId.isEmpty()) {
17
+ return prefix + "000000000000000";
18
+ }
19
+ String compact = incidentId.replace("-", "").toLowerCase(Locale.US);
20
+ if (compact.length() < SUFFIX_LEN) {
21
+ StringBuilder sb = new StringBuilder(compact);
22
+ while (sb.length() < SUFFIX_LEN) {
23
+ sb.append('0');
24
+ }
25
+ compact = sb.toString();
26
+ }
27
+ return prefix + compact.substring(0, SUFFIX_LEN);
28
+ }
29
+ }
@@ -0,0 +1,76 @@
1
+ package com.mentra.bluetoothsdk.utils;
2
+
3
+ import android.util.Log;
4
+
5
+ import java.io.IOException;
6
+ import java.util.concurrent.TimeUnit;
7
+
8
+ import okhttp3.HttpUrl;
9
+ import okhttp3.MediaType;
10
+ import okhttp3.OkHttpClient;
11
+ import okhttp3.Request;
12
+ import okhttp3.RequestBody;
13
+ import okhttp3.Response;
14
+
15
+ /**
16
+ * POSTs incident log JSON (from BLE relay) using the same path as glasses direct upload.
17
+ */
18
+ public final class IncidentLogBleUploadService {
19
+
20
+ private static final String TAG = "IncidentLogBleUpload";
21
+
22
+ private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
23
+
24
+ private IncidentLogBleUploadService() {}
25
+
26
+ public interface Callback {
27
+ void onDone(boolean success, String message);
28
+ }
29
+
30
+ public static void upload(String apiBaseUrl, String incidentId, String authToken,
31
+ byte[] jsonUtf8, Callback callback) {
32
+ new Thread(() -> {
33
+ try {
34
+ if (authToken == null || authToken.isEmpty()) {
35
+ callback.onDone(false, "no auth token");
36
+ return;
37
+ }
38
+ HttpUrl baseHttpUrl = HttpUrl.parse(apiBaseUrl != null ? apiBaseUrl.trim() : "");
39
+ if (baseHttpUrl == null) {
40
+ callback.onDone(false, "empty or malformed api base url");
41
+ return;
42
+ }
43
+ HttpUrl url = baseHttpUrl.newBuilder()
44
+ .addPathSegment("api")
45
+ .addPathSegment("incidents")
46
+ .addPathSegment(incidentId)
47
+ .addPathSegment("logs")
48
+ .build();
49
+ RequestBody body = RequestBody.create(jsonUtf8, JSON);
50
+ OkHttpClient client = new OkHttpClient.Builder()
51
+ .connectTimeout(20, TimeUnit.SECONDS)
52
+ .writeTimeout(60, TimeUnit.SECONDS)
53
+ .readTimeout(60, TimeUnit.SECONDS)
54
+ .build();
55
+ Request request = new Request.Builder()
56
+ .url(url)
57
+ .header("Authorization", "Bearer " + authToken)
58
+ .post(body)
59
+ .build();
60
+ try (Response response = client.newCall(request).execute()) {
61
+ if (response.isSuccessful()) {
62
+ Log.i(TAG, "Incident BLE relay upload OK: " + url);
63
+ callback.onDone(true, null);
64
+ } else {
65
+ String msg = "HTTP " + response.code();
66
+ Log.e(TAG, "Incident BLE relay upload failed: " + msg + " " + url);
67
+ callback.onDone(false, msg);
68
+ }
69
+ }
70
+ } catch (IOException e) {
71
+ Log.e(TAG, "Incident BLE relay upload IO error", e);
72
+ callback.onDone(false, e.getMessage());
73
+ }
74
+ }).start();
75
+ }
76
+ }