@glassly/bluetooth-sdk 0.1.0-dev.26
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 +563 -0
- package/android/build.gradle +450 -0
- package/android/gradle.properties.example +9 -0
- package/android/lc3Lib/CMakeLists.txt +6 -0
- package/android/lc3Lib/build.gradle +212 -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/glassly/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 +4 -0
- package/android/silero/LICENSE.md +17 -0
- package/android/silero/build.gradle +50 -0
- package/android/silero/proguard-rules.pro +24 -0
- package/android/silero/src/androidTest/assets/hello.wav +0 -0
- package/android/silero/src/androidTest/java/com/konovalov/vad/silero/VadSileroTest.kt +79 -0
- package/android/silero/src/main/assets/LICENSE +21 -0
- package/android/silero/src/main/assets/silero_vad.onnx +0 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/Vad.kt +160 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/VadSilero.kt +449 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/config/FrameSize.kt +15 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/config/Mode.kt +14 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/config/SampleRate.kt +12 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/utils/AudioUtils.kt +47 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/utils/TensorMap.kt +41 -0
- package/android/silero/src/test/java/com/konovalov/vad/silero/utils/AudioUtilsTest.kt +44 -0
- package/android/src/main/AndroidManifest.xml +42 -0
- package/android/src/main/assets/G2Firmware/README.md +11 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdk.kt +2325 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkAnalytics.kt +216 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkDebug.kt +14 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkDefaults.kt +7 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkModule.kt +1088 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/Bridge.kt +953 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/DeviceManager.kt +2528 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/DeviceStore.kt +360 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedChangelogCatalog.kt +8 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedReleaseMetadata.kt +11 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/LocalNetworkModule.kt +414 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/ObservableStore.kt +88 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/OtaManifest.kt +191 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/ReleaseChangelog.kt +61 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/ScopedNetworkReadiness.kt +17 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/audio/AudioModels.kt +144 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/camera/CameraModels.kt +486 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/connection/ConnectionModels.kt +78 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/controllers/ControllerManager.kt +158 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/controllers/R1.kt +937 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/debug/BleTraceLogger.kt +165 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/events/BluetoothEvents.kt +178 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/internal/MapParsing.kt +140 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/net/LocalIpv4.kt +57 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/otaserver/LocalOtaServer.kt +304 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/otaserver/OtaServerModule.kt +120 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistry.java +108 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoUploadServer.kt +622 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/PhotoReceiverModule.kt +156 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/requests/DisplayRequests.kt +56 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/services/Foreground.kt +272 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/services/PhoneMic.kt +1195 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Ar99.java +2653 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/BesOtaHeartbeatGuard.kt +49 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/BesOtaProgressMapper.kt +27 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G1.kt +3878 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G1TextSanitizer.kt +38 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2.kt +6428 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwClassification.kt +49 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwRenderer.kt +1241 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwTextureCache.kt +270 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2FlashProtocol.kt +291 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2Flasher.kt +411 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/GlasslyBle.java +43189 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Mach1.kt +1280 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLive.kt +10817 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLiveL2capChannel.kt +274 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLivePairingAdvertisement.kt +54 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraNex.kt +2011 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Nimo.kt +2532 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/SGCManager.kt +470 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Simulated.kt +228 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/Ar99OtaManager.java +566 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaByteUtils.java +18 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaCommandConstants.java +35 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaCrc32Util.java +13 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaGattTransport.java +11 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaProtocol.java +92 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/speakerid/SpeakerIdEngine.kt +525 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/status/DeviceStatus.kt +669 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/status/RuntimeState.kt +201 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/status/WifiHotspotStatus.kt +189 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/streaming/StreamModels.kt +518 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/stt/STTTools.kt +391 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +518 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/stt/VadGateSpeechPolicy.kt +229 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/tts/TTSTools.kt +248 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/types/DeviceModels.kt +96 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/AES.java +106 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/AudioSessionMonitor.kt +189 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/AvifExifStripper.java +573 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/BitmapJavaUtils.java +169 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/BleJsonCompact.java +496 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/BlePhotoUploadService.java +677 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/BleWireProtocol.java +108 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/Constants.kt +46 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/G1Text.kt +436 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/HeifExifTagReader.java +199 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/IncidentLogBleRelayNaming.java +29 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/IncidentLogBleUploadService.java +77 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/K900LengthCodec.java +115 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtils.java +827 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/MessageChunkReassembler.java +228 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/MessageChunker.java +325 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/NexSGCUtils.kt +698 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/PhoneAudioMonitor.kt +348 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/SmartGlassesConnectionState.java +9 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/Ar99OpusPcmDecoder.java +398 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/ByteUtilAudioPlayer.java +655 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/Lc3Player.java +441 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/PCMAudioPlayer.java +431 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/PcmStreamPlayer.kt +328 -0
- package/android/src/main/res/values/strings.xml +4 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/BluetoothSdkExceptionTest.kt +18 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/OtaManifestDowngradeTest.kt +86 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/OtaStartResponsePolicyTest.kt +30 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/ReleaseChangelogTest.kt +13 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/ScopedNetworkReadinessTest.kt +39 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/StreamStatusEventTest.kt +29 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/camera/PhotoRequestTest.kt +141 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/otaserver/LocalOtaServerTest.kt +82 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistryTest.java +75 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/services/ForegroundServiceTypeTest.kt +69 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/Ar99AdvertisementMatcherTest.java +22 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/BesOtaHeartbeatGuardTest.kt +73 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/BesOtaProgressMapperTest.kt +67 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/EvenRleTest.kt +63 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G1TextSanitizerTest.kt +31 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwClassificationTest.kt +89 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwRendererTest.kt +344 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwTextureCacheTest.kt +200 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2FlashProtocolTest.kt +131 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/MentraLiveGattCharacteristicsTest.kt +39 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/MentraLivePairingAdvertisementParserTest.kt +133 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/NimoProtocolTest.kt +333 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/AvifExifStripperTest.java +46 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/BinaryMessageChunkerTest.java +84 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/BleJsonCompactTest.java +319 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/BlePhotoUploadServiceTest.java +107 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtilsEndiannessTest.java +172 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtilsTest.java +24 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/PhoneAudioMonitorTest.kt +45 -0
- package/android/src/test/resources/avif_with_exif.avif +0 -0
- package/app.plugin.js +3 -0
- package/build/BluetoothSdk.types.d.ts +1354 -0
- package/build/BluetoothSdk.types.d.ts.map +1 -0
- package/build/BluetoothSdk.types.js +41 -0
- package/build/BluetoothSdk.types.js.map +1 -0
- package/build/_internal.d.ts +17 -0
- package/build/_internal.d.ts.map +1 -0
- package/build/_internal.js +16 -0
- package/build/_internal.js.map +1 -0
- package/build/_private/BluetoothSdkModule.d.ts +172 -0
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -0
- package/build/_private/BluetoothSdkModule.js +300 -0
- package/build/_private/BluetoothSdkModule.js.map +1 -0
- package/build/_private/LocalNetworkModule.d.ts +38 -0
- package/build/_private/LocalNetworkModule.d.ts.map +1 -0
- package/build/_private/LocalNetworkModule.js +3 -0
- package/build/_private/LocalNetworkModule.js.map +1 -0
- package/build/_private/cameraRequestPayload.d.ts +4 -0
- package/build/_private/cameraRequestPayload.d.ts.map +1 -0
- package/build/_private/cameraRequestPayload.js +32 -0
- package/build/_private/cameraRequestPayload.js.map +1 -0
- package/build/_private/photoRequestPayload.d.ts +6 -0
- package/build/_private/photoRequestPayload.d.ts.map +1 -0
- package/build/_private/photoRequestPayload.js +86 -0
- package/build/_private/photoRequestPayload.js.map +1 -0
- package/build/_private/sdkOtaManifest.d.ts +11 -0
- package/build/_private/sdkOtaManifest.d.ts.map +1 -0
- package/build/_private/sdkOtaManifest.js +15 -0
- package/build/_private/sdkOtaManifest.js.map +1 -0
- package/build/changelogs.d.ts +7 -0
- package/build/changelogs.d.ts.map +1 -0
- package/build/changelogs.js +46 -0
- package/build/changelogs.js.map +1 -0
- package/build/debug.d.ts +3 -0
- package/build/debug.d.ts.map +1 -0
- package/build/debug.js +8 -0
- package/build/debug.js.map +1 -0
- package/build/generated/changelogCatalog.d.ts +9 -0
- package/build/generated/changelogCatalog.d.ts.map +1 -0
- package/build/generated/changelogCatalog.js +12 -0
- package/build/generated/changelogCatalog.js.map +1 -0
- package/build/generated/releaseMetadata.d.ts +12 -0
- package/build/generated/releaseMetadata.d.ts.map +1 -0
- package/build/generated/releaseMetadata.js +10 -0
- package/build/generated/releaseMetadata.js.map +1 -0
- package/build/index.d.ts +6 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +171 -0
- package/build/index.js.map +1 -0
- package/build/ota-server/OtaServer.types.d.ts +14 -0
- package/build/ota-server/OtaServer.types.d.ts.map +1 -0
- package/build/ota-server/OtaServer.types.js +2 -0
- package/build/ota-server/OtaServer.types.js.map +1 -0
- package/build/ota-server/OtaServerModule.d.ts +21 -0
- package/build/ota-server/OtaServerModule.d.ts.map +1 -0
- package/build/ota-server/OtaServerModule.js +3 -0
- package/build/ota-server/OtaServerModule.js.map +1 -0
- package/build/ota-server/OtaServerModule.web.d.ts +10 -0
- package/build/ota-server/OtaServerModule.web.d.ts.map +1 -0
- package/build/ota-server/OtaServerModule.web.js +12 -0
- package/build/ota-server/OtaServerModule.web.js.map +1 -0
- package/build/ota-server/index.d.ts +3 -0
- package/build/ota-server/index.d.ts.map +1 -0
- package/build/ota-server/index.js +3 -0
- package/build/ota-server/index.js.map +1 -0
- package/build/ota-transport/index.d.ts +67 -0
- package/build/ota-transport/index.d.ts.map +1 -0
- package/build/ota-transport/index.js +58 -0
- package/build/ota-transport/index.js.map +1 -0
- package/build/photo-receiver/PhotoReceiver.types.d.ts +18 -0
- package/build/photo-receiver/PhotoReceiver.types.d.ts.map +1 -0
- package/build/photo-receiver/PhotoReceiver.types.js +2 -0
- package/build/photo-receiver/PhotoReceiver.types.js.map +1 -0
- package/build/photo-receiver/PhotoReceiverModule.d.ts +10 -0
- package/build/photo-receiver/PhotoReceiverModule.d.ts.map +1 -0
- package/build/photo-receiver/PhotoReceiverModule.js +3 -0
- package/build/photo-receiver/PhotoReceiverModule.js.map +1 -0
- package/build/photo-receiver/PhotoReceiverModule.web.d.ts +10 -0
- package/build/photo-receiver/PhotoReceiverModule.web.d.ts.map +1 -0
- package/build/photo-receiver/PhotoReceiverModule.web.js +12 -0
- package/build/photo-receiver/PhotoReceiverModule.web.js.map +1 -0
- package/build/photo-receiver/index.d.ts +3 -0
- package/build/photo-receiver/index.d.ts.map +1 -0
- package/build/photo-receiver/index.js +3 -0
- package/build/photo-receiver/index.js.map +1 -0
- package/build/react/index.d.ts +5 -0
- package/build/react/index.d.ts.map +1 -0
- package/build/react/index.js +4 -0
- package/build/react/index.js.map +1 -0
- package/build/react/useBluetooth.d.ts +100 -0
- package/build/react/useBluetooth.d.ts.map +1 -0
- package/build/react/useBluetooth.js +167 -0
- package/build/react/useBluetooth.js.map +1 -0
- package/build/react/useBluetoothEvent.d.ts +6 -0
- package/build/react/useBluetoothEvent.d.ts.map +1 -0
- package/build/react/useBluetoothEvent.js +21 -0
- package/build/react/useBluetoothEvent.js.map +1 -0
- package/build/react/useBluetoothScan.d.ts +22 -0
- package/build/react/useBluetoothScan.d.ts.map +1 -0
- package/build/react/useBluetoothScan.js +135 -0
- package/build/react/useBluetoothScan.js.map +1 -0
- package/build/react/useBluetoothStatus.d.ts +16 -0
- package/build/react/useBluetoothStatus.d.ts.map +1 -0
- package/build/react/useBluetoothStatus.js +137 -0
- package/build/react/useBluetoothStatus.js.map +1 -0
- package/build/react/useGlassesConnection.d.ts +29 -0
- package/build/react/useGlassesConnection.d.ts.map +1 -0
- package/build/react/useGlassesConnection.js +153 -0
- package/build/react/useGlassesConnection.js.map +1 -0
- package/build/types/index.d.ts +3 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/index.js +2 -0
- package/build/types/index.js.map +1 -0
- package/expo-module.config.json +14 -0
- package/ios/BackgroundOtaArtifactDownloader.swift +125 -0
- package/ios/BluetoothSdkModule.swift +1034 -0
- package/ios/GlasslyBluetoothSDK.podspec +106 -0
- package/ios/LocalIPv4.swift +150 -0
- package/ios/LocalOtaServer.swift +309 -0
- package/ios/LocalPhotoUploadServer.swift +754 -0
- package/ios/OtaServerModule.swift +147 -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/include/PcmConverter.h +22 -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 +2383 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +48 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/c-api.h +4689 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/cxx-api.h +2036 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/libsherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/Headers/sherpa-onnx/c-api/c-api.h +4689 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/Headers/sherpa-onnx/c-api/cxx-api.h +2036 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
- package/ios/Packages/libbz2/module.modulemap +5 -0
- package/ios/Packages/libbz2/shim.h +1 -0
- package/ios/PhotoReceiverModule.swift +129 -0
- package/ios/Source/BluetoothSDK.swift +2303 -0
- package/ios/Source/BluetoothSDKDebug.swift +12 -0
- package/ios/Source/BluetoothSdkDefaults.swift +29 -0
- package/ios/Source/Bridge.swift +708 -0
- package/ios/Source/Bridging-Header.h +16 -0
- package/ios/Source/DeviceManager.swift +2109 -0
- package/ios/Source/DeviceStore.swift +336 -0
- package/ios/Source/GeneratedChangelogCatalog.swift +7 -0
- package/ios/Source/GeneratedReleaseMetadata.swift +11 -0
- package/ios/Source/ObservableStore.swift +118 -0
- package/ios/Source/OtaManifest.swift +211 -0
- package/ios/Source/PrivacyInfo.xcprivacy +23 -0
- package/ios/Source/ReleaseChangelog.swift +65 -0
- package/ios/Source/Resources/G2Firmware/README.md +10 -0
- package/ios/Source/audio/AudioModels.swift +178 -0
- package/ios/Source/audio/PcmStreamPlayer.swift +410 -0
- package/ios/Source/camera/CameraModels.swift +866 -0
- package/ios/Source/connection/ScanSession.swift +27 -0
- package/ios/Source/controllers/ControllerManager.swift +184 -0
- package/ios/Source/controllers/R1.swift +829 -0
- package/ios/Source/errors/BluetoothSdkError.swift +19 -0
- package/ios/Source/events/BluetoothEvents.swift +342 -0
- package/ios/Source/internal/BleTraceLogger.swift +192 -0
- package/ios/Source/internal/BluetoothAvailability.swift +78 -0
- package/ios/Source/internal/BluetoothSdkAnalytics.swift +199 -0
- package/ios/Source/internal/ValueParsing.swift +99 -0
- package/ios/Source/requests/DisplayRequests.swift +82 -0
- package/ios/Source/services/PhoneMic.swift +662 -0
- package/ios/Source/sgcs/Ar99.swift +2451 -0
- package/ios/Source/sgcs/Frame.swift +649 -0
- package/ios/Source/sgcs/G1.swift +2554 -0
- package/ios/Source/sgcs/G2.swift +6887 -0
- package/ios/Source/sgcs/G2CfwClassification.swift +43 -0
- package/ios/Source/sgcs/G2CfwRenderer.swift +1279 -0
- package/ios/Source/sgcs/G2CfwTextureCache.swift +233 -0
- package/ios/Source/sgcs/G2FlashProtocol.swift +312 -0
- package/ios/Source/sgcs/G2Flasher.swift +773 -0
- package/ios/Source/sgcs/Mach1.swift +541 -0
- package/ios/Source/sgcs/MentraLive.swift +7011 -0
- package/ios/Source/sgcs/MentraLiveL2capChannel.swift +183 -0
- package/ios/Source/sgcs/MentraLivePairingAdvertisement.swift +64 -0
- package/ios/Source/sgcs/MentraNex.swift +3221 -0
- package/ios/Source/sgcs/Nimo.swift +1886 -0
- package/ios/Source/sgcs/SGCManager.swift +608 -0
- package/ios/Source/sgcs/Simulated.swift +274 -0
- package/ios/Source/sgcs/ar99/ota/Ar99OtaManager.swift +637 -0
- package/ios/Source/sgcs/glassly_ble.pb.swift +4354 -0
- package/ios/Source/speakerid/SpeakerIdEngine.swift +573 -0
- package/ios/Source/status/DeviceStatus.swift +981 -0
- package/ios/Source/status/RuntimeState.swift +359 -0
- package/ios/Source/status/WifiHotspotStatus.swift +345 -0
- package/ios/Source/streaming/StreamModels.swift +693 -0
- package/ios/Source/stt/STTTools.swift +191 -0
- package/ios/Source/stt/SherpaOnnxTranscriber.swift +466 -0
- package/ios/Source/tts/TTSTools.swift +171 -0
- package/ios/Source/types/DeviceModels.swift +177 -0
- package/ios/Source/utils/AudioSessionMonitor.swift +283 -0
- package/ios/Source/utils/BinaryCodec.swift +61 -0
- package/ios/Source/utils/BleJsonCompact.swift +405 -0
- package/ios/Source/utils/BleWireProtocol.swift +92 -0
- package/ios/Source/utils/Constants.swift +78 -0
- package/ios/Source/utils/Enums.swift +95 -0
- package/ios/Source/utils/G1Text.swift +2096 -0
- package/ios/Source/utils/JSCExperiment.swift +241 -0
- package/ios/Source/utils/MemoryMonitor.swift +44 -0
- package/ios/Source/utils/MessageChunkReassembler.swift +190 -0
- package/ios/Source/utils/MessageChunker.swift +294 -0
- package/ios/Source/utils/Models.swift +135 -0
- package/ios/Source/utils/PhoneAudioMonitor.swift +230 -0
- package/ios/Source/utils/TarBz2Extractor.swift +257 -0
- package/ios/Tests/BluetoothSDKTests/G2CfwClassificationTests.swift +78 -0
- package/ios/Tests/BluetoothSDKTests/G2CfwRendererTests.swift +372 -0
- package/ios/Tests/BluetoothSDKTests/G2CfwTextureCacheTests.swift +162 -0
- package/ios/Tests/BluetoothSDKTests/G2FlashProtocolTests.swift +182 -0
- package/ios/Tests/MentraLivePairingAdvertisementTests.swift +160 -0
- package/ios/Tests/ReleaseChangelogTests.swift +13 -0
- package/package.json +129 -0
- package/plugin/build/index.d.ts +10 -0
- package/plugin/build/index.js +12 -0
- package/plugin/build/withAndroid.d.ts +3 -0
- package/plugin/build/withAndroid.js +190 -0
- package/plugin/build/withIos.d.ts +5 -0
- package/plugin/build/withIos.js +108 -0
- package/scripts/inject-ios-sdk-version.mjs +65 -0
- package/scripts/public-ota-api.test.mjs +37 -0
- package/scripts/verify-release-package.mjs +45 -0
- package/scripts/write-release-metadata.mjs +152 -0
- package/scripts/write-release-metadata.test.mjs +37 -0
- package/src/BluetoothSdk.types.ts +1623 -0
- package/src/_internal.ts +16 -0
- package/src/_private/BluetoothSdkModule.ts +684 -0
- package/src/_private/LocalNetworkModule.ts +50 -0
- package/src/_private/cameraRequestPayload.ts +34 -0
- package/src/_private/photoRequestPayload.ts +90 -0
- package/src/_private/sdkOtaManifest.ts +18 -0
- package/src/changelogs.ts +46 -0
- package/src/debug.ts +9 -0
- package/src/generated/changelogCatalog.ts +13 -0
- package/src/generated/releaseMetadata.ts +20 -0
- package/src/index.ts +321 -0
- package/src/ota-server/OtaServer.types.ts +10 -0
- package/src/ota-server/OtaServerModule.ts +23 -0
- package/src/ota-server/OtaServerModule.web.ts +17 -0
- package/src/ota-server/index.ts +2 -0
- package/src/ota-transport/index.ts +116 -0
- package/src/photo-receiver/PhotoReceiver.types.ts +20 -0
- package/src/photo-receiver/PhotoReceiverModule.ts +11 -0
- package/src/photo-receiver/PhotoReceiverModule.web.ts +17 -0
- package/src/photo-receiver/index.ts +2 -0
- package/src/react/index.ts +21 -0
- package/src/react/useBluetooth.ts +309 -0
- package/src/react/useBluetoothEvent.ts +35 -0
- package/src/react/useBluetoothScan.ts +173 -0
- package/src/react/useBluetoothStatus.ts +180 -0
- package/src/react/useGlassesConnection.ts +202 -0
- package/src/types/index.ts +12 -0
|
@@ -0,0 +1,953 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Bridge.kt
|
|
3
|
+
// AOS
|
|
4
|
+
//
|
|
5
|
+
// Created by Matthew Fosse on 3/4/25.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
package com.glassly.bluetoothsdk
|
|
9
|
+
|
|
10
|
+
import android.util.Base64
|
|
11
|
+
import android.util.Log
|
|
12
|
+
import com.glassly.bluetoothsdk.debug.BleTraceLogger
|
|
13
|
+
import java.util.HashMap
|
|
14
|
+
import java.util.UUID
|
|
15
|
+
import kotlin.jvm.JvmStatic
|
|
16
|
+
import kotlin.jvm.Synchronized
|
|
17
|
+
import kotlin.jvm.Volatile
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Bridge class for SDK communication between Expo modules and native Android code This is the
|
|
21
|
+
* Android equivalent of the iOS Bridge.swift
|
|
22
|
+
*/
|
|
23
|
+
public class Bridge private constructor() {
|
|
24
|
+
private var deviceManager: DeviceManager? = null
|
|
25
|
+
|
|
26
|
+
companion object {
|
|
27
|
+
private const val TAG = "Bridge"
|
|
28
|
+
private const val MIC_SAMPLE_RATE = 16_000
|
|
29
|
+
private const val PCM_BITS_PER_SAMPLE = 16
|
|
30
|
+
private const val MIC_CHANNELS = 1
|
|
31
|
+
private const val LC3_FRAME_DURATION_MS = 10
|
|
32
|
+
private const val DEFAULT_LC3_FRAME_SIZE_BYTES = 60
|
|
33
|
+
private val AUDIO_TRACE_METADATA_KEYS =
|
|
34
|
+
listOf(
|
|
35
|
+
"sampleRate",
|
|
36
|
+
"bitsPerSample",
|
|
37
|
+
"channels",
|
|
38
|
+
"encoding",
|
|
39
|
+
"frameDurationMs",
|
|
40
|
+
"frameSizeBytes",
|
|
41
|
+
"bitrate",
|
|
42
|
+
"packetizedFromGlasses",
|
|
43
|
+
"voiceActivityDetectionEnabled",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
@Volatile private var instance: Bridge? = null
|
|
47
|
+
|
|
48
|
+
private const val DEFAULT_EVENT_SINK_ID = "default"
|
|
49
|
+
|
|
50
|
+
// Event sinks for JS and native consumers.
|
|
51
|
+
private val eventSinks = linkedMapOf<String, (String, Map<String, Any>) -> Unit>()
|
|
52
|
+
|
|
53
|
+
// Android Context for native operations
|
|
54
|
+
private var appContext: android.content.Context? = null
|
|
55
|
+
|
|
56
|
+
@JvmStatic
|
|
57
|
+
@Synchronized
|
|
58
|
+
fun getInstance(): Bridge {
|
|
59
|
+
if (instance == null) {
|
|
60
|
+
instance = Bridge()
|
|
61
|
+
}
|
|
62
|
+
return instance!!
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Initialize the Bridge with event callback and context This should be called from
|
|
67
|
+
* BluetoothSdkModule
|
|
68
|
+
*/
|
|
69
|
+
@JvmStatic
|
|
70
|
+
fun initialize(
|
|
71
|
+
context: android.content.Context,
|
|
72
|
+
callback: (String, Map<String, Any>) -> Unit
|
|
73
|
+
) {
|
|
74
|
+
Log.d(TAG, "Initializing Bridge with context and event callback")
|
|
75
|
+
initialize(context)
|
|
76
|
+
setEventSink(DEFAULT_EVENT_SINK_ID, callback)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@JvmStatic
|
|
80
|
+
fun initialize(context: android.content.Context) {
|
|
81
|
+
appContext = context
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@JvmStatic
|
|
85
|
+
@Synchronized
|
|
86
|
+
fun addEventSink(callback: (String, Map<String, Any>) -> Unit): String {
|
|
87
|
+
val id = UUID.randomUUID().toString()
|
|
88
|
+
setEventSink(id, callback)
|
|
89
|
+
return id
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@JvmStatic
|
|
93
|
+
@Synchronized
|
|
94
|
+
fun removeEventSink(id: String) {
|
|
95
|
+
eventSinks.remove(id)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@Synchronized
|
|
99
|
+
private fun setEventSink(id: String, callback: (String, Map<String, Any>) -> Unit) {
|
|
100
|
+
eventSinks[id] = callback
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@Synchronized
|
|
104
|
+
private fun getEventSinks(): List<(String, Map<String, Any>) -> Unit> {
|
|
105
|
+
return eventSinks.values.toList()
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Get the Android context for native operations */
|
|
109
|
+
@JvmStatic
|
|
110
|
+
fun getContext(): android.content.Context {
|
|
111
|
+
return appContext ?: throw IllegalStateException("Bridge not initialized with context")
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Log a message and send it to JavaScript */
|
|
115
|
+
@JvmStatic
|
|
116
|
+
fun log(message: String) {
|
|
117
|
+
val data = HashMap<String, Any>()
|
|
118
|
+
data["message"] = message
|
|
119
|
+
sendTypedMessage("log", data as Map<String, Any>)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Report tar.bz2 extraction progress to JavaScript. */
|
|
123
|
+
@JvmStatic
|
|
124
|
+
fun sendExtractionProgress(percentage: Int, bytesRead: Long, totalBytes: Long) {
|
|
125
|
+
val data = HashMap<String, Any>()
|
|
126
|
+
data["percentage"] = percentage
|
|
127
|
+
data["bytesRead"] = bytesRead
|
|
128
|
+
data["totalBytes"] = totalBytes
|
|
129
|
+
sendTypedMessage("extraction_progress", data as Map<String, Any>)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// MARK: - Speaker identification
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* One identification window from SpeakerIdEngine. [speakerId]/[name]
|
|
136
|
+
* are omitted for an unknown (unenrolled) voice. Matches iOS.
|
|
137
|
+
*/
|
|
138
|
+
@JvmStatic
|
|
139
|
+
fun sendSpeakerDetected(speakerId: String?, name: String?, similarity: Double, startMs: Long, endMs: Long) {
|
|
140
|
+
val body = HashMap<String, Any>()
|
|
141
|
+
body["similarity"] = similarity
|
|
142
|
+
body["startMs"] = startMs
|
|
143
|
+
body["endMs"] = endMs
|
|
144
|
+
if (speakerId != null) body["speakerId"] = speakerId
|
|
145
|
+
if (name != null) body["name"] = name
|
|
146
|
+
sendTypedMessage("speaker_detected", body as Map<String, Any>)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@JvmStatic
|
|
150
|
+
fun sendSpeakerEnrollProgress(voicedSeconds: Double, targetSeconds: Double, level: Double) {
|
|
151
|
+
val body = HashMap<String, Any>()
|
|
152
|
+
body["voicedSeconds"] = voicedSeconds
|
|
153
|
+
body["targetSeconds"] = targetSeconds
|
|
154
|
+
body["level"] = level
|
|
155
|
+
sendTypedMessage("speaker_enroll_progress", body as Map<String, Any>)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Enrollment outcome. Embeddings are base64 Float32Arrays — raw audio
|
|
160
|
+
* is already discarded by the time this fires. Matches iOS.
|
|
161
|
+
*/
|
|
162
|
+
@JvmStatic
|
|
163
|
+
fun sendSpeakerEnrollResult(ok: Boolean, reason: String?, embeddings: List<String>, dim: Int, source: String) {
|
|
164
|
+
val body = HashMap<String, Any>()
|
|
165
|
+
body["ok"] = ok
|
|
166
|
+
body["source"] = source
|
|
167
|
+
if (reason != null) body["reason"] = reason
|
|
168
|
+
if (ok) {
|
|
169
|
+
body["embeddings"] = embeddings
|
|
170
|
+
body["dim"] = dim
|
|
171
|
+
}
|
|
172
|
+
sendTypedMessage("speaker_enroll_result", body as Map<String, Any>)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Send head position event */
|
|
176
|
+
@JvmStatic
|
|
177
|
+
fun sendHeadUp(isUp: Boolean) {
|
|
178
|
+
val data = HashMap<String, Any>()
|
|
179
|
+
data["up"] = isUp
|
|
180
|
+
sendTypedMessage("head_up", data as Map<String, Any>)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** Send pair failure event */
|
|
184
|
+
@JvmStatic
|
|
185
|
+
fun sendPairFailureEvent(error: String) {
|
|
186
|
+
val data = HashMap<String, Any>()
|
|
187
|
+
data["error"] = error
|
|
188
|
+
sendTypedMessage("pair_failure", data as Map<String, Any>)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
@JvmStatic
|
|
192
|
+
fun sendPairingInfo(
|
|
193
|
+
hadPreviousBond: Boolean,
|
|
194
|
+
pairingCode: String? = null,
|
|
195
|
+
classicBondReady: Boolean = false,
|
|
196
|
+
securePairingCapable: Boolean = true,
|
|
197
|
+
protocolVersion: Int = 1,
|
|
198
|
+
) {
|
|
199
|
+
val data = HashMap<String, Any>()
|
|
200
|
+
data["had_previous_bond"] = hadPreviousBond
|
|
201
|
+
if (pairingCode != null) data["pairing_code"] = pairingCode
|
|
202
|
+
data["classic_bond_ready"] = classicBondReady
|
|
203
|
+
data["secure_pairing_capable"] = securePairingCapable
|
|
204
|
+
data["protocol_version"] = protocolVersion
|
|
205
|
+
sendTypedMessage("pairing_info", data as Map<String, Any>)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Send audio connected event - matches iOS implementation for platform parity */
|
|
209
|
+
@JvmStatic
|
|
210
|
+
fun sendAudioConnected(deviceName: String) {
|
|
211
|
+
val data = HashMap<String, Any>()
|
|
212
|
+
data["deviceName"] = deviceName
|
|
213
|
+
sendTypedMessage("audio_connected", data as Map<String, Any>)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Send audio disconnected event - matches iOS implementation for platform parity */
|
|
217
|
+
@JvmStatic
|
|
218
|
+
fun sendAudioDisconnected() {
|
|
219
|
+
val data = HashMap<String, Any>()
|
|
220
|
+
sendTypedMessage("audio_disconnected", data as Map<String, Any>)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
@JvmStatic
|
|
224
|
+
fun sendMicPcm(data: ByteArray) {
|
|
225
|
+
val body = micPcmEventBody(data)
|
|
226
|
+
sendTypedMessage("mic_pcm", body as Map<String, Any>)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
@JvmStatic
|
|
230
|
+
fun sendMicLc3(data: ByteArray) {
|
|
231
|
+
val body = micLc3EventBody(data)
|
|
232
|
+
sendTypedMessage("mic_lc3", body as Map<String, Any>)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
@JvmStatic
|
|
236
|
+
internal fun sendMicHealth(health: MicHealth, reason: String) {
|
|
237
|
+
val body = HashMap(health.toMap())
|
|
238
|
+
body["reason"] = reason
|
|
239
|
+
body["timestamp"] = System.currentTimeMillis()
|
|
240
|
+
sendTypedMessage("mic_health", body)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private fun micPcmEventBody(data: ByteArray): HashMap<String, Any> {
|
|
244
|
+
val voiceActivityDetectionEnabled =
|
|
245
|
+
DeviceStore.get("glasses", "voiceActivityDetectionEnabled") as? Boolean
|
|
246
|
+
?: BluetoothSdkDefaults.VOICE_ACTIVITY_DETECTION_ENABLED
|
|
247
|
+
val body = HashMap<String, Any>()
|
|
248
|
+
body["pcm"] = data
|
|
249
|
+
body["sampleRate"] = MIC_SAMPLE_RATE
|
|
250
|
+
body["bitsPerSample"] = PCM_BITS_PER_SAMPLE
|
|
251
|
+
body["channels"] = MIC_CHANNELS
|
|
252
|
+
body["encoding"] = "pcm_s16le"
|
|
253
|
+
body["voiceActivityDetectionEnabled"] = voiceActivityDetectionEnabled
|
|
254
|
+
return body
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private fun micLc3EventBody(data: ByteArray): HashMap<String, Any> {
|
|
258
|
+
val voiceActivityDetectionEnabled =
|
|
259
|
+
DeviceStore.get("glasses", "voiceActivityDetectionEnabled") as? Boolean
|
|
260
|
+
?: BluetoothSdkDefaults.VOICE_ACTIVITY_DETECTION_ENABLED
|
|
261
|
+
val frameSizeBytes =
|
|
262
|
+
(DeviceStore.store.get("bluetooth", "lc3_frame_size") as? Number)?.toInt()
|
|
263
|
+
?: DEFAULT_LC3_FRAME_SIZE_BYTES
|
|
264
|
+
val body = HashMap<String, Any>()
|
|
265
|
+
body["lc3"] = data
|
|
266
|
+
body["sampleRate"] = MIC_SAMPLE_RATE
|
|
267
|
+
body["channels"] = MIC_CHANNELS
|
|
268
|
+
body["encoding"] = "lc3"
|
|
269
|
+
body["frameDurationMs"] = LC3_FRAME_DURATION_MS
|
|
270
|
+
body["frameSizeBytes"] = frameSizeBytes
|
|
271
|
+
body["bitrate"] = frameSizeBytes * 8 * (1000 / LC3_FRAME_DURATION_MS)
|
|
272
|
+
body["packetizedFromGlasses"] = false
|
|
273
|
+
body["voiceActivityDetectionEnabled"] = voiceActivityDetectionEnabled
|
|
274
|
+
return body
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** Save a setting */
|
|
278
|
+
@JvmStatic
|
|
279
|
+
fun saveSetting(key: String, value: Any) {
|
|
280
|
+
val body = HashMap<String, Any>()
|
|
281
|
+
body["key"] = key
|
|
282
|
+
body["value"] = value
|
|
283
|
+
sendTypedMessage("save_setting", body as Map<String, Any>)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** Send Voice Activity Detection status */
|
|
287
|
+
@JvmStatic
|
|
288
|
+
fun sendVoiceActivityDetectionStatus(enabled: Boolean) {
|
|
289
|
+
DeviceStore.set("glasses", "voiceActivityDetectionEnabled", enabled)
|
|
290
|
+
val body = HashMap<String, Any>()
|
|
291
|
+
body["voiceActivityDetectionEnabled"] = enabled
|
|
292
|
+
sendTypedMessage("voice_activity_detection_status", body as Map<String, Any>)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** Send live speaking status reported by glasses-side Voice Activity Detection. */
|
|
296
|
+
@JvmStatic
|
|
297
|
+
fun sendSpeakingStatus(speaking: Boolean) {
|
|
298
|
+
val body = HashMap<String, Any>()
|
|
299
|
+
body["speaking"] = speaking
|
|
300
|
+
body["timestamp"] = System.currentTimeMillis()
|
|
301
|
+
sendTypedMessage("speaking_status", body as Map<String, Any>)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Send battery status */
|
|
305
|
+
@JvmStatic
|
|
306
|
+
fun sendBatteryStatus(level: Int, charging: Boolean) {
|
|
307
|
+
val body = HashMap<String, Any>()
|
|
308
|
+
body["level"] = level
|
|
309
|
+
body["charging"] = charging
|
|
310
|
+
body["timestamp"] = System.currentTimeMillis()
|
|
311
|
+
sendTypedMessage("battery_status", body as Map<String, Any>)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** Send discovered device */
|
|
315
|
+
@JvmStatic
|
|
316
|
+
@JvmOverloads
|
|
317
|
+
fun sendDiscoveredDevice(
|
|
318
|
+
deviceModel: String,
|
|
319
|
+
deviceName: String,
|
|
320
|
+
deviceAddress: String = "",
|
|
321
|
+
rssi: Int? = null,
|
|
322
|
+
projectName: String? = null,
|
|
323
|
+
pairingMode: Boolean? = null,
|
|
324
|
+
pairingCode: String? = null,
|
|
325
|
+
securePairingCapable: Boolean? = null,
|
|
326
|
+
) {
|
|
327
|
+
val searchResults =
|
|
328
|
+
(DeviceStore.store.getCategory("bluetooth")["searchResults"] as? List<*>)
|
|
329
|
+
?.mapNotNull { result ->
|
|
330
|
+
(result as? Map<*, *>)?.entries
|
|
331
|
+
?.mapNotNull { (key, value) ->
|
|
332
|
+
if (key is String && value != null) key to value else null
|
|
333
|
+
}
|
|
334
|
+
?.toMap()
|
|
335
|
+
}
|
|
336
|
+
?: emptyList()
|
|
337
|
+
val id = listOfNotNull(deviceModel, projectName?.takeIf { it.isNotBlank() }, deviceName).joinToString(":")
|
|
338
|
+
val newResult =
|
|
339
|
+
buildMap<String, Any> {
|
|
340
|
+
put("id", id)
|
|
341
|
+
put("model", deviceModel)
|
|
342
|
+
put("name", deviceName)
|
|
343
|
+
if (deviceAddress.isNotBlank()) {
|
|
344
|
+
put("address", deviceAddress)
|
|
345
|
+
}
|
|
346
|
+
projectName?.takeIf { it.isNotBlank() }?.let { put("projectName", it) }
|
|
347
|
+
rssi?.let { put("rssi", it) }
|
|
348
|
+
pairingMode?.let { put("pairingMode", it) }
|
|
349
|
+
pairingCode?.takeIf { it.isNotBlank() }?.let { put("pairingCode", it) }
|
|
350
|
+
securePairingCapable?.let { put("securePairingCapable", it) }
|
|
351
|
+
}
|
|
352
|
+
// Keep the public searchResults array stable as glasses are added or removed.
|
|
353
|
+
// Duplicate discoveries refresh their existing row; only new glasses append.
|
|
354
|
+
val uniqueResults = mergeStableSearchResults(searchResults, newResult, deviceModel)
|
|
355
|
+
DeviceStore.set("bluetooth", "searchResults", uniqueResults)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
private fun mergeStableSearchResults(
|
|
359
|
+
currentResults: List<Map<String, Any>>,
|
|
360
|
+
newResult: Map<String, Any>,
|
|
361
|
+
fallbackModel: String
|
|
362
|
+
): List<Map<String, Any>> {
|
|
363
|
+
val newKey = searchResultKey(newResult, fallbackModel) ?: return currentResults
|
|
364
|
+
val nextResults = currentResults.toMutableList()
|
|
365
|
+
val existingIndex =
|
|
366
|
+
nextResults.indexOfFirst { result ->
|
|
367
|
+
searchResultKey(result, fallbackModel) == newKey
|
|
368
|
+
}
|
|
369
|
+
if (existingIndex >= 0) {
|
|
370
|
+
nextResults[existingIndex] = newResult
|
|
371
|
+
} else {
|
|
372
|
+
nextResults += newResult
|
|
373
|
+
}
|
|
374
|
+
return nextResults
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
private fun searchResultKey(result: Map<String, Any>, fallbackModel: String): String? {
|
|
378
|
+
val id = result["id"] as? String
|
|
379
|
+
if (!id.isNullOrBlank()) {
|
|
380
|
+
return id
|
|
381
|
+
}
|
|
382
|
+
val model = result["model"] as? String ?: fallbackModel
|
|
383
|
+
val name = result["name"] as? String ?: return null
|
|
384
|
+
return "$model:$name"
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// MARK: - Hardware Events
|
|
388
|
+
|
|
389
|
+
/** Send button press event to React Native - matches iOS implementation */
|
|
390
|
+
@JvmStatic
|
|
391
|
+
fun sendButtonPressEvent(buttonId: String, pressType: String) {
|
|
392
|
+
val buttonData = HashMap<String, Any>()
|
|
393
|
+
buttonData["buttonId"] = buttonId
|
|
394
|
+
buttonData["pressType"] = pressType
|
|
395
|
+
buttonData["timestamp"] = System.currentTimeMillis()
|
|
396
|
+
|
|
397
|
+
sendTypedMessage("button_press", buttonData as Map<String, Any>)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** Send miniapp selection event from glasses dashboard menu */
|
|
401
|
+
@JvmStatic
|
|
402
|
+
fun sendMiniappSelected(packageName: String) {
|
|
403
|
+
val body = HashMap<String, Any>()
|
|
404
|
+
body["packageName"] = packageName
|
|
405
|
+
sendTypedMessage("miniapp_selected", body)
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/** Send touch/gesture event from glasses - matches iOS implementation */
|
|
409
|
+
@JvmStatic
|
|
410
|
+
@JvmOverloads
|
|
411
|
+
fun sendTouchEvent(
|
|
412
|
+
deviceModel: String,
|
|
413
|
+
gestureName: String,
|
|
414
|
+
timestamp: Long,
|
|
415
|
+
source: Int? = null
|
|
416
|
+
) {
|
|
417
|
+
val body = HashMap<String, Any>()
|
|
418
|
+
body["type"] = "touch_event"
|
|
419
|
+
body["deviceModel"] = deviceModel
|
|
420
|
+
body["gestureName"] = gestureName
|
|
421
|
+
body["timestamp"] = timestamp
|
|
422
|
+
if (source != null) {
|
|
423
|
+
body["source"] = source
|
|
424
|
+
}
|
|
425
|
+
sendTypedMessage("touch_event", body)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/** Send swipe volume control status - matches iOS implementation */
|
|
429
|
+
@JvmStatic
|
|
430
|
+
fun sendSwipeVolumeStatus(enabled: Boolean, timestamp: Long) {
|
|
431
|
+
val body = HashMap<String, Any>()
|
|
432
|
+
body["enabled"] = enabled
|
|
433
|
+
body["timestamp"] = timestamp
|
|
434
|
+
sendTypedMessage("swipe_volume_status", body)
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/** Send switch status from glasses - matches iOS implementation */
|
|
438
|
+
@JvmStatic
|
|
439
|
+
fun sendSwitchStatus(switchType: Int, value: Int, timestamp: Long) {
|
|
440
|
+
val body = HashMap<String, Any>()
|
|
441
|
+
body["switchType"] = switchType
|
|
442
|
+
body["switchValue"] = value
|
|
443
|
+
body["timestamp"] = timestamp
|
|
444
|
+
sendTypedMessage("switch_status", body)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
@JvmStatic
|
|
448
|
+
fun sendPhotoError(requestId: String, errorCode: String, errorMessage: String) {
|
|
449
|
+
val timestamp = System.currentTimeMillis()
|
|
450
|
+
val event = HashMap<String, Any>()
|
|
451
|
+
event["type"] = "photo_response"
|
|
452
|
+
event["state"] = "error"
|
|
453
|
+
event["requestId"] = requestId
|
|
454
|
+
event["errorCode"] = errorCode
|
|
455
|
+
event["errorMessage"] = errorMessage
|
|
456
|
+
event["timestamp"] = timestamp
|
|
457
|
+
sendTypedMessage("photo_response", event as Map<String, Any>)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
@JvmStatic
|
|
461
|
+
fun sendPhotoStatus(statusJson: Map<String, Any>) {
|
|
462
|
+
sendTypedMessage("photo_status", statusJson)
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
@JvmStatic
|
|
466
|
+
fun sendCameraStatus(statusJson: Map<String, Any>) {
|
|
467
|
+
sendTypedMessage("camera_status", statusJson)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
@JvmStatic
|
|
471
|
+
fun sendPhotoResponse(responseJson: Map<String, Any>) {
|
|
472
|
+
sendTypedMessage("photo_response", responseJson)
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/** Send RGB LED control response */
|
|
476
|
+
@JvmStatic
|
|
477
|
+
fun sendRgbLedControlResponse(requestId: String, success: Boolean, error: String?) {
|
|
478
|
+
if (requestId.isEmpty()) return
|
|
479
|
+
try {
|
|
480
|
+
val body = HashMap<String, Any>()
|
|
481
|
+
body["type"] = "rgb_led_control_response"
|
|
482
|
+
body["requestId"] = requestId
|
|
483
|
+
body["state"] = if (success) "success" else "error"
|
|
484
|
+
if (!success) {
|
|
485
|
+
body["errorCode"] = error ?: "unknown_error"
|
|
486
|
+
}
|
|
487
|
+
sendTypedMessage("rgb_led_control_response", body)
|
|
488
|
+
} catch (e: Exception) {
|
|
489
|
+
log("Bridge: Error sending rgb_led_control_response: $e")
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
@JvmStatic
|
|
494
|
+
fun sendSettingsAck(values: Map<String, Any>) {
|
|
495
|
+
val body = HashMap<String, Any>()
|
|
496
|
+
body["type"] = "settings_ack"
|
|
497
|
+
values.forEach { (key, value) ->
|
|
498
|
+
body[key] = value
|
|
499
|
+
}
|
|
500
|
+
sendTypedMessage("settings_ack", body)
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
@JvmStatic
|
|
504
|
+
fun sendVideoRecordingStatus(values: Map<String, Any>) {
|
|
505
|
+
val body = HashMap<String, Any>()
|
|
506
|
+
body["type"] = "video_recording_status"
|
|
507
|
+
values.forEach { (key, value) ->
|
|
508
|
+
body[key] = value
|
|
509
|
+
}
|
|
510
|
+
sendTypedMessage("video_recording_status", body)
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
@JvmStatic
|
|
514
|
+
fun sendMediaUploadEvent(type: String, values: Map<String, Any>) {
|
|
515
|
+
val body = HashMap<String, Any>()
|
|
516
|
+
body["type"] = type
|
|
517
|
+
values.forEach { (key, value) ->
|
|
518
|
+
body[key] = value
|
|
519
|
+
}
|
|
520
|
+
sendTypedMessage(type, body)
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
@JvmStatic
|
|
524
|
+
fun sendVersionInfo(values: Map<String, Any>) {
|
|
525
|
+
fun stringField(vararg keys: String): String =
|
|
526
|
+
keys.firstNotNullOfOrNull { key -> values[key] as? String } ?: ""
|
|
527
|
+
val body = HashMap<String, Any>()
|
|
528
|
+
body["type"] = "version_info"
|
|
529
|
+
body["androidVersion"] = stringField("androidVersion", "android_version")
|
|
530
|
+
body["firmwareVersion"] = stringField("firmwareVersion", "firmware_version")
|
|
531
|
+
body["besFirmwareVersion"] = stringField("besFirmwareVersion", "bes_fw_version")
|
|
532
|
+
body["mtkFirmwareVersion"] = stringField("mtkFirmwareVersion", "mtk_fw_version")
|
|
533
|
+
body["buildNumber"] = stringField("buildNumber", "build_number")
|
|
534
|
+
(values["systemTimeMs"] as? Number ?: values["system_time_ms"] as? Number)?.let {
|
|
535
|
+
body["systemTimeMs"] = it.toLong()
|
|
536
|
+
}
|
|
537
|
+
body["otaVersionUrl"] = stringField("otaVersionUrl", "ota_version_url")
|
|
538
|
+
body["appVersion"] = stringField("appVersion", "app_version")
|
|
539
|
+
(values["hotspotOtaVersion"] as? Number
|
|
540
|
+
?: values["hotspot_ota_version"] as? Number)
|
|
541
|
+
?.let { body["hotspotOtaVersion"] = it.toInt() }
|
|
542
|
+
sendTypedMessage("version_info", body)
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Send transcription result to server Used by AOSManager to send pre-formatted
|
|
547
|
+
* transcription results Matches the Swift structure exactly
|
|
548
|
+
*/
|
|
549
|
+
@JvmStatic
|
|
550
|
+
fun sendLocalTranscription(transcription: Map<String, Any>) {
|
|
551
|
+
val text = transcription["text"] as? String
|
|
552
|
+
if (text == null || text.isEmpty()) {
|
|
553
|
+
log("Skipping empty transcription result")
|
|
554
|
+
return
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
sendTypedMessage("local_transcription", transcription)
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/** Convenience method for sending local transcription from transcriber */
|
|
561
|
+
@JvmStatic
|
|
562
|
+
fun sendLocalTranscription(text: String, isFinal: Boolean, language: String) {
|
|
563
|
+
if (text.isEmpty()) {
|
|
564
|
+
log("Skipping empty transcription result")
|
|
565
|
+
return
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
val transcription =
|
|
569
|
+
mapOf(
|
|
570
|
+
"text" to text,
|
|
571
|
+
"isFinal" to isFinal,
|
|
572
|
+
"language" to language,
|
|
573
|
+
"type" to "local_transcription"
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
sendTypedMessage("local_transcription", transcription)
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// Bluetooth SDK bridge funcs:
|
|
580
|
+
|
|
581
|
+
/** Send status update */
|
|
582
|
+
@JvmStatic
|
|
583
|
+
fun sendStatus(statusObj: Map<String, Any>) {
|
|
584
|
+
val body = HashMap<String, Any>()
|
|
585
|
+
body["bluetooth_status"] = statusObj
|
|
586
|
+
sendTypedMessage("bluetooth_status_update", body as Map<String, Any>)
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/** Send glasses serial number */
|
|
590
|
+
@JvmStatic
|
|
591
|
+
fun sendserialNumber(serialNumber: String, style: String, color: String) {
|
|
592
|
+
val serialData = HashMap<String, Any>()
|
|
593
|
+
serialData["serial_number"] = serialNumber
|
|
594
|
+
serialData["style"] = style
|
|
595
|
+
serialData["color"] = color
|
|
596
|
+
|
|
597
|
+
val body = HashMap<String, Any>()
|
|
598
|
+
body["glasses_serial_number"] = serialData
|
|
599
|
+
sendTypedMessage("glasses_serial_number", body as Map<String, Any>)
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Send WiFi status change. [error] is the glasses' provisioning failure reason
|
|
604
|
+
* (e.g. "connect_timeout", "connected_to_other_network") when this status is the
|
|
605
|
+
* verdict of a failed connect attempt; null for routine link-state updates.
|
|
606
|
+
*/
|
|
607
|
+
@JvmStatic
|
|
608
|
+
@JvmOverloads
|
|
609
|
+
fun sendWifiStatusChange(
|
|
610
|
+
connected: Boolean,
|
|
611
|
+
ssid: String?,
|
|
612
|
+
localIp: String?,
|
|
613
|
+
error: String? = null
|
|
614
|
+
) {
|
|
615
|
+
val status = WifiStatus.fromStoreFields(connected, ssid, localIp) ?: return
|
|
616
|
+
val payload =
|
|
617
|
+
if (error != null) status.toMap() + mapOf("error" to error)
|
|
618
|
+
else status.toMap()
|
|
619
|
+
sendTypedMessage("wifi_status_change", payload)
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Claim the WiFi scan-results store for a newly requested scan. Called by the
|
|
624
|
+
* SDK when it generates the scanId, BEFORE the scan command goes out: store
|
|
625
|
+
* ownership is decided at request time, not by whichever chunk arrives first,
|
|
626
|
+
* so a delayed chunk from an older, abandoned scan can never reset or clobber
|
|
627
|
+
* the current scan's accumulator.
|
|
628
|
+
*/
|
|
629
|
+
@JvmStatic
|
|
630
|
+
fun claimWifiScanResults(scanId: String) {
|
|
631
|
+
DeviceStore.apply("bluetooth", "wifiScanActiveScanId", scanId)
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/** Send WiFi scan results */
|
|
635
|
+
@JvmStatic
|
|
636
|
+
fun updateWifiScanResults(
|
|
637
|
+
networks: List<Map<String, Any>>,
|
|
638
|
+
scanComplete: Boolean,
|
|
639
|
+
scanId: String? = null
|
|
640
|
+
) {
|
|
641
|
+
// Only chunks echoing the active scanId claimed at request time may mutate
|
|
642
|
+
// the store; foreign chunks are still forwarded to the SDK sink, which
|
|
643
|
+
// drops stale ids itself. Scan-id-less chunks (old firmware) keep the
|
|
644
|
+
// legacy accumulate-forever store behavior.
|
|
645
|
+
val ownsStore =
|
|
646
|
+
scanId == null || scanId == DeviceStore.get("bluetooth", "wifiScanActiveScanId")
|
|
647
|
+
var updatedNetworks: List<Map<String, Any>> = networks
|
|
648
|
+
if (ownsStore) {
|
|
649
|
+
var storedNetworks: List<Map<String, Any>> =
|
|
650
|
+
DeviceStore.get("bluetooth", "wifiScanResults") as? List<Map<String, Any>>
|
|
651
|
+
?: emptyList()
|
|
652
|
+
val lastScanId = DeviceStore.get("bluetooth", "wifiScanResultsScanId")
|
|
653
|
+
if (scanId != null && scanId != lastScanId) {
|
|
654
|
+
// First chunk of a new scan: drop networks accumulated for a previous scan
|
|
655
|
+
// so stale entries never carry over into this scan's store.
|
|
656
|
+
storedNetworks = emptyList()
|
|
657
|
+
DeviceStore.apply("bluetooth", "wifiScanResultsScanId", scanId)
|
|
658
|
+
}
|
|
659
|
+
// add the networks to the storedNetworks array, removing duplicates by ssid
|
|
660
|
+
val merged = storedNetworks.toMutableList()
|
|
661
|
+
for (network in networks) {
|
|
662
|
+
if (!merged.any { it["ssid"] as? String == network["ssid"] as? String }) {
|
|
663
|
+
merged.add(network)
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
DeviceStore.apply("bluetooth", "wifiScanResults", merged)
|
|
667
|
+
updatedNetworks = merged
|
|
668
|
+
}
|
|
669
|
+
val body = HashMap<String, Any>()
|
|
670
|
+
// Correlated scans: the SDK accumulates and dedupes chunks per scanId itself,
|
|
671
|
+
// so forward only this chunk; the merged store list is for UI consumers.
|
|
672
|
+
body["networks"] = if (scanId != null) networks else updatedNetworks
|
|
673
|
+
body["scanComplete"] = scanComplete
|
|
674
|
+
if (scanId != null) {
|
|
675
|
+
body["scanId"] = scanId
|
|
676
|
+
}
|
|
677
|
+
sendTypedMessage("wifi_scan_result", body)
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/** Send gallery status - matches iOS MentraLive.swift handleGalleryStatus pattern */
|
|
681
|
+
@JvmStatic
|
|
682
|
+
fun sendGalleryStatus(
|
|
683
|
+
photoCount: Int,
|
|
684
|
+
videoCount: Int,
|
|
685
|
+
totalCount: Int,
|
|
686
|
+
totalSize: Long,
|
|
687
|
+
hasContent: Boolean,
|
|
688
|
+
cameraBusy: Boolean,
|
|
689
|
+
cameraBusyReason: String?
|
|
690
|
+
) {
|
|
691
|
+
val galleryData = HashMap<String, Any>()
|
|
692
|
+
galleryData["type"] = "gallery_status"
|
|
693
|
+
galleryData["photos"] = photoCount
|
|
694
|
+
galleryData["videos"] = videoCount
|
|
695
|
+
galleryData["total"] = totalCount
|
|
696
|
+
galleryData["totalSize"] = totalSize
|
|
697
|
+
galleryData["hasContent"] = hasContent
|
|
698
|
+
galleryData["cameraBusy"] = cameraBusy
|
|
699
|
+
if (!cameraBusyReason.isNullOrBlank()) {
|
|
700
|
+
galleryData["cameraBusyReason"] = cameraBusyReason
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
sendTypedMessage("gallery_status", galleryData as Map<String, Any>)
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/** Send hotspot status change - matches iOS MentraLive.swift emitHotspotStatusChange */
|
|
707
|
+
@JvmStatic
|
|
708
|
+
fun sendHotspotStatusChange(
|
|
709
|
+
enabled: Boolean,
|
|
710
|
+
ssid: String,
|
|
711
|
+
password: String,
|
|
712
|
+
gatewayIp: String
|
|
713
|
+
) {
|
|
714
|
+
val status = HotspotStatus.fromStoreFields(enabled, ssid, password, gatewayIp) ?: return
|
|
715
|
+
sendTypedMessage("hotspot_status_change", status.toMap())
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/** Send hotspot error - notifies React Native of hotspot failures */
|
|
719
|
+
@JvmStatic
|
|
720
|
+
fun sendHotspotError(errorMessage: String, timestamp: Long) {
|
|
721
|
+
val eventBody = HashMap<String, Any>()
|
|
722
|
+
eventBody["errorMessage"] = errorMessage
|
|
723
|
+
eventBody["timestamp"] = timestamp
|
|
724
|
+
|
|
725
|
+
sendTypedMessage("hotspot_error", eventBody as Map<String, Any>)
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/** Send MTK firmware update complete notification - matches iOS implementation */
|
|
729
|
+
@JvmStatic
|
|
730
|
+
fun sendMtkUpdateComplete(message: String) {
|
|
731
|
+
val eventBody = HashMap<String, Any>()
|
|
732
|
+
eventBody["message"] = message
|
|
733
|
+
eventBody["timestamp"] = System.currentTimeMillis()
|
|
734
|
+
sendTypedMessage("mtk_update_complete", eventBody as Map<String, Any>)
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/** Send ota_start_ack — glasses confirmed receipt of ota_start command */
|
|
738
|
+
@JvmStatic
|
|
739
|
+
fun sendOtaStartAck() {
|
|
740
|
+
val eventBody = HashMap<String, Any>()
|
|
741
|
+
eventBody["timestamp"] = System.currentTimeMillis()
|
|
742
|
+
sendTypedMessage("ota_start_ack", eventBody as Map<String, Any>)
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
@JvmStatic
|
|
746
|
+
@JvmOverloads
|
|
747
|
+
fun sendOtaStatus(
|
|
748
|
+
sessionId: String,
|
|
749
|
+
totalSteps: Int,
|
|
750
|
+
currentStep: Int,
|
|
751
|
+
stepType: String,
|
|
752
|
+
phase: String,
|
|
753
|
+
stepPercent: Int,
|
|
754
|
+
overallPercent: Int,
|
|
755
|
+
status: String,
|
|
756
|
+
errorMessage: String? = null,
|
|
757
|
+
glassesTimeMs: Long? = null,
|
|
758
|
+
) {
|
|
759
|
+
val eventBody = HashMap<String, Any>()
|
|
760
|
+
eventBody["session_id"] = sessionId
|
|
761
|
+
eventBody["total_steps"] = totalSteps
|
|
762
|
+
eventBody["current_step"] = currentStep
|
|
763
|
+
eventBody["step_type"] = stepType
|
|
764
|
+
eventBody["phase"] = phase
|
|
765
|
+
eventBody["step_percent"] = stepPercent
|
|
766
|
+
eventBody["overall_percent"] = overallPercent
|
|
767
|
+
eventBody["status"] = status
|
|
768
|
+
errorMessage?.let { eventBody["error_message"] = it }
|
|
769
|
+
if (glassesTimeMs != null && glassesTimeMs > 0) {
|
|
770
|
+
eventBody["glasses_time_ms"] = glassesTimeMs
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
Log.d(TAG, "Bridge: sendOtaStatus: $eventBody")
|
|
774
|
+
|
|
775
|
+
sendTypedMessage("ota_status", eventBody as Map<String, Any>)
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/** Send stream status - forwards to websocket system (matches iOS) */
|
|
779
|
+
@JvmStatic
|
|
780
|
+
fun sendStreamStatus(statusJson: Map<String, Any>) {
|
|
781
|
+
sendTypedMessage("stream_status", statusJson)
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/** Send keep alive ACK - forwards to websocket system (matches iOS) */
|
|
785
|
+
@JvmStatic
|
|
786
|
+
fun sendKeepAliveAck(ackJson: Map<String, Any>) {
|
|
787
|
+
sendTypedMessage("keep_alive_ack", ackJson)
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
/** Send IMU data event - matches iOS MentraLive.swift emitImuDataEvent */
|
|
791
|
+
@JvmStatic
|
|
792
|
+
fun sendImuDataEvent(
|
|
793
|
+
accel: DoubleArray,
|
|
794
|
+
gyro: DoubleArray,
|
|
795
|
+
mag: DoubleArray,
|
|
796
|
+
quat: DoubleArray,
|
|
797
|
+
euler: DoubleArray,
|
|
798
|
+
timestamp: Long
|
|
799
|
+
) {
|
|
800
|
+
val eventBody = HashMap<String, Any>()
|
|
801
|
+
eventBody["accel"] = accel.toList()
|
|
802
|
+
eventBody["gyro"] = gyro.toList()
|
|
803
|
+
eventBody["mag"] = mag.toList()
|
|
804
|
+
eventBody["quat"] = quat.toList()
|
|
805
|
+
eventBody["euler"] = euler.toList()
|
|
806
|
+
eventBody["timestamp"] = timestamp
|
|
807
|
+
|
|
808
|
+
sendTypedMessage("imu_data_event", eventBody as Map<String, Any>)
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/** Send IMU gesture event - matches iOS MentraLive.swift emitImuGestureEvent */
|
|
812
|
+
@JvmStatic
|
|
813
|
+
fun sendImuGestureEvent(gesture: String, timestamp: Long) {
|
|
814
|
+
val eventBody = HashMap<String, Any>()
|
|
815
|
+
eventBody["gesture"] = gesture
|
|
816
|
+
eventBody["timestamp"] = timestamp
|
|
817
|
+
|
|
818
|
+
sendTypedMessage("imu_gesture_event", eventBody as Map<String, Any>)
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Send a single accelerometer reading from the glasses IMU - matches iOS
|
|
823
|
+
* Bridge.sendAccelEvent. A richer combined IMU event (gyro + magnetometer) is future work.
|
|
824
|
+
*/
|
|
825
|
+
@JvmStatic
|
|
826
|
+
fun sendAccelEvent(x: Float, y: Float, z: Float, timestamp: Long) {
|
|
827
|
+
val body = HashMap<String, Any>()
|
|
828
|
+
body["x"] = x
|
|
829
|
+
body["y"] = y
|
|
830
|
+
body["z"] = z
|
|
831
|
+
body["timestamp"] = timestamp
|
|
832
|
+
sendTypedMessage("accel_event", body as Map<String, Any>)
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// Arbitrary WS Comms (don't use these, make a dedicated function for your use case):
|
|
836
|
+
|
|
837
|
+
/** Send WebSocket text message */
|
|
838
|
+
@JvmStatic
|
|
839
|
+
fun sendWSText(msg: String) {
|
|
840
|
+
val data = HashMap<String, Any>()
|
|
841
|
+
data["text"] = msg
|
|
842
|
+
sendTypedMessage("ws_text", data as Map<String, Any>)
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/** Send WebSocket binary message */
|
|
846
|
+
@JvmStatic
|
|
847
|
+
fun sendWSBinary(data: ByteArray) {
|
|
848
|
+
val base64String = Base64.encodeToString(data, Base64.NO_WRAP)
|
|
849
|
+
val body = HashMap<String, Any>()
|
|
850
|
+
body["base64"] = base64String
|
|
851
|
+
sendTypedMessage("ws_bin", body as Map<String, Any>)
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
/**
|
|
855
|
+
* Send a typed message to JavaScript Don't call this function directly, instead make a
|
|
856
|
+
* function above that calls this function
|
|
857
|
+
*/
|
|
858
|
+
@JvmStatic
|
|
859
|
+
fun sendTypedMessage(type: String, body: Map<String, Any>) {
|
|
860
|
+
var mutableBody = body
|
|
861
|
+
if (body !is HashMap) {
|
|
862
|
+
mutableBody = HashMap(body)
|
|
863
|
+
}
|
|
864
|
+
(mutableBody as HashMap<String, Any>)["type"] = type
|
|
865
|
+
|
|
866
|
+
try {
|
|
867
|
+
val sinks = getEventSinks()
|
|
868
|
+
if (sinks.isEmpty()) {
|
|
869
|
+
Log.w(
|
|
870
|
+
TAG,
|
|
871
|
+
"Cannot send typed message '$type': no event sinks registered (app may be killed/backgrounded)"
|
|
872
|
+
)
|
|
873
|
+
return
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
val tracePayload = tracePayloadForTypedMessage(type, mutableBody as Map<String, Any>)
|
|
877
|
+
if (tracePayload != null) {
|
|
878
|
+
try {
|
|
879
|
+
BleTraceLogger.logMap(
|
|
880
|
+
"phone_to_app",
|
|
881
|
+
"sdk_event_dispatch",
|
|
882
|
+
type,
|
|
883
|
+
tracePayload,
|
|
884
|
+
)
|
|
885
|
+
} catch (e: Exception) {
|
|
886
|
+
Log.d(TAG, "BLE trace logging failed for typed message '$type'", e)
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// Send directly using type as event name - no JSON serialization
|
|
891
|
+
sinks.forEach { sink ->
|
|
892
|
+
try {
|
|
893
|
+
sink(type, mutableBody as Map<String, Any>)
|
|
894
|
+
} catch (e: Exception) {
|
|
895
|
+
Log.e(
|
|
896
|
+
TAG,
|
|
897
|
+
"Error invoking event sink for type '$type' (listener may be dead)",
|
|
898
|
+
e
|
|
899
|
+
)
|
|
900
|
+
// Don't rethrow - one dead listener should not break other consumers.
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
} catch (e: Exception) {
|
|
904
|
+
Log.e(TAG, "Error sending typed message of type '$type'", e)
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
private fun tracePayloadForTypedMessage(
|
|
909
|
+
type: String,
|
|
910
|
+
body: Map<String, Any>
|
|
911
|
+
): Map<String, Any>? =
|
|
912
|
+
when {
|
|
913
|
+
type == "log" -> null
|
|
914
|
+
isAudioPayloadEvent(type) -> audioTracePayload(type, body)
|
|
915
|
+
else -> body
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
private fun isAudioPayloadEvent(type: String): Boolean =
|
|
919
|
+
type == "mic_pcm" || type == "mic_lc3"
|
|
920
|
+
|
|
921
|
+
private fun audioTracePayload(type: String, body: Map<String, Any>): Map<String, Any> {
|
|
922
|
+
val payload = HashMap<String, Any>()
|
|
923
|
+
payload["type"] = type
|
|
924
|
+
payload["timestamp"] = System.currentTimeMillis()
|
|
925
|
+
payload["payloadOmitted"] = true
|
|
926
|
+
payload["payloadOmittedReason"] = "audio"
|
|
927
|
+
|
|
928
|
+
val audioBytes =
|
|
929
|
+
when (type) {
|
|
930
|
+
"mic_pcm" -> (body["pcm"] as? ByteArray)?.size
|
|
931
|
+
"mic_lc3" -> (body["lc3"] as? ByteArray)?.size
|
|
932
|
+
else -> null
|
|
933
|
+
}
|
|
934
|
+
audioBytes?.let { payload["audioBytes"] = it }
|
|
935
|
+
|
|
936
|
+
AUDIO_TRACE_METADATA_KEYS.forEach { key ->
|
|
937
|
+
val value = body[key]
|
|
938
|
+
if (value != null) {
|
|
939
|
+
payload[key] = value
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
return payload
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
init {
|
|
948
|
+
deviceManager = DeviceManager.Companion.getInstance()
|
|
949
|
+
if (deviceManager == null) {
|
|
950
|
+
Log.e(TAG, "Failed to initialize DeviceManager in Bridge constructor")
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|