@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,229 @@
|
|
|
1
|
+
package com.glassly.bluetoothsdk.stt
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.util.Log
|
|
5
|
+
import com.konovalov.vad.silero.Vad
|
|
6
|
+
import com.konovalov.vad.silero.VadSilero
|
|
7
|
+
import com.konovalov.vad.silero.config.FrameSize
|
|
8
|
+
import com.konovalov.vad.silero.config.Mode
|
|
9
|
+
import com.konovalov.vad.silero.config.SampleRate
|
|
10
|
+
import java.nio.ByteBuffer
|
|
11
|
+
import java.nio.ByteOrder
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* VadGateSpeechPolicy handles Voice Activity Detection using Silero VAD.
|
|
15
|
+
*
|
|
16
|
+
* Features:
|
|
17
|
+
* - Dynamic VAD check throttling (adjusts frequency based on silence duration)
|
|
18
|
+
* - 8-second silence timeout before declaring "not speaking"
|
|
19
|
+
* - Bypass modes for debugging and PCM streaming
|
|
20
|
+
* - 512-sample frame size (matches Sherpa-ONNX requirements)
|
|
21
|
+
*
|
|
22
|
+
* Ported from android_core VadGateSpeechPolicy.java
|
|
23
|
+
*/
|
|
24
|
+
class VadGateSpeechPolicy(private val context: Context) {
|
|
25
|
+
companion object {
|
|
26
|
+
private const val TAG = "VadGateSpeechPolicy"
|
|
27
|
+
|
|
28
|
+
// Total required silence duration
|
|
29
|
+
private const val REQUIRED_SILENCE_DURATION_MS = 8000L
|
|
30
|
+
|
|
31
|
+
// Dynamic VAD check intervals
|
|
32
|
+
private const val INITIAL_SILENCE_VAD_INTERVAL_MS = 50L // Check frequently at first
|
|
33
|
+
private const val MEDIUM_SILENCE_VAD_INTERVAL_MS = 100L // Medium frequency after some time
|
|
34
|
+
private const val LONG_SILENCE_VAD_INTERVAL_MS =
|
|
35
|
+
200L // Less frequent after extended silence
|
|
36
|
+
|
|
37
|
+
// Thresholds for switching intervals
|
|
38
|
+
private const val MEDIUM_SILENCE_THRESHOLD_MS =
|
|
39
|
+
20000L // Switch to medium interval after 20s
|
|
40
|
+
private const val LONG_SILENCE_THRESHOLD_MS = 60000L // Switch to long interval after 60s
|
|
41
|
+
|
|
42
|
+
private const val FRAME_SIZE = 512
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private var vad: VadSilero? = null
|
|
46
|
+
private var isCurrentlySpeech = false
|
|
47
|
+
private var bypassVadForDebugging = false
|
|
48
|
+
private var bypassVadForPCM = false
|
|
49
|
+
|
|
50
|
+
/** Notified whenever the speech/silence state actually flips. */
|
|
51
|
+
var onSpeechStateChanged: ((Boolean) -> Unit)? = null
|
|
52
|
+
|
|
53
|
+
// Timestamp of the last detected speech
|
|
54
|
+
private var lastSpeechDetectedTime = 0L
|
|
55
|
+
// Throttle timer for silence VAD checks
|
|
56
|
+
private var lastVadCheckTime = 0L
|
|
57
|
+
|
|
58
|
+
/** Initialize the Silero VAD model */
|
|
59
|
+
fun init(blockSizeSamples: Int) {
|
|
60
|
+
startVad()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private fun startVad() {
|
|
64
|
+
try {
|
|
65
|
+
// Set internal silence duration very low; external logic manages the full required
|
|
66
|
+
// silence duration
|
|
67
|
+
vad =
|
|
68
|
+
Vad.builder()
|
|
69
|
+
.setContext(context)
|
|
70
|
+
.setSampleRate(SampleRate.SAMPLE_RATE_16K)
|
|
71
|
+
.setFrameSize(FrameSize.FRAME_SIZE_512)
|
|
72
|
+
.setMode(Mode.NORMAL)
|
|
73
|
+
.setSilenceDurationMs(50)
|
|
74
|
+
.setSpeechDurationMs(50)
|
|
75
|
+
.build()
|
|
76
|
+
|
|
77
|
+
Log.d(TAG, "VAD initialized successfully")
|
|
78
|
+
} catch (e: Exception) {
|
|
79
|
+
Log.e(TAG, "Failed to initialize VAD", e)
|
|
80
|
+
vad = null
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Check if audio should be passed to the recognizer based on VAD state */
|
|
85
|
+
fun shouldPassAudioToRecognizer(): Boolean {
|
|
86
|
+
// CRITICAL: Handle VAD null case
|
|
87
|
+
if (vad == null) {
|
|
88
|
+
return bypassVadForDebugging || bypassVadForPCM || true
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return bypassVadForDebugging || bypassVadForPCM || isCurrentlySpeech
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Process audio bytes through VAD to detect speech */
|
|
95
|
+
fun processAudioBytes(bytes: ByteArray, offset: Int, length: Int) {
|
|
96
|
+
val now = System.currentTimeMillis()
|
|
97
|
+
|
|
98
|
+
// If in speech state and it hasn't been 8 seconds since the last speech was detected, skip
|
|
99
|
+
// processing
|
|
100
|
+
if (isCurrentlySpeech && (now - lastSpeechDetectedTime < REQUIRED_SILENCE_DURATION_MS)) {
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Calculate silence duration
|
|
105
|
+
val silenceDuration = now - lastSpeechDetectedTime
|
|
106
|
+
|
|
107
|
+
// Determine which VAD interval to use based on silence duration
|
|
108
|
+
val currentVadInterval =
|
|
109
|
+
when {
|
|
110
|
+
silenceDuration < MEDIUM_SILENCE_THRESHOLD_MS -> INITIAL_SILENCE_VAD_INTERVAL_MS
|
|
111
|
+
silenceDuration < LONG_SILENCE_THRESHOLD_MS -> MEDIUM_SILENCE_VAD_INTERVAL_MS
|
|
112
|
+
else -> LONG_SILENCE_VAD_INTERVAL_MS
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// During silence, throttle VAD checks based on the dynamic interval
|
|
116
|
+
if (!isCurrentlySpeech && (now - lastVadCheckTime < currentVadInterval)) {
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
lastVadCheckTime = now
|
|
120
|
+
|
|
121
|
+
val audioBytesFull = bytesToShort(bytes)
|
|
122
|
+
val totalSamples = audioBytesFull.size
|
|
123
|
+
|
|
124
|
+
if (totalSamples % FRAME_SIZE != 0) {
|
|
125
|
+
Log.e(
|
|
126
|
+
TAG,
|
|
127
|
+
"Invalid audio frame size: $totalSamples samples. Needs to be multiple of $FRAME_SIZE."
|
|
128
|
+
)
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
val currentVad =
|
|
133
|
+
vad
|
|
134
|
+
?: run {
|
|
135
|
+
Log.w(TAG, "VAD not initialized, skipping audio processing")
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
var previousSpeechState = isCurrentlySpeech
|
|
140
|
+
|
|
141
|
+
// Process each 512-sample frame
|
|
142
|
+
val numFrames = totalSamples / FRAME_SIZE
|
|
143
|
+
for (i in 0 until numFrames) {
|
|
144
|
+
val currentTime = System.currentTimeMillis()
|
|
145
|
+
val startIdx = i * FRAME_SIZE
|
|
146
|
+
val audioFrame = audioBytesFull.copyOfRange(startIdx, startIdx + FRAME_SIZE)
|
|
147
|
+
val detectedSpeech = currentVad.isSpeech(audioFrame)
|
|
148
|
+
|
|
149
|
+
if (detectedSpeech) {
|
|
150
|
+
isCurrentlySpeech = true
|
|
151
|
+
// Update the last speech detection timestamp
|
|
152
|
+
lastSpeechDetectedTime = currentTime
|
|
153
|
+
} else {
|
|
154
|
+
// If no speech detected, and 8 seconds have elapsed since the last speech, mark as
|
|
155
|
+
// silence
|
|
156
|
+
if (currentTime - lastSpeechDetectedTime >= REQUIRED_SILENCE_DURATION_MS) {
|
|
157
|
+
isCurrentlySpeech = false
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (isCurrentlySpeech != previousSpeechState) {
|
|
162
|
+
Log.d(
|
|
163
|
+
TAG,
|
|
164
|
+
"Speech detection changed to: ${if (isCurrentlySpeech) "SPEECH" else "SILENCE"}"
|
|
165
|
+
)
|
|
166
|
+
previousSpeechState = isCurrentlySpeech
|
|
167
|
+
onSpeechStateChanged?.invoke(isCurrentlySpeech)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Convert byte array (PCM16LE) to short array */
|
|
173
|
+
private fun bytesToShort(bytes: ByteArray): ShortArray {
|
|
174
|
+
val shorts = ShortArray(bytes.size / 2)
|
|
175
|
+
ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts)
|
|
176
|
+
return shorts
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Stop VAD and release resources */
|
|
180
|
+
fun stop() {
|
|
181
|
+
try {
|
|
182
|
+
vad?.close()
|
|
183
|
+
vad = null
|
|
184
|
+
Log.d(TAG, "VAD stopped and resources released")
|
|
185
|
+
} catch (e: Exception) {
|
|
186
|
+
Log.e(TAG, "Error stopping VAD", e)
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Reset VAD state */
|
|
191
|
+
fun reset() {
|
|
192
|
+
val wasSpeaking = isCurrentlySpeech
|
|
193
|
+
isCurrentlySpeech = false
|
|
194
|
+
lastSpeechDetectedTime = 0
|
|
195
|
+
lastVadCheckTime = 0
|
|
196
|
+
if (wasSpeaking) onSpeechStateChanged?.invoke(false)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Change bypass VAD for debugging state */
|
|
200
|
+
fun changeBypassVadForDebugging(bypass: Boolean) {
|
|
201
|
+
bypassVadForDebugging = bypass
|
|
202
|
+
Log.d(TAG, "Bypass VAD for debugging: $bypass")
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Change bypass VAD for PCM streaming state */
|
|
206
|
+
fun changeBypassVadForPCM(bypass: Boolean) {
|
|
207
|
+
Log.d(TAG, "VAD PCM Bypass State Change: $bypassVadForPCM -> $bypass")
|
|
208
|
+
bypassVadForPCM = bypass
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Handle microphone state changes */
|
|
212
|
+
fun microphoneStateChanged(state: Boolean) {
|
|
213
|
+
if (!state) {
|
|
214
|
+
// Microphone turned off: force immediate silence
|
|
215
|
+
val wasSpeaking = isCurrentlySpeech
|
|
216
|
+
isCurrentlySpeech = false
|
|
217
|
+
lastSpeechDetectedTime = 0
|
|
218
|
+
lastVadCheckTime = 0
|
|
219
|
+
|
|
220
|
+
// Optionally flush the VAD's internal state by processing a silent frame
|
|
221
|
+
vad?.let { vadInstance ->
|
|
222
|
+
val silentFrame = ShortArray(FRAME_SIZE)
|
|
223
|
+
vadInstance.isSpeech(silentFrame)
|
|
224
|
+
}
|
|
225
|
+
Log.d(TAG, "Microphone turned off; forced state to SILENCE.")
|
|
226
|
+
if (wasSpeaking) onSpeechStateChanged?.invoke(false)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
package com.glassly.core.tts
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.SharedPreferences
|
|
5
|
+
import com.k2fsa.sherpa.onnx.GenerationConfig
|
|
6
|
+
import com.k2fsa.sherpa.onnx.OfflineTts
|
|
7
|
+
import com.k2fsa.sherpa.onnx.OfflineTtsConfig
|
|
8
|
+
import com.k2fsa.sherpa.onnx.OfflineTtsModelConfig
|
|
9
|
+
import com.k2fsa.sherpa.onnx.OfflineTtsSupertonicModelConfig
|
|
10
|
+
import com.glassly.bluetoothsdk.Bridge
|
|
11
|
+
import java.io.File
|
|
12
|
+
import java.util.concurrent.Executors
|
|
13
|
+
import java.util.concurrent.ScheduledFuture
|
|
14
|
+
import java.util.concurrent.TimeUnit
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Utilities for offline Sherpa-ONNX Supertonic 3 TTS model management.
|
|
18
|
+
*
|
|
19
|
+
* Supertonic 3 is a single multilingual model bundle (31 languages) with 10
|
|
20
|
+
* preset voice styles packed into a single voice.bin. Speaker IDs are indexed
|
|
21
|
+
* alphabetically by JSON filename, so the order is F1, F2, F3, F4, F5, M1, M2,
|
|
22
|
+
* M3, M4, M5 (sids 0..9). We default to F1 (sid 0) for a female voice.
|
|
23
|
+
*/
|
|
24
|
+
object TTSTools {
|
|
25
|
+
private const val PREFS_NAME = "GlasslyPrefs"
|
|
26
|
+
private const val KEY_TTS_MODEL_PATH = "TTSModelPath"
|
|
27
|
+
private const val KEY_TTS_MODEL_LANGUAGE = "TTSModelLanguageCode"
|
|
28
|
+
|
|
29
|
+
private const val FILE_DURATION_PREDICTOR = "duration_predictor.int8.onnx"
|
|
30
|
+
private const val FILE_TEXT_ENCODER = "text_encoder.int8.onnx"
|
|
31
|
+
private const val FILE_VECTOR_ESTIMATOR = "vector_estimator.int8.onnx"
|
|
32
|
+
private const val FILE_VOCODER = "vocoder.int8.onnx"
|
|
33
|
+
private const val FILE_TTS_JSON = "tts.json"
|
|
34
|
+
private const val FILE_UNICODE_INDEXER = "unicode_indexer.bin"
|
|
35
|
+
private const val FILE_VOICE_STYLE = "voice.bin"
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Keep the native model warm briefly after use to reduce repeated TTS latency while
|
|
39
|
+
* still reclaiming its memory when speech has been idle for a while.
|
|
40
|
+
*/
|
|
41
|
+
private const val MODEL_IDLE_TIMEOUT_MINUTES = 3L
|
|
42
|
+
private val modelLock = Any()
|
|
43
|
+
private val teardownExecutor =
|
|
44
|
+
Executors.newSingleThreadScheduledExecutor { runnable ->
|
|
45
|
+
Thread(runnable, "GlasslyTtsIdleTeardown").apply { isDaemon = true }
|
|
46
|
+
}
|
|
47
|
+
private var cachedTts: OfflineTts? = null
|
|
48
|
+
private var cachedModelPath: String? = null
|
|
49
|
+
private var teardownFuture: ScheduledFuture<*>? = null
|
|
50
|
+
private var teardownGeneration = 0L
|
|
51
|
+
|
|
52
|
+
private val REQUIRED_FILES = listOf(
|
|
53
|
+
FILE_DURATION_PREDICTOR,
|
|
54
|
+
FILE_TEXT_ENCODER,
|
|
55
|
+
FILE_VECTOR_ESTIMATOR,
|
|
56
|
+
FILE_VOCODER,
|
|
57
|
+
FILE_TTS_JSON,
|
|
58
|
+
FILE_UNICODE_INDEXER,
|
|
59
|
+
FILE_VOICE_STYLE,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
fun setTtsModelDetails(context: Context, path: String, languageCode: String) {
|
|
63
|
+
synchronized(modelLock) {
|
|
64
|
+
if (cachedModelPath != null && cachedModelPath != path) {
|
|
65
|
+
releaseCachedModelLocked("model path changed")
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
val prefs = getPrefs(context)
|
|
69
|
+
prefs.edit().apply {
|
|
70
|
+
putString(KEY_TTS_MODEL_PATH, path)
|
|
71
|
+
putString(KEY_TTS_MODEL_LANGUAGE, languageCode)
|
|
72
|
+
apply()
|
|
73
|
+
}
|
|
74
|
+
Bridge.log("TTS model details saved: path=$path, language=$languageCode")
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
fun getTtsModelPath(context: Context): String {
|
|
78
|
+
val prefs = getPrefs(context)
|
|
79
|
+
return prefs.getString(KEY_TTS_MODEL_PATH, "") ?: ""
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fun getTtsModelLanguage(context: Context): String {
|
|
83
|
+
val prefs = getPrefs(context)
|
|
84
|
+
return prefs.getString(KEY_TTS_MODEL_LANGUAGE, "en-US") ?: "en-US"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fun checkTTSModelAvailable(context: Context): Boolean {
|
|
88
|
+
val modelPath = getTtsModelPath(context)
|
|
89
|
+
if (modelPath.isEmpty()) {
|
|
90
|
+
return false
|
|
91
|
+
}
|
|
92
|
+
return validateTTSModel(modelPath)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fun validateTTSModel(path: String): Boolean {
|
|
96
|
+
val modelDir = File(path)
|
|
97
|
+
if (!modelDir.exists() || !modelDir.isDirectory) {
|
|
98
|
+
Bridge.log("TTS model path does not exist or is not a directory: $path")
|
|
99
|
+
return false
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
for (name in REQUIRED_FILES) {
|
|
103
|
+
val file = File(modelDir, name)
|
|
104
|
+
if (!file.exists() || !file.canRead() || file.length() == 0L) {
|
|
105
|
+
Bridge.log("TTS model missing required file '$name' at: $path")
|
|
106
|
+
return false
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return true
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private val SUPPORTED_LANGS = setOf(
|
|
114
|
+
"en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et",
|
|
115
|
+
"fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl",
|
|
116
|
+
"pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
/** Convert a BCP-47 tag like "en-US" or "fr-FR" to a Supertonic 2-letter code. */
|
|
120
|
+
private fun languageTagToSupertonicLang(tag: String?): String {
|
|
121
|
+
if (tag.isNullOrBlank()) return "en"
|
|
122
|
+
val primary = tag.substringBefore('-').lowercase()
|
|
123
|
+
return if (primary in SUPPORTED_LANGS) primary else "en"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
fun generateTtsAudio(
|
|
127
|
+
context: Context,
|
|
128
|
+
text: String,
|
|
129
|
+
modelPath: String,
|
|
130
|
+
outputPath: String,
|
|
131
|
+
speakerId: Int,
|
|
132
|
+
speed: Float,
|
|
133
|
+
): Boolean {
|
|
134
|
+
val languageTag = getTtsModelLanguage(context)
|
|
135
|
+
if (text.isBlank()) {
|
|
136
|
+
Bridge.log("TTS_ERROR: text is empty")
|
|
137
|
+
return false
|
|
138
|
+
}
|
|
139
|
+
if (!validateTTSModel(modelPath)) {
|
|
140
|
+
Bridge.log("TTS_ERROR: model is invalid: $modelPath")
|
|
141
|
+
return false
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
val outputFile = File(outputPath)
|
|
145
|
+
outputFile.parentFile?.mkdirs()
|
|
146
|
+
|
|
147
|
+
return synchronized(modelLock) {
|
|
148
|
+
try {
|
|
149
|
+
val tts = getOrCreateModelLocked(modelPath)
|
|
150
|
+
|
|
151
|
+
// sid out of range falls back to F1 (sid 0); clamp 0..9.
|
|
152
|
+
val sid = speakerId.coerceIn(0, tts.numSpeakers() - 1)
|
|
153
|
+
val clampedSpeed = speed.coerceIn(0.5f, 2.0f)
|
|
154
|
+
val lang = languageTagToSupertonicLang(languageTag)
|
|
155
|
+
val genConfig = GenerationConfig(
|
|
156
|
+
sid = sid,
|
|
157
|
+
speed = clampedSpeed,
|
|
158
|
+
numSteps = 5,
|
|
159
|
+
extra = mapOf("lang" to lang),
|
|
160
|
+
)
|
|
161
|
+
val audio = tts.generateWithConfig(text = text, config = genConfig)
|
|
162
|
+
val saved = audio.save(outputFile.absolutePath)
|
|
163
|
+
Bridge.log("TTS generated ${outputFile.absolutePath}: saved=$saved sid=$sid lang=$lang")
|
|
164
|
+
saved
|
|
165
|
+
} catch (e: Exception) {
|
|
166
|
+
Bridge.log("TTS_ERROR: ${e.javaClass.simpleName}: ${e.message}")
|
|
167
|
+
e.printStackTrace()
|
|
168
|
+
false
|
|
169
|
+
} finally {
|
|
170
|
+
scheduleIdleTeardownLocked()
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private fun getOrCreateModelLocked(modelPath: String): OfflineTts {
|
|
176
|
+
cachedTts?.let { cached ->
|
|
177
|
+
if (cachedModelPath == modelPath) {
|
|
178
|
+
Bridge.log("TTS reusing cached model")
|
|
179
|
+
return cached
|
|
180
|
+
}
|
|
181
|
+
releaseCachedModelLocked("model path changed")
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
val modelDir = File(modelPath)
|
|
185
|
+
val supertonic = OfflineTtsSupertonicModelConfig(
|
|
186
|
+
durationPredictor = File(modelDir, FILE_DURATION_PREDICTOR).absolutePath,
|
|
187
|
+
textEncoder = File(modelDir, FILE_TEXT_ENCODER).absolutePath,
|
|
188
|
+
vectorEstimator = File(modelDir, FILE_VECTOR_ESTIMATOR).absolutePath,
|
|
189
|
+
vocoder = File(modelDir, FILE_VOCODER).absolutePath,
|
|
190
|
+
ttsJson = File(modelDir, FILE_TTS_JSON).absolutePath,
|
|
191
|
+
unicodeIndexer = File(modelDir, FILE_UNICODE_INDEXER).absolutePath,
|
|
192
|
+
voiceStyle = File(modelDir, FILE_VOICE_STYLE).absolutePath,
|
|
193
|
+
)
|
|
194
|
+
val modelConfig = OfflineTtsModelConfig(
|
|
195
|
+
supertonic = supertonic,
|
|
196
|
+
numThreads = 8,
|
|
197
|
+
provider = "cpu",
|
|
198
|
+
)
|
|
199
|
+
val config = OfflineTtsConfig(
|
|
200
|
+
model = modelConfig,
|
|
201
|
+
maxNumSentences = 1,
|
|
202
|
+
silenceScale = 0.2f,
|
|
203
|
+
)
|
|
204
|
+
return OfflineTts(null, config).also {
|
|
205
|
+
cachedTts = it
|
|
206
|
+
cachedModelPath = modelPath
|
|
207
|
+
Bridge.log("TTS loaded model; keeping it warm for $MODEL_IDLE_TIMEOUT_MINUTES minutes after use")
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private fun scheduleIdleTeardownLocked() {
|
|
212
|
+
if (cachedTts == null) return
|
|
213
|
+
teardownFuture?.cancel(false)
|
|
214
|
+
val generation = ++teardownGeneration
|
|
215
|
+
teardownFuture =
|
|
216
|
+
teardownExecutor.schedule(
|
|
217
|
+
{
|
|
218
|
+
synchronized(modelLock) {
|
|
219
|
+
if (generation == teardownGeneration) {
|
|
220
|
+
releaseCachedModelLocked("idle for $MODEL_IDLE_TIMEOUT_MINUTES minutes")
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
MODEL_IDLE_TIMEOUT_MINUTES,
|
|
225
|
+
TimeUnit.MINUTES,
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private fun releaseCachedModelLocked(reason: String) {
|
|
230
|
+
teardownFuture?.cancel(false)
|
|
231
|
+
teardownFuture = null
|
|
232
|
+
teardownGeneration++
|
|
233
|
+
val tts = cachedTts
|
|
234
|
+
cachedTts = null
|
|
235
|
+
cachedModelPath = null
|
|
236
|
+
if (tts == null) return
|
|
237
|
+
try {
|
|
238
|
+
tts.release()
|
|
239
|
+
Bridge.log("TTS released cached model: $reason")
|
|
240
|
+
} catch (e: Exception) {
|
|
241
|
+
Bridge.log("TTS release failed: ${e.message}")
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private fun getPrefs(context: Context): SharedPreferences {
|
|
246
|
+
return context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
package com.glassly.bluetoothsdk
|
|
2
|
+
|
|
3
|
+
import com.glassly.bluetoothsdk.utils.ControllerTypes
|
|
4
|
+
import com.glassly.bluetoothsdk.utils.DeviceTypes
|
|
5
|
+
|
|
6
|
+
data class BluetoothSdkConfig @JvmOverloads constructor(
|
|
7
|
+
val deliverCallbacksOnMainThread: Boolean = true,
|
|
8
|
+
val analytics: BluetoothSdkAnalyticsConfig = BluetoothSdkAnalyticsConfig(),
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
class BluetoothSdkException(
|
|
12
|
+
val code: String,
|
|
13
|
+
message: String,
|
|
14
|
+
cause: Throwable? = null,
|
|
15
|
+
) : IllegalStateException(message, cause)
|
|
16
|
+
|
|
17
|
+
enum class DeviceModel(val deviceType: String) {
|
|
18
|
+
G1(DeviceTypes.G1),
|
|
19
|
+
G2(DeviceTypes.G2),
|
|
20
|
+
MENTRA_LIVE(DeviceTypes.LIVE),
|
|
21
|
+
MENTRA_NEX(DeviceTypes.NEX),
|
|
22
|
+
MACH1(DeviceTypes.MACH1),
|
|
23
|
+
Z100(DeviceTypes.Z100),
|
|
24
|
+
FRAME(DeviceTypes.FRAME),
|
|
25
|
+
NIMO(DeviceTypes.NIMO),
|
|
26
|
+
AR99(DeviceTypes.AR99),
|
|
27
|
+
SIMULATED(DeviceTypes.SIMULATED),
|
|
28
|
+
R1(ControllerTypes.R1);
|
|
29
|
+
|
|
30
|
+
companion object {
|
|
31
|
+
@JvmStatic
|
|
32
|
+
fun fromDeviceType(deviceType: String?): DeviceModel =
|
|
33
|
+
values().firstOrNull { it.deviceType == deviceType } ?: MENTRA_LIVE
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
data class Device(
|
|
38
|
+
val model: DeviceModel,
|
|
39
|
+
val name: String,
|
|
40
|
+
/** Android Bluetooth address when available. */
|
|
41
|
+
val address: String? = null,
|
|
42
|
+
val projectName: String? = null,
|
|
43
|
+
val rssi: Int? = null,
|
|
44
|
+
/** Stable app-facing scan-result key. Do not parse; use typed fields instead. */
|
|
45
|
+
val id: String = address?.takeIf { it.isNotBlank() } ?: "${model.deviceType}:$name",
|
|
46
|
+
val pairingMode: Boolean? = null,
|
|
47
|
+
val pairingCode: String? = null,
|
|
48
|
+
val securePairingCapable: Boolean? = null,
|
|
49
|
+
) {
|
|
50
|
+
internal fun toMap(): Map<String, Any> =
|
|
51
|
+
buildMap {
|
|
52
|
+
put("id", id)
|
|
53
|
+
put("model", model.deviceType)
|
|
54
|
+
put("name", name)
|
|
55
|
+
address?.takeIf { it.isNotBlank() }?.let {
|
|
56
|
+
put("address", it)
|
|
57
|
+
}
|
|
58
|
+
projectName?.takeIf { it.isNotBlank() }?.let {
|
|
59
|
+
put("projectName", it)
|
|
60
|
+
}
|
|
61
|
+
rssi?.let { put("rssi", it) }
|
|
62
|
+
pairingMode?.let { put("pairingMode", it) }
|
|
63
|
+
pairingCode?.takeIf { it.isNotBlank() }?.let { put("pairingCode", it) }
|
|
64
|
+
securePairingCapable?.let { put("securePairingCapable", it) }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
companion object {
|
|
68
|
+
internal fun fromMap(values: Map<String, Any>): Device? {
|
|
69
|
+
val model = stringValue(values, "model") ?: return null
|
|
70
|
+
val name = stringValue(values, "name") ?: return null
|
|
71
|
+
val address = stringValue(values, "address")?.takeIf { it.isNotBlank() }
|
|
72
|
+
val projectName = stringValue(values, "projectName")?.takeIf { it.isNotBlank() }
|
|
73
|
+
val rssi = numberValue(values, "rssi")
|
|
74
|
+
val id = stringValue(values, "id")?.takeIf { it.isNotBlank() } ?: address ?: "${model}:$name"
|
|
75
|
+
val pairingMode = boolValue(values, "pairingMode")
|
|
76
|
+
val pairingCode = stringValue(values, "pairingCode")?.takeIf { it.isNotBlank() }
|
|
77
|
+
val securePairingCapable = boolValue(values, "securePairingCapable")
|
|
78
|
+
return Device(
|
|
79
|
+
model = DeviceModel.fromDeviceType(model),
|
|
80
|
+
name = name,
|
|
81
|
+
address = address,
|
|
82
|
+
projectName = projectName,
|
|
83
|
+
rssi = rssi,
|
|
84
|
+
id = id,
|
|
85
|
+
pairingMode = pairingMode,
|
|
86
|
+
pairingCode = pairingCode,
|
|
87
|
+
securePairingCapable = securePairingCapable,
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
data class ConnectOptions(
|
|
94
|
+
val saveAsDefault: Boolean = true,
|
|
95
|
+
val cancelExistingConnectionAttempt: Boolean = true,
|
|
96
|
+
)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
package com.glassly.bluetoothsdk.utils;
|
|
2
|
+
|
|
3
|
+
import android.util.Base64;
|
|
4
|
+
|
|
5
|
+
import java.io.UnsupportedEncodingException;
|
|
6
|
+
import java.security.MessageDigest;
|
|
7
|
+
import java.security.NoSuchAlgorithmException;
|
|
8
|
+
import java.util.Arrays;
|
|
9
|
+
|
|
10
|
+
import javax.crypto.Cipher;
|
|
11
|
+
import javax.crypto.spec.SecretKeySpec;
|
|
12
|
+
|
|
13
|
+
import android.util.Log;
|
|
14
|
+
|
|
15
|
+
public class AES {
|
|
16
|
+
private static final String TAG = "WearableIntelligenceSystem_AES";
|
|
17
|
+
|
|
18
|
+
private static SecretKeySpec secretKey;
|
|
19
|
+
private static byte[] key;
|
|
20
|
+
|
|
21
|
+
public static void setKey(String myKey)
|
|
22
|
+
{
|
|
23
|
+
MessageDigest sha = null;
|
|
24
|
+
try {
|
|
25
|
+
key = myKey.getBytes("UTF-8");
|
|
26
|
+
sha = MessageDigest.getInstance("SHA-1");
|
|
27
|
+
key = sha.digest(key);
|
|
28
|
+
key = Arrays.copyOf(key, 16);
|
|
29
|
+
secretKey = new SecretKeySpec(key, "AES");
|
|
30
|
+
}
|
|
31
|
+
catch (NoSuchAlgorithmException e) {
|
|
32
|
+
e.printStackTrace();
|
|
33
|
+
}
|
|
34
|
+
catch (UnsupportedEncodingException e) {
|
|
35
|
+
e.printStackTrace();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public static String encrypt(String strToEncrypt, String secret)
|
|
40
|
+
{
|
|
41
|
+
try
|
|
42
|
+
{
|
|
43
|
+
setKey(secret);
|
|
44
|
+
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
|
|
45
|
+
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
|
46
|
+
return Base64.encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")), Base64.DEFAULT);
|
|
47
|
+
}
|
|
48
|
+
catch (Exception e)
|
|
49
|
+
{
|
|
50
|
+
Log.d(TAG, "Error while encrypting: " + e.toString());
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//bytes version
|
|
56
|
+
public static byte [] encrypt(byte [ ] bytesToEncrypt, String secret)
|
|
57
|
+
{
|
|
58
|
+
try
|
|
59
|
+
{
|
|
60
|
+
setKey(secret);
|
|
61
|
+
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
|
|
62
|
+
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
|
63
|
+
return cipher.doFinal(bytesToEncrypt);
|
|
64
|
+
}
|
|
65
|
+
catch (Exception e)
|
|
66
|
+
{
|
|
67
|
+
Log.d(TAG, "Error while encrypting: " + e.toString());
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
//String version
|
|
73
|
+
public static String decrypt(String strToDecrypt, String secret)
|
|
74
|
+
{
|
|
75
|
+
try
|
|
76
|
+
{
|
|
77
|
+
Log.d(TAG, "Secret key is: " + secret);
|
|
78
|
+
setKey(secret);
|
|
79
|
+
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7PADDING");
|
|
80
|
+
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
|
81
|
+
return new String(cipher.doFinal(Base64.decode(strToDecrypt, Base64.DEFAULT)));
|
|
82
|
+
}
|
|
83
|
+
catch (Exception e)
|
|
84
|
+
{
|
|
85
|
+
Log.d(TAG, "Error while decrypting: " + e.toString());
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
//bytes version
|
|
91
|
+
public static byte [] decrypt(byte [] bytesToDecrypt, String secret)
|
|
92
|
+
{
|
|
93
|
+
try
|
|
94
|
+
{
|
|
95
|
+
setKey(secret);
|
|
96
|
+
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7PADDING");
|
|
97
|
+
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
|
98
|
+
return cipher.doFinal(bytesToDecrypt);
|
|
99
|
+
}
|
|
100
|
+
catch (Exception e)
|
|
101
|
+
{
|
|
102
|
+
Log.d(TAG, "Error while decrypting: " + e.toString());
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|