@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,226 @@
1
+ //
2
+ // PhoneAudioMonitor.swift
3
+ // AOS
4
+ //
5
+ // Monitors iOS system audio playback state
6
+ //
7
+ // Used to detect when the phone is playing audio (music, podcasts, etc.)
8
+ // so we can temporarily suspend the LC3 microphone on MentraLive glasses
9
+ // to avoid overloading the MCU when both A2DP output and LC3 mic input
10
+ // are active simultaneously.
11
+ //
12
+ // This class mirrors the Android PhoneAudioMonitor.kt implementation.
13
+ //
14
+
15
+ import AVFoundation
16
+ import Foundation
17
+
18
+ /// Listener protocol for phone audio state changes
19
+ protocol PhoneAudioMonitorListener: AnyObject {
20
+ func onPhoneAudioStateChanged(isPlaying: Bool)
21
+ }
22
+
23
+ /// Monitors system audio playback to detect when the phone is playing audio
24
+ class PhoneAudioMonitor {
25
+ /// Singleton instance
26
+ private static var instance: PhoneAudioMonitor?
27
+
28
+ private weak var listener: PhoneAudioMonitorListener?
29
+ private var isMonitoring = false
30
+ private var lastKnownState = false
31
+
32
+ /// Track our own app's audio playback state
33
+ /// isOtherAudioPlaying only detects OTHER apps, not our own
34
+ private var ownAppAudioPlaying = false
35
+
36
+ // Polling timer for fallback detection
37
+ private var pollingTimer: Timer?
38
+ private let pollingIntervalSeconds: TimeInterval = 1.0
39
+
40
+ private init() {
41
+ Bridge.log("PhoneAudioMonitor: Initialized")
42
+ }
43
+
44
+ static func getInstance() -> PhoneAudioMonitor {
45
+ if instance == nil {
46
+ instance = PhoneAudioMonitor()
47
+ }
48
+ return instance!
49
+ }
50
+
51
+ /// Check if any audio is currently playing on the device (including our own app)
52
+ func isPlaying() -> Bool {
53
+ let session = AVAudioSession.sharedInstance()
54
+ // Combine: other apps playing OR our own app playing
55
+ return session.isOtherAudioPlaying || ownAppAudioPlaying
56
+ }
57
+
58
+ /// Notify the monitor that our own app started/stopped playing audio
59
+ /// Called from RN AudioPlaybackService via Bridge
60
+ func setOwnAppAudioPlaying(_ playing: Bool) {
61
+ guard ownAppAudioPlaying != playing else { return }
62
+
63
+ ownAppAudioPlaying = playing
64
+ Bridge.log("PhoneAudioMonitor: Own app audio -> \(playing ? "PLAYING" : "STOPPED")")
65
+
66
+ // Immediately notify listener if overall state changed
67
+ notifyIfStateChanged(isPlaying())
68
+ }
69
+
70
+ /// Start monitoring for phone audio playback changes
71
+ ///
72
+ /// - Parameter listener: Callback to receive audio state change notifications
73
+ func startMonitoring(listener: PhoneAudioMonitorListener) {
74
+ guard !isMonitoring else {
75
+ Bridge.log("PhoneAudioMonitor: Already monitoring")
76
+ return
77
+ }
78
+
79
+ self.listener = listener
80
+ lastKnownState = isPlaying()
81
+ isMonitoring = true
82
+
83
+ Bridge.log(
84
+ "PhoneAudioMonitor: Starting audio playback monitoring (initial state: \(lastKnownState ? "playing" : "not playing"))"
85
+ )
86
+
87
+ // Register for silenceSecondaryAudioHint notification
88
+ // This is fired when other apps start/stop playing audio
89
+ NotificationCenter.default.addObserver(
90
+ self,
91
+ selector: #selector(handleSilenceSecondaryAudioHint),
92
+ name: AVAudioSession.silenceSecondaryAudioHintNotification,
93
+ object: nil
94
+ )
95
+
96
+ // Also register for interruption notifications as a supplement
97
+ NotificationCenter.default.addObserver(
98
+ self,
99
+ selector: #selector(handleAudioInterruption),
100
+ name: AVAudioSession.interruptionNotification,
101
+ object: nil
102
+ )
103
+
104
+ // Start polling as a fallback mechanism
105
+ // Some audio sources might not trigger notifications reliably
106
+ startPolling()
107
+ }
108
+
109
+ /// Stop monitoring for phone audio playback changes
110
+ func stopMonitoring() {
111
+ guard isMonitoring else {
112
+ Bridge.log("PhoneAudioMonitor: Not currently monitoring")
113
+ return
114
+ }
115
+
116
+ Bridge.log("PhoneAudioMonitor: Stopping audio playback monitoring")
117
+
118
+ NotificationCenter.default.removeObserver(
119
+ self,
120
+ name: AVAudioSession.silenceSecondaryAudioHintNotification,
121
+ object: nil
122
+ )
123
+
124
+ NotificationCenter.default.removeObserver(
125
+ self,
126
+ name: AVAudioSession.interruptionNotification,
127
+ object: nil
128
+ )
129
+
130
+ stopPolling()
131
+
132
+ listener = nil
133
+ isMonitoring = false
134
+ }
135
+
136
+ /// Handle silenceSecondaryAudioHint notification
137
+ @objc private func handleSilenceSecondaryAudioHint(_ notification: Notification) {
138
+ guard let userInfo = notification.userInfo,
139
+ let typeValue = userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey] as? UInt,
140
+ let type = AVAudioSession.SilenceSecondaryAudioHintType(rawValue: typeValue)
141
+ else {
142
+ return
143
+ }
144
+
145
+ let isPlaying: Bool
146
+ switch type {
147
+ case .begin:
148
+ // Another app started playing audio
149
+ isPlaying = true
150
+ Bridge.log("PhoneAudioMonitor: Received silenceSecondaryAudioHint - begin")
151
+ case .end:
152
+ // Another app stopped playing audio
153
+ isPlaying = false
154
+ Bridge.log("PhoneAudioMonitor: Received silenceSecondaryAudioHint - end")
155
+ @unknown default:
156
+ // Check actual state for unknown types
157
+ isPlaying = self.isPlaying()
158
+ }
159
+
160
+ notifyIfStateChanged(isPlaying)
161
+ }
162
+
163
+ /// Handle audio interruption notifications
164
+ @objc private func handleAudioInterruption(_ notification: Notification) {
165
+ guard let userInfo = notification.userInfo,
166
+ let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
167
+ let type = AVAudioSession.InterruptionType(rawValue: typeValue)
168
+ else {
169
+ return
170
+ }
171
+
172
+ switch type {
173
+ case .began:
174
+ // Audio was interrupted (e.g., phone call, other app took audio focus)
175
+ Bridge.log("PhoneAudioMonitor: Audio interruption began")
176
+ // Don't necessarily mean audio is playing - check actual state
177
+ notifyIfStateChanged(isPlaying())
178
+ case .ended:
179
+ Bridge.log("PhoneAudioMonitor: Audio interruption ended")
180
+ // Small delay to let audio state settle
181
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
182
+ guard let self = self else { return }
183
+ self.notifyIfStateChanged(self.isPlaying())
184
+ }
185
+ @unknown default:
186
+ break
187
+ }
188
+ }
189
+
190
+ /// Start polling isOtherAudioPlaying as a fallback mechanism
191
+ private func startPolling() {
192
+ pollingTimer = Timer.scheduledTimer(
193
+ withTimeInterval: pollingIntervalSeconds,
194
+ repeats: true
195
+ ) { [weak self] _ in
196
+ guard let self = self, self.isMonitoring else { return }
197
+
198
+ let currentState = self.isPlaying()
199
+ self.notifyIfStateChanged(currentState)
200
+ }
201
+ }
202
+
203
+ /// Stop the polling mechanism
204
+ private func stopPolling() {
205
+ pollingTimer?.invalidate()
206
+ pollingTimer = nil
207
+ }
208
+
209
+ /// Notify listener if state has changed
210
+ private func notifyIfStateChanged(_ isPlaying: Bool) {
211
+ guard isPlaying != lastKnownState else { return }
212
+
213
+ lastKnownState = isPlaying
214
+ Bridge.log("PhoneAudioMonitor: Audio state changed -> \(isPlaying ? "PLAYING" : "STOPPED")")
215
+
216
+ DispatchQueue.main.async { [weak self] in
217
+ self?.listener?.onPhoneAudioStateChanged(isPlaying: isPlaying)
218
+ }
219
+ }
220
+
221
+ /// Clean up resources
222
+ func destroy() {
223
+ stopMonitoring()
224
+ PhoneAudioMonitor.instance = nil
225
+ }
226
+ }
@@ -0,0 +1,206 @@
1
+ import Compression
2
+ import Foundation
3
+ @_implementationOnly import libbz2
4
+ import SWCompression
5
+
6
+ @objc(TarBz2Extractor)
7
+ public class TarBz2Extractor: NSObject {
8
+ private static let chunkSize = 1 << 16 // 64 KB
9
+
10
+ @objc
11
+ public static func extractTarBz2From(
12
+ _ sourcePath: String,
13
+ to destinationPath: String,
14
+ error errorPointer: NSErrorPointer
15
+ ) -> Bool {
16
+ Bridge.log("TarBz2Extractor: begin extraction")
17
+ do {
18
+ try performExtraction(from: sourcePath, to: destinationPath)
19
+ Bridge.log("TarBz2Extractor: extraction complete")
20
+ return true
21
+ } catch let extractionError as NSError {
22
+ Bridge.log("TarBz2Extractor: failed - \(extractionError.localizedDescription)")
23
+ errorPointer?.pointee = extractionError
24
+ return false
25
+ } catch {
26
+ let nsError = NSError(
27
+ domain: "TarBz2Extractor",
28
+ code: -1,
29
+ userInfo: [NSLocalizedDescriptionKey: error.localizedDescription]
30
+ )
31
+ Bridge.log("TarBz2Extractor: failed - \(error.localizedDescription)")
32
+ errorPointer?.pointee = nsError
33
+ return false
34
+ }
35
+ }
36
+
37
+ private static func performExtraction(from sourcePath: String, to destinationPath: String) throws {
38
+ let fileManager = FileManager.default
39
+ try fileManager.createDirectory(
40
+ atPath: destinationPath,
41
+ withIntermediateDirectories: true,
42
+ attributes: nil
43
+ )
44
+
45
+ let tempTarURL = try decompressBzipArchive(at: sourcePath)
46
+ defer { try? fileManager.removeItem(at: tempTarURL) }
47
+
48
+ try extractTarArchive(at: tempTarURL, to: destinationPath)
49
+ try flattenNestedDirectory(at: destinationPath)
50
+ }
51
+
52
+ private static func decompressBzipArchive(at sourcePath: String) throws -> URL {
53
+ let tempTarURL = FileManager.default.temporaryDirectory
54
+ .appendingPathComponent(UUID().uuidString)
55
+ .appendingPathExtension("tar")
56
+
57
+ guard let sourceFile = fopen(sourcePath, "rb") else {
58
+ throw makeError(code: 1001, message: "Unable to open source file at \(sourcePath)")
59
+ }
60
+ defer { fclose(sourceFile) }
61
+
62
+ guard let destinationFile = fopen(tempTarURL.path, "wb") else {
63
+ throw makeError(code: 1002, message: "Unable to create temporary tar file")
64
+ }
65
+ defer { fclose(destinationFile) }
66
+
67
+ var bzError: Int32 = BZ_OK
68
+ guard let bzFile = BZ2_bzReadOpen(&bzError, sourceFile, 0, 0, nil, 0), bzError == BZ_OK else {
69
+ throw makeError(code: 1003, message: "Unable to open bzip stream (code \(bzError))")
70
+ }
71
+
72
+ var buffer = [Int8](repeating: 0, count: chunkSize)
73
+ while true {
74
+ let bytesRead = BZ2_bzRead(&bzError, bzFile, &buffer, Int32(buffer.count))
75
+ if bzError == BZ_OK || bzError == BZ_STREAM_END {
76
+ if bytesRead > 0 {
77
+ let written = buffer.withUnsafeBytes { rawBuffer -> Int in
78
+ guard let baseAddress = rawBuffer.baseAddress else { return 0 }
79
+ return fwrite(baseAddress, 1, Int(bytesRead), destinationFile)
80
+ }
81
+ guard written == Int(bytesRead) else {
82
+ BZ2_bzReadClose(&bzError, bzFile)
83
+ throw makeError(code: 1004, message: "Failed to write decompressed data")
84
+ }
85
+ }
86
+ if bzError == BZ_STREAM_END {
87
+ break
88
+ }
89
+ } else {
90
+ BZ2_bzReadClose(&bzError, bzFile)
91
+ throw makeError(code: 1005, message: "bzip2 read failed with code \(bzError)")
92
+ }
93
+ }
94
+
95
+ BZ2_bzReadClose(&bzError, bzFile)
96
+ guard bzError == BZ_OK else {
97
+ throw makeError(code: 1006, message: "bzip2 close failed with code \(bzError)")
98
+ }
99
+
100
+ return tempTarURL
101
+ }
102
+
103
+ private static func extractTarArchive(at tarURL: URL, to destinationPath: String) throws {
104
+ let destinationRoot = URL(fileURLWithPath: destinationPath, isDirectory: true)
105
+ let fileManager = FileManager.default
106
+
107
+ let handle = try FileHandle(forReadingFrom: tarURL)
108
+ defer { try? handle.close() }
109
+
110
+ var reader = TarReader(fileHandle: handle)
111
+
112
+ while let entry = try reader.read() {
113
+ let sanitizedName = sanitize(entryName: entry.info.name)
114
+ if sanitizedName.isEmpty {
115
+ continue
116
+ }
117
+
118
+ let entryURL = destinationRoot.appendingPathComponent(sanitizedName)
119
+ switch entry.info.type {
120
+ case .directory:
121
+ try fileManager.createDirectory(
122
+ at: entryURL,
123
+ withIntermediateDirectories: true,
124
+ attributes: nil
125
+ )
126
+ case .regular:
127
+ guard let data = entry.data else { continue }
128
+ try fileManager.createDirectory(
129
+ at: entryURL.deletingLastPathComponent(),
130
+ withIntermediateDirectories: true,
131
+ attributes: nil
132
+ )
133
+ let finalURL = remapModelFileIfNeeded(for: entryURL)
134
+ try data.write(to: finalURL, options: .atomic)
135
+ default:
136
+ continue
137
+ }
138
+ }
139
+ }
140
+
141
+ private static func flattenNestedDirectory(at destinationPath: String) throws {
142
+ let fileManager = FileManager.default
143
+ let destinationURL = URL(fileURLWithPath: destinationPath, isDirectory: true)
144
+ let nestedURL = destinationURL.appendingPathComponent(destinationURL.lastPathComponent)
145
+
146
+ guard fileManager.fileExists(atPath: nestedURL.path) else { return }
147
+
148
+ let nestedFiles = try fileManager.contentsOfDirectory(at: nestedURL, includingPropertiesForKeys: nil)
149
+ for file in nestedFiles {
150
+ let target = destinationURL.appendingPathComponent(file.lastPathComponent)
151
+ if fileManager.fileExists(atPath: target.path) {
152
+ try fileManager.removeItem(at: target)
153
+ }
154
+ try fileManager.moveItem(at: file, to: target)
155
+ }
156
+
157
+ try fileManager.removeItem(at: nestedURL)
158
+ }
159
+
160
+ private static func sanitize(entryName: String) -> String {
161
+ var name = entryName
162
+
163
+ if name.hasPrefix("./") {
164
+ name.removeFirst(2)
165
+ }
166
+ while name.hasPrefix("/") {
167
+ name.removeFirst()
168
+ }
169
+
170
+ guard !name.isEmpty else { return "" }
171
+
172
+ var components = name.split(separator: "/").map(String.init)
173
+ guard !components.isEmpty else { return "" }
174
+
175
+ if components.count > 1 {
176
+ components.removeFirst()
177
+ name = components.joined(separator: "/")
178
+ } else {
179
+ name = components[0]
180
+ }
181
+
182
+ return name
183
+ }
184
+
185
+ private static func remapModelFileIfNeeded(for url: URL) -> URL {
186
+ let parent = url.deletingLastPathComponent()
187
+ switch url.lastPathComponent {
188
+ case "encoder-epoch-99-avg-1.onnx":
189
+ return parent.appendingPathComponent("encoder.onnx")
190
+ case "decoder-epoch-99-avg-1.onnx":
191
+ return parent.appendingPathComponent("decoder.onnx")
192
+ case "joiner-epoch-99-avg-1.int8.onnx":
193
+ return parent.appendingPathComponent("joiner.onnx")
194
+ default:
195
+ return url
196
+ }
197
+ }
198
+
199
+ private static func makeError(code: Int, message: String) -> NSError {
200
+ return NSError(
201
+ domain: "TarBz2Extractor",
202
+ code: code,
203
+ userInfo: [NSLocalizedDescriptionKey: message]
204
+ )
205
+ }
206
+ }
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@mentra/bluetooth-sdk",
3
+ "version": "0.1.0",
4
+ "description": "SDK for communicating with smart glasses",
5
+ "main": "build/index.js",
6
+ "react-native": "src/index.ts",
7
+ "app.plugin": "app.plugin.js",
8
+ "types": "build/index.d.ts",
9
+ "files": [
10
+ "android",
11
+ "!android/.gradle",
12
+ "!android/.gradle/**",
13
+ "!android/build",
14
+ "!android/build/**",
15
+ "!android/lc3Lib/.cxx",
16
+ "!android/lc3Lib/.cxx/**",
17
+ "!android/lc3Lib/build",
18
+ "!android/lc3Lib/build/**",
19
+ "app.plugin.js",
20
+ "build",
21
+ "expo-module.config.json",
22
+ "ios",
23
+ "!ios/build",
24
+ "!ios/build/**",
25
+ "!ios/Pods",
26
+ "!ios/Pods/**",
27
+ "plugin/build",
28
+ "README.md",
29
+ "src",
30
+ "!src/__tests__"
31
+ ],
32
+ "scripts": {
33
+ "build": "expo-module build",
34
+ "build:plugin": "expo-module build plugin",
35
+ "clean": "expo-module clean",
36
+ "test": "expo-module test",
37
+ "prepare": "expo-module prepare",
38
+ "prepublishOnly": "expo-module prepublishOnly",
39
+ "lint": "expo-module lint",
40
+ "expo-module": "expo-module",
41
+ "open:ios": "xed example/ios",
42
+ "open:android": "open -a \"Android Studio\" example/android"
43
+ },
44
+ "keywords": [
45
+ "react-native",
46
+ "expo",
47
+ "smart-glasses",
48
+ "bluetooth",
49
+ "ble",
50
+ "ar-glasses"
51
+ ],
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "git+https://github.com/Mentra-Community/MentraOS.git",
55
+ "directory": "mobile/modules/bluetooth-sdk"
56
+ },
57
+ "bugs": {
58
+ "url": "https://github.com/Mentra-Community/MentraOS/issues"
59
+ },
60
+ "author": "Mentra",
61
+ "license": "MIT",
62
+ "homepage": "https://github.com/Mentra-Community/MentraOS/tree/main/mobile/modules/bluetooth-sdk#readme",
63
+ "publishConfig": {
64
+ "access": "public",
65
+ "registry": "https://registry.npmjs.org/"
66
+ },
67
+ "dependencies": {},
68
+ "devDependencies": {
69
+ "expo-module-scripts": "^55.0.2"
70
+ },
71
+ "peerDependencies": {
72
+ "@expo/config-plugins": ">=8.0.0",
73
+ "@types/react": ">=18.0.0",
74
+ "expo": ">=49.0.0",
75
+ "react": ">=18.0.0",
76
+ "react-native": ">=0.72.0"
77
+ }
78
+ }
@@ -0,0 +1,6 @@
1
+ import { type ConfigPlugin } from "expo/config-plugins";
2
+ export interface BluetoothSdkPluginProps {
3
+ node?: boolean;
4
+ }
5
+ declare const withBluetoothSdk: ConfigPlugin<BluetoothSdkPluginProps>;
6
+ export default withBluetoothSdk;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const withAndroid_1 = require("./withAndroid");
4
+ const withIos_1 = require("./withIos");
5
+ const withBluetoothSdk = (config, props) => {
6
+ // Apply Android configurations
7
+ config = (0, withAndroid_1.withAndroidConfiguration)(config, props);
8
+ // Apply iOS configurations
9
+ config = (0, withIos_1.withIosConfiguration)(config, props);
10
+ return config;
11
+ };
12
+ exports.default = withBluetoothSdk;
@@ -0,0 +1,4 @@
1
+ import { type ConfigPlugin } from "expo/config-plugins";
2
+ export declare const withAndroidConfiguration: ConfigPlugin<{
3
+ node?: boolean;
4
+ }>;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.withAndroidConfiguration = void 0;
7
+ const child_process_1 = require("child_process");
8
+ const path_1 = __importDefault(require("path"));
9
+ const config_plugins_1 = require("expo/config-plugins");
10
+ function getBluetoothSdkRoot() {
11
+ return path_1.default.dirname(require.resolve("../../package.json"));
12
+ }
13
+ function toGroovyString(value) {
14
+ return JSON.stringify(value);
15
+ }
16
+ /**
17
+ * Modify settings.gradle to include lc3Lib module
18
+ */
19
+ function withSettingsGradleModifications(config) {
20
+ return (0, config_plugins_1.withSettingsGradle)(config, (config) => {
21
+ let settingsGradle = config.modResults.contents;
22
+ // Add lc3Lib module if not present
23
+ if (!settingsGradle.includes("include ':lc3Lib'")) {
24
+ const bluetoothSdkRoot = getBluetoothSdkRoot();
25
+ settingsGradle += `
26
+ include ':lc3Lib'
27
+ project(':lc3Lib').projectDir = new File(${toGroovyString(bluetoothSdkRoot)}, 'android/lc3Lib')
28
+ `;
29
+ }
30
+ config.modResults.contents = settingsGradle;
31
+ return config;
32
+ });
33
+ }
34
+ /**
35
+ * Modify gradle.properties to add node path for native builds launched outside a shell.
36
+ */
37
+ function withGradlePropertiesModifications(config) {
38
+ return (0, config_plugins_1.withGradleProperties)(config, (config) => {
39
+ let props = config.modResults;
40
+ // Get node path and add to org.gradle.jvmargs
41
+ try {
42
+ const nodeExecutable = (0, child_process_1.execSync)("which node", { encoding: "utf-8" }).trim();
43
+ // Get parent directory of bin (e.g., /path/to/node/bin/node -> /path/to/node)
44
+ const nodePath = path_1.default.dirname(nodeExecutable);
45
+ // Find existing org.gradle.jvmargs property
46
+ const jvmArgsIndex = props.findIndex((p) => p.type === "property" && p.key === "org.gradle.jvmargs");
47
+ if (jvmArgsIndex !== -1) {
48
+ // Append nodePath to existing jvmargs if not already present
49
+ const jvmArgsProp = props[jvmArgsIndex];
50
+ if (jvmArgsProp.type === "property" && "value" in jvmArgsProp) {
51
+ const currentValue = jvmArgsProp.value;
52
+ if (!currentValue.includes("-Dorg.gradle.project.nodePath=")) {
53
+ jvmArgsProp.value = `${currentValue} -Dorg.gradle.project.nodePath=${nodePath}`;
54
+ }
55
+ }
56
+ }
57
+ else {
58
+ // Create new jvmargs property with nodePath
59
+ props.push({
60
+ type: "property",
61
+ key: "org.gradle.jvmargs",
62
+ value: `-Dorg.gradle.project.nodePath=${nodePath}`,
63
+ });
64
+ }
65
+ }
66
+ catch (error) {
67
+ console.warn("Failed to get node path:", error);
68
+ }
69
+ config.modResults = props;
70
+ return config;
71
+ });
72
+ }
73
+ const withAndroidConfiguration = (config, props) => {
74
+ config = withSettingsGradleModifications(config);
75
+ if (props?.node) {
76
+ config = withGradlePropertiesModifications(config);
77
+ }
78
+ return config;
79
+ };
80
+ exports.withAndroidConfiguration = withAndroidConfiguration;
@@ -0,0 +1,4 @@
1
+ import { type ConfigPlugin } from "expo/config-plugins";
2
+ export declare const withIosConfiguration: ConfigPlugin<{
3
+ node?: boolean;
4
+ }>;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.withIosConfiguration = void 0;
7
+ const child_process_1 = require("child_process");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const config_plugins_1 = require("expo/config-plugins");
11
+ const BLUETOOTH_SDK_EXPO_ADAPTER_ENV = "MENTRA_BLUETOOTH_SDK_INCLUDE_EXPO_ADAPTER";
12
+ const BLUETOOTH_SDK_EXPO_ADAPTER_LINE = `ENV['${BLUETOOTH_SDK_EXPO_ADAPTER_ENV}'] ||= '1'`;
13
+ const ensureBluetoothSdkExpoAdapterPodEnv = (podfile) => {
14
+ if (podfile.includes(BLUETOOTH_SDK_EXPO_ADAPTER_ENV)) {
15
+ return podfile;
16
+ }
17
+ const insertion = [
18
+ " # Expo apps need the SDK's Expo module adapter so autolinking can register BluetoothSdk.",
19
+ ` ${BLUETOOTH_SDK_EXPO_ADAPTER_LINE}`,
20
+ "",
21
+ ].join("\n");
22
+ return podfile.replace(/(target\s+['"][^'"]+['"]\s+do\n)/, `$1${insertion}`);
23
+ };
24
+ const withXcodeEnvLocal = (config) => {
25
+ return (0, config_plugins_1.withDangerousMod)(config, [
26
+ "ios",
27
+ async (config) => {
28
+ try {
29
+ // Get node executable path
30
+ const nodeExecutable = (0, child_process_1.execSync)("which node", { encoding: "utf-8" }).trim();
31
+ // Path to .xcode.env.local
32
+ const iosPath = path_1.default.join(config.modRequest.platformProjectRoot);
33
+ const xcodeEnvLocalPath = path_1.default.join(iosPath, ".xcode.env.local");
34
+ // Content to write
35
+ const content = `export NODE_BINARY=${nodeExecutable}\n`;
36
+ // Write or append to .xcode.env.local
37
+ if (fs_1.default.existsSync(xcodeEnvLocalPath)) {
38
+ const existingContent = fs_1.default.readFileSync(xcodeEnvLocalPath, "utf-8");
39
+ if (!existingContent.includes("NODE_BINARY")) {
40
+ fs_1.default.appendFileSync(xcodeEnvLocalPath, content);
41
+ }
42
+ }
43
+ else {
44
+ fs_1.default.writeFileSync(xcodeEnvLocalPath, content);
45
+ }
46
+ }
47
+ catch (error) {
48
+ console.warn("Failed to create .xcode.env.local:", error);
49
+ }
50
+ return config;
51
+ },
52
+ ]);
53
+ };
54
+ const withIosConfiguration = (config, props) => {
55
+ config = (0, config_plugins_1.withPodfile)(config, (config) => {
56
+ config.modResults.contents = ensureBluetoothSdkExpoAdapterPodEnv(config.modResults.contents);
57
+ return config;
58
+ });
59
+ if (props?.node) {
60
+ config = withXcodeEnvLocal(config);
61
+ }
62
+ return config;
63
+ };
64
+ exports.withIosConfiguration = withIosConfiguration;