@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.
- package/README.md +278 -0
- package/android/build.gradle +167 -0
- package/android/lc3Lib/CMakeLists.txt +6 -0
- package/android/lc3Lib/build.gradle +109 -0
- package/android/lc3Lib/proguard-rules.pro +33 -0
- package/android/lc3Lib/src/main/AndroidManifest.xml +2 -0
- package/android/lc3Lib/src/main/cpp/CMakeLists.txt +8 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/CMakeLists.txt +30 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/CMakeLists.txt +7 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.cc +96 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.h +53 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/Makefile.am +6 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h +26 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h.in +26 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/ogg.h +209 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/os_types.h +158 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus.h +981 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_custom.h +342 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_defines.h +799 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_multistream.h +660 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_projection.h +568 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_types.h +166 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.cc +268 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.h +115 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/opus_tools/opus_header.h +59 -0
- package/android/lc3Lib/src/main/cpp/liblc3/CMakeLists.txt +38 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/lc3.h +309 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/lc3_private.h +162 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/rnnoise.h +114 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/CMakeLists.txt +19 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.c +92 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.h +44 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.c +375 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.h +315 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.c +129 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.h +69 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/common.h +148 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.c +70 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.h +43 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/fastmath.h +158 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/lc3.c +702 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.c +893 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.h +111 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_arm.h +506 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_neon.h +281 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/makefile.mk +35 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.c +452 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.h +57 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct_neon.h +296 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/meson.build +46 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.c +61 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.h +57 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.c +880 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.h +103 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.c +904 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.h +119 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.c +3457 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.h +94 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.c +457 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.h +99 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3.cpp +159 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/_kiss_fft_guts.h +182 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/arch.h +261 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.c +279 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.h +59 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/common.h +48 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/compile.sh +3 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/denoise.c +646 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.c +601 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.h +203 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/opus_types.h +159 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.c +526 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.h +149 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.c +178 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.h +69 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.c +11051 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.h +34 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_reader.c +168 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_train.py +66 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/tansig_table.h +45 -0
- package/android/lc3Lib/src/main/java/com/mentra/lc3Lib/Lc3Cpp.java +38 -0
- package/android/lc3Lib/third_party/CMakeLists.txt +23 -0
- package/android/lc3Lib/third_party/CMakeLists_libogg.txt +18 -0
- package/android/lc3Lib/third_party/CMakeLists_libopus.txt +18 -0
- package/android/lc3Lib/third_party/CMakeLists_opus-tools.txt +23 -0
- package/android/lc3Lib/third_party/opus_tools/src/AUTHORS +5 -0
- package/android/lc3Lib/third_party/opus_tools/src/CMakeLists.txt +4 -0
- package/android/lc3Lib/third_party/opus_tools/src/COPYING +371 -0
- package/android/lc3Lib/third_party/opus_tools/src/ChangeLog +3 -0
- package/android/lc3Lib/third_party/opus_tools/src/Makefile.am +42 -0
- package/android/lc3Lib/third_party/opus_tools/src/Makefile.unix +23 -0
- package/android/lc3Lib/third_party/opus_tools/src/NEWS +0 -0
- package/android/lc3Lib/third_party/opus_tools/src/README +0 -0
- package/android/lc3Lib/third_party/opus_tools/src/autogen.sh +115 -0
- package/android/lc3Lib/third_party/opus_tools/src/configure.ac +293 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/arch.h +239 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/audio-in.c +1046 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.c +245 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.h +28 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.c +320 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.h +51 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/lpc.c +157 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/lpc.h +27 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.c +286 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.h +59 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusdec.c +884 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.c +1021 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.h +101 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.c +639 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.h +51 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/os_support.h +167 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/resample.c +1137 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/speex_resampler.h +344 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/stack_alloc.h +115 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.c +125 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.h +62 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.c +223 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.h +60 -0
- package/android/settings.gradle +1 -0
- package/android/src/main/AndroidManifest.xml +40 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +528 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +610 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +1616 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +314 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +1710 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +554 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/ObservableStore.kt +68 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +158 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +934 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/services/Foreground.kt +175 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +1109 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +3974 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3551 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1327 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +6959 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1655 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraosBle.java +53675 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +202 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +224 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/STTTools.kt +340 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +465 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/VadGateSpeechPolicy.kt +221 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/AES.java +106 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/AudioSessionMonitor.kt +189 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/BitmapJavaUtils.java +169 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadService.java +179 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +44 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/G1Text.kt +436 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleRelayNaming.java +29 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleUploadService.java +76 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtils.java +791 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunker.java +186 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/NexSGCUtils.kt +589 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/PhoneAudioMonitor.kt +303 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/SmartGlassesConnectionState.java +9 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/ByteUtilAudioPlayer.java +655 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/Lc3Player.java +441 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/PCMAudioPlayer.java +431 -0
- package/android/src/main/res/values/strings.xml +4 -0
- package/app.plugin.js +1 -0
- package/build/BluetoothSdk.types.d.ts +498 -0
- package/build/BluetoothSdk.types.d.ts.map +1 -0
- package/build/BluetoothSdk.types.js +23 -0
- package/build/BluetoothSdk.types.js.map +1 -0
- package/build/BluetoothSdkModule.d.ts +71 -0
- package/build/BluetoothSdkModule.d.ts.map +1 -0
- package/build/BluetoothSdkModule.js +106 -0
- package/build/BluetoothSdkModule.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +5 -0
- package/build/index.js.map +1 -0
- package/expo-module.config.json +9 -0
- package/ios/BluetoothSdkModule.swift +665 -0
- package/ios/MentraBluetoothSDK.podspec +77 -0
- package/ios/Packages/CoreObjC/CoreObjC.xcodeproj/project.pbxproj +213 -0
- package/ios/Packages/CoreObjC/PcmConverter.h +22 -0
- package/ios/Packages/CoreObjC/PcmConverter.m +266 -0
- package/ios/Packages/CoreObjC/attdet.c +92 -0
- package/ios/Packages/CoreObjC/attdet.h +44 -0
- package/ios/Packages/CoreObjC/bits.c +375 -0
- package/ios/Packages/CoreObjC/bits.h +315 -0
- package/ios/Packages/CoreObjC/bwdet.c +129 -0
- package/ios/Packages/CoreObjC/bwdet.h +69 -0
- package/ios/Packages/CoreObjC/common.h +151 -0
- package/ios/Packages/CoreObjC/energy.c +70 -0
- package/ios/Packages/CoreObjC/energy.h +43 -0
- package/ios/Packages/CoreObjC/fastmath.h +158 -0
- package/ios/Packages/CoreObjC/lc3.c +704 -0
- package/ios/Packages/CoreObjC/lc3.h +313 -0
- package/ios/Packages/CoreObjC/lc3_cpp.h +283 -0
- package/ios/Packages/CoreObjC/lc3_private.h +163 -0
- package/ios/Packages/CoreObjC/ltpf.c +905 -0
- package/ios/Packages/CoreObjC/ltpf.h +111 -0
- package/ios/Packages/CoreObjC/ltpf_arm.h +506 -0
- package/ios/Packages/CoreObjC/ltpf_neon.h +281 -0
- package/ios/Packages/CoreObjC/makefile.mk +35 -0
- package/ios/Packages/CoreObjC/mdct.c +469 -0
- package/ios/Packages/CoreObjC/mdct.h +57 -0
- package/ios/Packages/CoreObjC/mdct_neon.h +296 -0
- package/ios/Packages/CoreObjC/meson.build +61 -0
- package/ios/Packages/CoreObjC/plc.c +61 -0
- package/ios/Packages/CoreObjC/plc.h +57 -0
- package/ios/Packages/CoreObjC/rnnoise.h +114 -0
- package/ios/Packages/CoreObjC/sns.c +880 -0
- package/ios/Packages/CoreObjC/sns.h +103 -0
- package/ios/Packages/CoreObjC/spec.c +907 -0
- package/ios/Packages/CoreObjC/spec.h +119 -0
- package/ios/Packages/CoreObjC/tables.c +3457 -0
- package/ios/Packages/CoreObjC/tables.h +94 -0
- package/ios/Packages/CoreObjC/tns.c +457 -0
- package/ios/Packages/CoreObjC/tns.h +99 -0
- package/ios/Packages/SherpaOnnx/Model/joiner.onnx +0 -0
- package/ios/Packages/SherpaOnnx/Model/tokens.txt +502 -0
- package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +1659 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/cargs.h +162 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/c-api.h +1852 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/cxx-api.h +674 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +44 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/libsherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/sherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/sherpa-onnx.a +0 -0
- package/ios/Packages/VAD/Common/VAD/VADQuality.swift +41 -0
- package/ios/Packages/VAD/Common/VAD/VADState.swift +26 -0
- package/ios/Packages/VAD/Common/VAD/VADStrategy.swift +29 -0
- package/ios/Packages/VAD/Common/VAD/VADType.swift +14 -0
- package/ios/Packages/VAD/Data/Configuration.swift +68 -0
- package/ios/Packages/VAD/Data/FrameSize.swift +39 -0
- package/ios/Packages/VAD/Data/Record.swift +13 -0
- package/ios/Packages/VAD/Data/Result.swift +22 -0
- package/ios/Packages/VAD/Data/SampleRate.swift +48 -0
- package/ios/Packages/VAD/Silero/Model/silero_vad.onnx +0 -0
- package/ios/Packages/VAD/Silero/SileroVAD.swift +284 -0
- package/ios/Packages/VAD/Silero/SileroVADStrategy.swift +64 -0
- package/ios/Packages/libbz2/module.modulemap +5 -0
- package/ios/Packages/libbz2/shim.h +1 -0
- package/ios/Source/Bridge.swift +353 -0
- package/ios/Source/Bridging-Header.h +16 -0
- package/ios/Source/DeviceManager.swift +1478 -0
- package/ios/Source/DeviceStore.swift +295 -0
- package/ios/Source/MentraBluetoothSDK.swift +2439 -0
- package/ios/Source/ObservableStore.swift +88 -0
- package/ios/Source/PrivacyInfo.xcprivacy +23 -0
- package/ios/Source/controllers/ControllerManager.swift +187 -0
- package/ios/Source/controllers/R1.swift +827 -0
- package/ios/Source/services/PhoneMic.swift +662 -0
- package/ios/Source/sgcs/Frame.swift +651 -0
- package/ios/Source/sgcs/G1.swift +2505 -0
- package/ios/Source/sgcs/G2.swift +3730 -0
- package/ios/Source/sgcs/Mach1.swift +543 -0
- package/ios/Source/sgcs/MentraLive.swift +4708 -0
- package/ios/Source/sgcs/MentraNex.swift +2479 -0
- package/ios/Source/sgcs/SGCManager.swift +243 -0
- package/ios/Source/sgcs/Simulated.swift +270 -0
- package/ios/Source/sgcs/mentraos_ble.pb.swift +3811 -0
- package/ios/Source/stt/STTTools.swift +154 -0
- package/ios/Source/stt/SherpaOnnxTranscriber.swift +401 -0
- package/ios/Source/utils/AudioSessionMonitor.swift +283 -0
- package/ios/Source/utils/Constants.swift +74 -0
- package/ios/Source/utils/Enums.swift +95 -0
- package/ios/Source/utils/G1Text.swift +2067 -0
- package/ios/Source/utils/JSCExperiment.swift +241 -0
- package/ios/Source/utils/MemoryMonitor.swift +44 -0
- package/ios/Source/utils/MessageChunker.swift +164 -0
- package/ios/Source/utils/Models.swift +135 -0
- package/ios/Source/utils/PhoneAudioMonitor.swift +226 -0
- package/ios/Source/utils/TarBz2Extractor.swift +206 -0
- package/package.json +78 -0
- package/plugin/build/index.d.ts +6 -0
- package/plugin/build/index.js +12 -0
- package/plugin/build/withAndroid.d.ts +4 -0
- package/plugin/build/withAndroid.js +80 -0
- package/plugin/build/withIos.d.ts +4 -0
- package/plugin/build/withIos.js +64 -0
- package/src/BluetoothSdk.types.ts +581 -0
- package/src/BluetoothSdkModule.ts +259 -0
- 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,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,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,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;
|