@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,610 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Bridge.kt
|
|
3
|
+
// AOS
|
|
4
|
+
//
|
|
5
|
+
// Created by Matthew Fosse on 3/4/25.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
package com.mentra.bluetoothsdk
|
|
9
|
+
|
|
10
|
+
import android.util.Base64
|
|
11
|
+
import android.util.Log
|
|
12
|
+
import java.util.HashMap
|
|
13
|
+
import java.util.UUID
|
|
14
|
+
import kotlin.jvm.JvmStatic
|
|
15
|
+
import kotlin.jvm.Synchronized
|
|
16
|
+
import kotlin.jvm.Volatile
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Bridge class for SDK communication between Expo modules and native Android code This is the
|
|
20
|
+
* Android equivalent of the iOS Bridge.swift
|
|
21
|
+
*/
|
|
22
|
+
public class Bridge private constructor() {
|
|
23
|
+
private var deviceManager: DeviceManager? = null
|
|
24
|
+
|
|
25
|
+
companion object {
|
|
26
|
+
private const val TAG = "Bridge"
|
|
27
|
+
|
|
28
|
+
@Volatile private var instance: Bridge? = null
|
|
29
|
+
|
|
30
|
+
private const val DEFAULT_EVENT_SINK_ID = "default"
|
|
31
|
+
|
|
32
|
+
// Event sinks for JS and native consumers.
|
|
33
|
+
private val eventSinks = linkedMapOf<String, (String, Map<String, Any>) -> Unit>()
|
|
34
|
+
|
|
35
|
+
// Android Context for native operations
|
|
36
|
+
private var appContext: android.content.Context? = null
|
|
37
|
+
|
|
38
|
+
@JvmStatic
|
|
39
|
+
@Synchronized
|
|
40
|
+
fun getInstance(): Bridge {
|
|
41
|
+
if (instance == null) {
|
|
42
|
+
instance = Bridge()
|
|
43
|
+
}
|
|
44
|
+
return instance!!
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Initialize the Bridge with event callback and context This should be called from
|
|
49
|
+
* BluetoothSdkModule
|
|
50
|
+
*/
|
|
51
|
+
@JvmStatic
|
|
52
|
+
fun initialize(
|
|
53
|
+
context: android.content.Context,
|
|
54
|
+
callback: (String, Map<String, Any>) -> Unit
|
|
55
|
+
) {
|
|
56
|
+
Log.d(TAG, "Initializing Bridge with context and event callback")
|
|
57
|
+
initialize(context)
|
|
58
|
+
setEventSink(DEFAULT_EVENT_SINK_ID, callback)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@JvmStatic
|
|
62
|
+
fun initialize(context: android.content.Context) {
|
|
63
|
+
appContext = context
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@JvmStatic
|
|
67
|
+
@Synchronized
|
|
68
|
+
fun addEventSink(callback: (String, Map<String, Any>) -> Unit): String {
|
|
69
|
+
val id = UUID.randomUUID().toString()
|
|
70
|
+
setEventSink(id, callback)
|
|
71
|
+
return id
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@JvmStatic
|
|
75
|
+
@Synchronized
|
|
76
|
+
fun removeEventSink(id: String) {
|
|
77
|
+
eventSinks.remove(id)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@Synchronized
|
|
81
|
+
private fun setEventSink(id: String, callback: (String, Map<String, Any>) -> Unit) {
|
|
82
|
+
eventSinks[id] = callback
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@Synchronized
|
|
86
|
+
private fun getEventSinks(): List<(String, Map<String, Any>) -> Unit> {
|
|
87
|
+
return eventSinks.values.toList()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Get the Android context for native operations */
|
|
91
|
+
@JvmStatic
|
|
92
|
+
fun getContext(): android.content.Context {
|
|
93
|
+
return appContext ?: throw IllegalStateException("Bridge not initialized with context")
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Log a message and send it to JavaScript */
|
|
97
|
+
@JvmStatic
|
|
98
|
+
fun log(message: String) {
|
|
99
|
+
val data = HashMap<String, Any>()
|
|
100
|
+
data["message"] = message
|
|
101
|
+
sendTypedMessage("log", data as Map<String, Any>)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Send head position event */
|
|
105
|
+
@JvmStatic
|
|
106
|
+
fun sendHeadUp(isUp: Boolean) {
|
|
107
|
+
val data = HashMap<String, Any>()
|
|
108
|
+
data["up"] = isUp
|
|
109
|
+
sendTypedMessage("head_up", data as Map<String, Any>)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Send pair failure event */
|
|
113
|
+
@JvmStatic
|
|
114
|
+
fun sendPairFailureEvent(error: String) {
|
|
115
|
+
val data = HashMap<String, Any>()
|
|
116
|
+
data["error"] = error
|
|
117
|
+
sendTypedMessage("pair_failure", data as Map<String, Any>)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Send audio connected event - matches iOS implementation for platform parity */
|
|
121
|
+
@JvmStatic
|
|
122
|
+
fun sendAudioConnected(deviceName: String) {
|
|
123
|
+
val data = HashMap<String, Any>()
|
|
124
|
+
data["device_name"] = deviceName
|
|
125
|
+
sendTypedMessage("audio_connected", data as Map<String, Any>)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Send audio disconnected event - matches iOS implementation for platform parity */
|
|
129
|
+
@JvmStatic
|
|
130
|
+
fun sendAudioDisconnected() {
|
|
131
|
+
val data = HashMap<String, Any>()
|
|
132
|
+
sendTypedMessage("audio_disconnected", data as Map<String, Any>)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@JvmStatic
|
|
136
|
+
fun sendMicPcm(data: ByteArray) {
|
|
137
|
+
// val base64String = Base64.encodeToString(data, Base64.NO_WRAP)
|
|
138
|
+
// val body = HashMap<String, Any>()
|
|
139
|
+
// body["base64"] = base64String
|
|
140
|
+
// sendTypedMessage("mic_pcm", body as Map<String, Any>)
|
|
141
|
+
val body = HashMap<String, Any>()
|
|
142
|
+
body["pcm"] = data
|
|
143
|
+
sendTypedMessage("mic_pcm", body as Map<String, Any>)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@JvmStatic
|
|
147
|
+
fun sendMicLc3(data: ByteArray) {
|
|
148
|
+
// val base64String = Base64.encodeToString(data, Base64.NO_WRAP)
|
|
149
|
+
// val body = HashMap<String, Any>()
|
|
150
|
+
// body["base64"] = base64String
|
|
151
|
+
// sendTypedMessage("mic_lc3", body as Map<String, Any>)
|
|
152
|
+
val body = HashMap<String, Any>()
|
|
153
|
+
body["lc3"] = data
|
|
154
|
+
sendTypedMessage("mic_lc3", body as Map<String, Any>)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Save a setting */
|
|
158
|
+
@JvmStatic
|
|
159
|
+
fun saveSetting(key: String, value: Any) {
|
|
160
|
+
val body = HashMap<String, Any>()
|
|
161
|
+
body["key"] = key
|
|
162
|
+
body["value"] = value
|
|
163
|
+
sendTypedMessage("save_setting", body as Map<String, Any>)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Send VAD (Voice Activity Detection) status */
|
|
167
|
+
@JvmStatic
|
|
168
|
+
fun sendVadEvent(isSpeaking: Boolean) {
|
|
169
|
+
val body = HashMap<String, Any>()
|
|
170
|
+
body["status"] = isSpeaking
|
|
171
|
+
sendTypedMessage("vad_status", body as Map<String, Any>)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Send battery status */
|
|
175
|
+
@JvmStatic
|
|
176
|
+
fun sendBatteryStatus(level: Int, charging: Boolean) {
|
|
177
|
+
val body = HashMap<String, Any>()
|
|
178
|
+
body["level"] = level
|
|
179
|
+
body["charging"] = charging
|
|
180
|
+
body["timestamp"] = System.currentTimeMillis()
|
|
181
|
+
sendTypedMessage("battery_status", body as Map<String, Any>)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Send discovered device */
|
|
185
|
+
@JvmStatic
|
|
186
|
+
@JvmOverloads
|
|
187
|
+
fun sendDiscoveredDevice(
|
|
188
|
+
deviceModel: String,
|
|
189
|
+
deviceName: String,
|
|
190
|
+
deviceAddress: String = "",
|
|
191
|
+
rssi: Int? = null
|
|
192
|
+
) {
|
|
193
|
+
val searchResults =
|
|
194
|
+
(DeviceStore.store.getCategory("bluetooth")["searchResults"] as? List<*>)
|
|
195
|
+
?.mapNotNull { result ->
|
|
196
|
+
(result as? Map<*, *>)?.entries
|
|
197
|
+
?.mapNotNull { (key, value) ->
|
|
198
|
+
if (key is String && value != null) key to value else null
|
|
199
|
+
}
|
|
200
|
+
?.toMap()
|
|
201
|
+
}
|
|
202
|
+
?: emptyList()
|
|
203
|
+
val id = "$deviceModel:$deviceName"
|
|
204
|
+
val newResult =
|
|
205
|
+
buildMap<String, Any> {
|
|
206
|
+
put("id", id)
|
|
207
|
+
put("model", deviceModel)
|
|
208
|
+
put("name", deviceName)
|
|
209
|
+
if (deviceAddress.isNotBlank()) {
|
|
210
|
+
put("address", deviceAddress)
|
|
211
|
+
}
|
|
212
|
+
rssi?.let { put("rssi", it) }
|
|
213
|
+
}
|
|
214
|
+
val allResults = searchResults + newResult
|
|
215
|
+
val uniqueResults =
|
|
216
|
+
allResults
|
|
217
|
+
.asReversed()
|
|
218
|
+
.distinctBy {
|
|
219
|
+
val model = it["model"] ?: it["deviceModel"] ?: deviceModel
|
|
220
|
+
val name = it["name"] ?: it["deviceName"] ?: return@distinctBy null
|
|
221
|
+
"$model:$name"
|
|
222
|
+
}
|
|
223
|
+
.asReversed()
|
|
224
|
+
DeviceStore.set("bluetooth", "searchResults", uniqueResults)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// MARK: - Hardware Events
|
|
228
|
+
|
|
229
|
+
/** Send button press event to React Native - matches iOS implementation */
|
|
230
|
+
@JvmStatic
|
|
231
|
+
fun sendButtonPressEvent(buttonId: String, pressType: String) {
|
|
232
|
+
val buttonData = HashMap<String, Any>()
|
|
233
|
+
buttonData["buttonId"] = buttonId
|
|
234
|
+
buttonData["pressType"] = pressType
|
|
235
|
+
buttonData["timestamp"] = System.currentTimeMillis()
|
|
236
|
+
|
|
237
|
+
sendTypedMessage("button_press", buttonData as Map<String, Any>)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** Send miniapp selection event from glasses dashboard menu */
|
|
241
|
+
@JvmStatic
|
|
242
|
+
fun sendMiniappSelected(packageName: String) {
|
|
243
|
+
val body = HashMap<String, Any>()
|
|
244
|
+
body["packageName"] = packageName
|
|
245
|
+
sendTypedMessage("miniapp_selected", body)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Send touch/gesture event from glasses - matches iOS implementation */
|
|
249
|
+
@JvmStatic
|
|
250
|
+
@JvmOverloads
|
|
251
|
+
fun sendTouchEvent(
|
|
252
|
+
deviceModel: String,
|
|
253
|
+
gestureName: String,
|
|
254
|
+
timestamp: Long,
|
|
255
|
+
source: Int? = null
|
|
256
|
+
) {
|
|
257
|
+
val body = HashMap<String, Any>()
|
|
258
|
+
body["device_model"] = deviceModel
|
|
259
|
+
body["gesture_name"] = gestureName
|
|
260
|
+
body["timestamp"] = timestamp
|
|
261
|
+
if (source != null) {
|
|
262
|
+
body["source"] = source
|
|
263
|
+
}
|
|
264
|
+
sendTypedMessage("touch_event", body)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** Send swipe volume control status - matches iOS implementation */
|
|
268
|
+
@JvmStatic
|
|
269
|
+
fun sendSwipeVolumeStatus(enabled: Boolean, timestamp: Long) {
|
|
270
|
+
val body = HashMap<String, Any>()
|
|
271
|
+
body["enabled"] = enabled
|
|
272
|
+
body["timestamp"] = timestamp
|
|
273
|
+
sendTypedMessage("swipe_volume_status", body)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** Send switch status from glasses - matches iOS implementation */
|
|
277
|
+
@JvmStatic
|
|
278
|
+
fun sendSwitchStatus(switchType: Int, value: Int, timestamp: Long) {
|
|
279
|
+
val body = HashMap<String, Any>()
|
|
280
|
+
body["switch_type"] = switchType
|
|
281
|
+
body["switch_value"] = value
|
|
282
|
+
body["timestamp"] = timestamp
|
|
283
|
+
sendTypedMessage("switch_status", body)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
@JvmStatic
|
|
287
|
+
fun sendPhotoError(requestId: String, errorCode: String, errorMessage: String) {
|
|
288
|
+
val event = HashMap<String, Any>()
|
|
289
|
+
event["type"] = "photo_response"
|
|
290
|
+
event["state"] = "error"
|
|
291
|
+
event["requestId"] = requestId
|
|
292
|
+
event["errorCode"] = errorCode
|
|
293
|
+
event["errorMessage"] = errorMessage
|
|
294
|
+
event["timestamp"] = System.currentTimeMillis()
|
|
295
|
+
sendTypedMessage("photo_response", event as Map<String, Any>)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** Send RGB LED control response */
|
|
299
|
+
@JvmStatic
|
|
300
|
+
fun sendRgbLedControlResponse(requestId: String, success: Boolean, error: String?) {
|
|
301
|
+
if (requestId.isEmpty()) return
|
|
302
|
+
try {
|
|
303
|
+
val body = HashMap<String, Any>()
|
|
304
|
+
body["requestId"] = requestId
|
|
305
|
+
body["state"] = if (success) "success" else "error"
|
|
306
|
+
if (!success) {
|
|
307
|
+
body["errorCode"] = error ?: "unknown_error"
|
|
308
|
+
}
|
|
309
|
+
sendTypedMessage("rgb_led_control_response", body)
|
|
310
|
+
} catch (e: Exception) {
|
|
311
|
+
log("Bridge: Error sending rgb_led_control_response: $e")
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Send transcription result to server Used by AOSManager to send pre-formatted
|
|
317
|
+
* transcription results Matches the Swift structure exactly
|
|
318
|
+
*/
|
|
319
|
+
@JvmStatic
|
|
320
|
+
fun sendLocalTranscription(transcription: Map<String, Any>) {
|
|
321
|
+
val text = transcription["text"] as? String
|
|
322
|
+
if (text == null || text.isEmpty()) {
|
|
323
|
+
log("Skipping empty transcription result")
|
|
324
|
+
return
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
sendTypedMessage("local_transcription", transcription)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** Convenience method for sending local transcription from transcriber */
|
|
331
|
+
@JvmStatic
|
|
332
|
+
fun sendLocalTranscription(text: String, isFinal: Boolean, language: String) {
|
|
333
|
+
if (text.isEmpty()) {
|
|
334
|
+
log("Skipping empty transcription result")
|
|
335
|
+
return
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
val transcription =
|
|
339
|
+
mapOf(
|
|
340
|
+
"text" to text,
|
|
341
|
+
"isFinal" to isFinal,
|
|
342
|
+
"language" to language,
|
|
343
|
+
"type" to "local_transcription"
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
sendTypedMessage("local_transcription", transcription)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Bluetooth SDK bridge funcs:
|
|
350
|
+
|
|
351
|
+
/** Send status update */
|
|
352
|
+
@JvmStatic
|
|
353
|
+
fun sendStatus(statusObj: Map<String, Any>) {
|
|
354
|
+
val body = HashMap<String, Any>()
|
|
355
|
+
body["bluetooth_status"] = statusObj
|
|
356
|
+
sendTypedMessage("bluetooth_status_update", body as Map<String, Any>)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/** Send glasses serial number */
|
|
360
|
+
@JvmStatic
|
|
361
|
+
fun sendserialNumber(serialNumber: String, style: String, color: String) {
|
|
362
|
+
val serialData = HashMap<String, Any>()
|
|
363
|
+
serialData["serial_number"] = serialNumber
|
|
364
|
+
serialData["style"] = style
|
|
365
|
+
serialData["color"] = color
|
|
366
|
+
|
|
367
|
+
val body = HashMap<String, Any>()
|
|
368
|
+
body["glasses_serial_number"] = serialData
|
|
369
|
+
sendTypedMessage("glasses_serial_number", body as Map<String, Any>)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Send WiFi status change */
|
|
373
|
+
@JvmStatic
|
|
374
|
+
fun sendWifiStatusChange(connected: Boolean, ssid: String?, localIp: String?) {
|
|
375
|
+
val status = WifiStatus.fromStoreFields(connected, ssid, localIp) ?: return
|
|
376
|
+
sendTypedMessage("wifi_status_change", status.toMap())
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/** Send WiFi scan results */
|
|
380
|
+
@JvmStatic
|
|
381
|
+
fun updateWifiScanResults(networks: List<Map<String, Any>>) {
|
|
382
|
+
var storedNetworks: List<Map<String, Any>> =
|
|
383
|
+
DeviceStore.get("bluetooth", "wifiScanResults") as? List<Map<String, Any>>
|
|
384
|
+
?: emptyList()
|
|
385
|
+
// add the networks to the storedNetworks array, removing duplicates by ssid
|
|
386
|
+
val updatedNetworks = storedNetworks.toMutableList()
|
|
387
|
+
for (network in networks) {
|
|
388
|
+
if (!updatedNetworks.any { it["ssid"] as? String == network["ssid"] as? String }) {
|
|
389
|
+
updatedNetworks.add(network)
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
DeviceStore.apply("bluetooth", "wifiScanResults", updatedNetworks)
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/** Send gallery status - matches iOS MentraLive.swift handleGalleryStatus pattern */
|
|
396
|
+
@JvmStatic
|
|
397
|
+
fun sendGalleryStatus(
|
|
398
|
+
photoCount: Int,
|
|
399
|
+
videoCount: Int,
|
|
400
|
+
totalCount: Int,
|
|
401
|
+
totalSize: Long,
|
|
402
|
+
hasContent: Boolean
|
|
403
|
+
) {
|
|
404
|
+
val galleryData = HashMap<String, Any>()
|
|
405
|
+
galleryData["photos"] = photoCount
|
|
406
|
+
galleryData["videos"] = videoCount
|
|
407
|
+
galleryData["total"] = totalCount
|
|
408
|
+
galleryData["total_size"] = totalSize
|
|
409
|
+
galleryData["has_content"] = hasContent
|
|
410
|
+
|
|
411
|
+
sendTypedMessage("gallery_status", galleryData as Map<String, Any>)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/** Send hotspot status change - matches iOS MentraLive.swift emitHotspotStatusChange */
|
|
415
|
+
@JvmStatic
|
|
416
|
+
fun sendHotspotStatusChange(
|
|
417
|
+
enabled: Boolean,
|
|
418
|
+
ssid: String,
|
|
419
|
+
password: String,
|
|
420
|
+
gatewayIp: String
|
|
421
|
+
) {
|
|
422
|
+
val status = HotspotStatus.fromStoreFields(enabled, ssid, password, gatewayIp) ?: return
|
|
423
|
+
sendTypedMessage("hotspot_status_change", status.toMap())
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/** Send hotspot error - notifies React Native of hotspot failures */
|
|
427
|
+
@JvmStatic
|
|
428
|
+
fun sendHotspotError(errorMessage: String, timestamp: Long) {
|
|
429
|
+
val eventBody = HashMap<String, Any>()
|
|
430
|
+
eventBody["error_message"] = errorMessage
|
|
431
|
+
eventBody["timestamp"] = timestamp
|
|
432
|
+
|
|
433
|
+
sendTypedMessage("hotspot_error", eventBody as Map<String, Any>)
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/** Send MTK firmware update complete notification - matches iOS implementation */
|
|
437
|
+
@JvmStatic
|
|
438
|
+
fun sendMtkUpdateComplete(message: String) {
|
|
439
|
+
val eventBody = HashMap<String, Any>()
|
|
440
|
+
eventBody["message"] = message
|
|
441
|
+
eventBody["timestamp"] = System.currentTimeMillis()
|
|
442
|
+
sendTypedMessage("mtk_update_complete", eventBody as Map<String, Any>)
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Send OTA update available notification - glasses have detected an available update
|
|
447
|
+
* (background mode)
|
|
448
|
+
*/
|
|
449
|
+
@JvmStatic
|
|
450
|
+
fun sendOtaUpdateAvailable(
|
|
451
|
+
versionCode: Long,
|
|
452
|
+
versionName: String,
|
|
453
|
+
updates: List<String>,
|
|
454
|
+
totalSize: Long
|
|
455
|
+
) {
|
|
456
|
+
val eventBody = HashMap<String, Any>()
|
|
457
|
+
eventBody["version_code"] = versionCode
|
|
458
|
+
eventBody["version_name"] = versionName
|
|
459
|
+
eventBody["updates"] = updates
|
|
460
|
+
eventBody["total_size"] = totalSize
|
|
461
|
+
|
|
462
|
+
sendTypedMessage("ota_update_available", eventBody as Map<String, Any>)
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/** Send ota_start_ack — glasses confirmed receipt of ota_start command */
|
|
466
|
+
@JvmStatic
|
|
467
|
+
fun sendOtaStartAck() {
|
|
468
|
+
val eventBody = HashMap<String, Any>()
|
|
469
|
+
eventBody["timestamp"] = System.currentTimeMillis()
|
|
470
|
+
sendTypedMessage("ota_start_ack", eventBody as Map<String, Any>)
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
@JvmStatic
|
|
474
|
+
fun sendOtaStatus(
|
|
475
|
+
sessionId: String,
|
|
476
|
+
totalSteps: Int,
|
|
477
|
+
currentStep: Int,
|
|
478
|
+
stepType: String,
|
|
479
|
+
phase: String,
|
|
480
|
+
stepPercent: Int,
|
|
481
|
+
overallPercent: Int,
|
|
482
|
+
status: String,
|
|
483
|
+
errorMessage: String?
|
|
484
|
+
) {
|
|
485
|
+
val eventBody = HashMap<String, Any>()
|
|
486
|
+
eventBody["session_id"] = sessionId
|
|
487
|
+
eventBody["total_steps"] = totalSteps
|
|
488
|
+
eventBody["current_step"] = currentStep
|
|
489
|
+
eventBody["step_type"] = stepType
|
|
490
|
+
eventBody["phase"] = phase
|
|
491
|
+
eventBody["step_percent"] = stepPercent
|
|
492
|
+
eventBody["overall_percent"] = overallPercent
|
|
493
|
+
eventBody["status"] = status
|
|
494
|
+
errorMessage?.let { eventBody["error_message"] = it }
|
|
495
|
+
|
|
496
|
+
Log.d(TAG, "Bridge: sendOtaStatus: $eventBody")
|
|
497
|
+
|
|
498
|
+
sendTypedMessage("ota_status", eventBody as Map<String, Any>)
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/** Send stream status - forwards to websocket system (matches iOS) */
|
|
502
|
+
@JvmStatic
|
|
503
|
+
fun sendStreamStatus(statusJson: Map<String, Any>) {
|
|
504
|
+
sendTypedMessage("stream_status", statusJson)
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/** Send keep alive ACK - forwards to websocket system (matches iOS) */
|
|
508
|
+
@JvmStatic
|
|
509
|
+
fun sendKeepAliveAck(ackJson: Map<String, Any>) {
|
|
510
|
+
sendTypedMessage("keep_alive_ack", ackJson)
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/** Send IMU data event - matches iOS MentraLive.swift emitImuDataEvent */
|
|
514
|
+
@JvmStatic
|
|
515
|
+
fun sendImuDataEvent(
|
|
516
|
+
accel: DoubleArray,
|
|
517
|
+
gyro: DoubleArray,
|
|
518
|
+
mag: DoubleArray,
|
|
519
|
+
quat: DoubleArray,
|
|
520
|
+
euler: DoubleArray,
|
|
521
|
+
timestamp: Long
|
|
522
|
+
) {
|
|
523
|
+
val eventBody = HashMap<String, Any>()
|
|
524
|
+
eventBody["accel"] = accel.toList()
|
|
525
|
+
eventBody["gyro"] = gyro.toList()
|
|
526
|
+
eventBody["mag"] = mag.toList()
|
|
527
|
+
eventBody["quat"] = quat.toList()
|
|
528
|
+
eventBody["euler"] = euler.toList()
|
|
529
|
+
eventBody["timestamp"] = timestamp
|
|
530
|
+
|
|
531
|
+
sendTypedMessage("imu_data_event", eventBody as Map<String, Any>)
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/** Send IMU gesture event - matches iOS MentraLive.swift emitImuGestureEvent */
|
|
535
|
+
@JvmStatic
|
|
536
|
+
fun sendImuGestureEvent(gesture: String, timestamp: Long) {
|
|
537
|
+
val eventBody = HashMap<String, Any>()
|
|
538
|
+
eventBody["gesture"] = gesture
|
|
539
|
+
eventBody["timestamp"] = timestamp
|
|
540
|
+
|
|
541
|
+
sendTypedMessage("imu_gesture_event", eventBody as Map<String, Any>)
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Arbitrary WS Comms (don't use these, make a dedicated function for your use case):
|
|
545
|
+
|
|
546
|
+
/** Send WebSocket text message */
|
|
547
|
+
@JvmStatic
|
|
548
|
+
fun sendWSText(msg: String) {
|
|
549
|
+
val data = HashMap<String, Any>()
|
|
550
|
+
data["text"] = msg
|
|
551
|
+
sendTypedMessage("ws_text", data as Map<String, Any>)
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/** Send WebSocket binary message */
|
|
555
|
+
@JvmStatic
|
|
556
|
+
fun sendWSBinary(data: ByteArray) {
|
|
557
|
+
val base64String = Base64.encodeToString(data, Base64.NO_WRAP)
|
|
558
|
+
val body = HashMap<String, Any>()
|
|
559
|
+
body["base64"] = base64String
|
|
560
|
+
sendTypedMessage("ws_bin", body as Map<String, Any>)
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Send a typed message to JavaScript Don't call this function directly, instead make a
|
|
565
|
+
* function above that calls this function
|
|
566
|
+
*/
|
|
567
|
+
@JvmStatic
|
|
568
|
+
fun sendTypedMessage(type: String, body: Map<String, Any>) {
|
|
569
|
+
var mutableBody = body
|
|
570
|
+
if (body !is HashMap) {
|
|
571
|
+
mutableBody = HashMap(body)
|
|
572
|
+
}
|
|
573
|
+
(mutableBody as HashMap<String, Any>)["type"] = type
|
|
574
|
+
|
|
575
|
+
try {
|
|
576
|
+
val sinks = getEventSinks()
|
|
577
|
+
if (sinks.isEmpty()) {
|
|
578
|
+
Log.w(
|
|
579
|
+
TAG,
|
|
580
|
+
"Cannot send typed message '$type': no event sinks registered (app may be killed/backgrounded)"
|
|
581
|
+
)
|
|
582
|
+
return
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// Send directly using type as event name - no JSON serialization
|
|
586
|
+
sinks.forEach { sink ->
|
|
587
|
+
try {
|
|
588
|
+
sink(type, mutableBody as Map<String, Any>)
|
|
589
|
+
} catch (e: Exception) {
|
|
590
|
+
Log.e(
|
|
591
|
+
TAG,
|
|
592
|
+
"Error invoking event sink for type '$type' (listener may be dead)",
|
|
593
|
+
e
|
|
594
|
+
)
|
|
595
|
+
// Don't rethrow - one dead listener should not break other consumers.
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
} catch (e: Exception) {
|
|
599
|
+
Log.e(TAG, "Error sending typed message of type '$type'", e)
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
init {
|
|
605
|
+
deviceManager = DeviceManager.Companion.getInstance()
|
|
606
|
+
if (deviceManager == null) {
|
|
607
|
+
Log.e(TAG, "Failed to initialize DeviceManager in Bridge constructor")
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|