@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,241 @@
|
|
|
1
|
+
//
|
|
2
|
+
// JSCExperiment.swift
|
|
3
|
+
// Glassly
|
|
4
|
+
//
|
|
5
|
+
// Test/benchmark infrastructure. Self-contained file, never invoked in
|
|
6
|
+
// normal user flow. Triggered only when (a) GLASSLY_RUN_JSC_BENCH env
|
|
7
|
+
// var is set at app launch, or (b) the user taps a JSC button on the
|
|
8
|
+
// (Super-Mode-gated) stress-test screen.
|
|
9
|
+
//
|
|
10
|
+
// Spike: measure the actual memory cost of N concurrent JSContexts on iOS.
|
|
11
|
+
// We want to know whether "Pebble-style native JSC per miniapp" is viable
|
|
12
|
+
// for our N-concurrent-miniapp use case (Pebble runs only 1 at a time, so
|
|
13
|
+
// they have no data on this).
|
|
14
|
+
//
|
|
15
|
+
// Each spawned context:
|
|
16
|
+
// - Has its own JSVirtualMachine (full isolation, separate heap)
|
|
17
|
+
// - Has __dispatch as a single bridge function (no per-method bindings,
|
|
18
|
+
// to avoid the production crash Pebble documented in CrashReproducer.kt)
|
|
19
|
+
// - Runs a representative idle workload: setInterval ping every 5 s
|
|
20
|
+
// - Names itself "GlasslyJS: <id>" for Safari Web Inspector
|
|
21
|
+
// - Is NOT inspectable in release builds
|
|
22
|
+
//
|
|
23
|
+
// Measure resident memory before and after spawning N contexts.
|
|
24
|
+
|
|
25
|
+
import Foundation
|
|
26
|
+
import JavaScriptCore
|
|
27
|
+
import os.log
|
|
28
|
+
|
|
29
|
+
private let jscLog = OSLog(subsystem: "com.tetramo.glassly", category: "JSCSpike")
|
|
30
|
+
|
|
31
|
+
/// Log to BOTH jlog (forwarded into JS) AND os_log AND a flat file in
|
|
32
|
+
/// the app's Documents directory. Release builds don't pipe RN's
|
|
33
|
+
/// console.log or Swift print() to syslog, and os_log filtering through
|
|
34
|
+
/// idevicesyslog is unreliable. The Documents file is the agentic-test
|
|
35
|
+
/// path: `xcrun devicectl device copy from --domain-type appDataContainer
|
|
36
|
+
/// --domain-identifier com.tetramo.glassly --source Documents/jsc-spike.log`.
|
|
37
|
+
private let logFileURL: URL = {
|
|
38
|
+
let docs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
|
39
|
+
return docs.appendingPathComponent("jsc-spike.log")
|
|
40
|
+
}()
|
|
41
|
+
|
|
42
|
+
private func jlog(_ message: String) {
|
|
43
|
+
Bridge.log(message)
|
|
44
|
+
os_log("%{public}@", log: jscLog, type: .info, message)
|
|
45
|
+
let stamped = "[\(ISO8601DateFormatter().string(from: Date()))] \(message)\n"
|
|
46
|
+
if let data = stamped.data(using: .utf8) {
|
|
47
|
+
if FileManager.default.fileExists(atPath: logFileURL.path) {
|
|
48
|
+
if let handle = try? FileHandle(forWritingTo: logFileURL) {
|
|
49
|
+
defer { try? handle.close() }
|
|
50
|
+
try? handle.seekToEnd()
|
|
51
|
+
try? handle.write(contentsOf: data)
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
try? data.write(to: logFileURL, options: .atomic)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@objc class JSCExperiment: NSObject {
|
|
60
|
+
/// Called from BluetoothSdkModule init. If GLASSLY_RUN_JSC_BENCH env var
|
|
61
|
+
/// is set, kick off the benchmark after a 5s settle window so the app
|
|
62
|
+
/// is fully booted (RN bridge up, Metro pull done if dev, etc).
|
|
63
|
+
@objc static func maybeAutoBenchmark() {
|
|
64
|
+
guard ProcessInfo.processInfo.environment["GLASSLY_RUN_JSC_BENCH"] != nil else { return }
|
|
65
|
+
os_log("🧪 GLASSLY_RUN_JSC_BENCH set — auto-running benchmark in 5s",
|
|
66
|
+
log: jscLog, type: .info)
|
|
67
|
+
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 5.0) {
|
|
68
|
+
runBenchmark()
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/// id → (context, virtualMachine, timer for the workload)
|
|
73
|
+
private static var contexts: [String: (JSContext, JSVirtualMachine, Timer)] = [:]
|
|
74
|
+
private static let queue = DispatchQueue(label: "com.glassly.jsc-experiment")
|
|
75
|
+
|
|
76
|
+
/// Spawn N JSContexts at once. Each gets its own VM + a representative
|
|
77
|
+
/// idle workload. Returns the count successfully spawned.
|
|
78
|
+
@objc static func spawn(count: Int) -> Int {
|
|
79
|
+
let beforeMB = MemoryMonitor.currentMemoryMB()
|
|
80
|
+
jlog("🧪 JSCExperiment.spawn(\(count)) starting; baseline \(String(format: "%.1f", beforeMB)) MB")
|
|
81
|
+
var spawned = 0
|
|
82
|
+
for i in 0 ..< count {
|
|
83
|
+
let id = "spike-\(UUID().uuidString.prefix(8))-\(i)"
|
|
84
|
+
if spawnOne(id: id) {
|
|
85
|
+
spawned += 1
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
let afterMB = MemoryMonitor.currentMemoryMB()
|
|
89
|
+
let perMB = spawned > 0 ? (afterMB - beforeMB) / Double(spawned) : 0
|
|
90
|
+
jlog("🧪 JSCExperiment: spawned \(spawned)/\(count) contexts; total alive \(contexts.count); mem \(String(format: "%.1f", beforeMB))→\(String(format: "%.1f", afterMB)) MB (\(String(format: "%+.2f", perMB)) MB/ctx)")
|
|
91
|
+
return spawned
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/// Spawn one named context. Returns true on success.
|
|
95
|
+
@objc static func spawnOne(id: String) -> Bool {
|
|
96
|
+
return queue.sync {
|
|
97
|
+
// Each context gets its own VM = full heap isolation between miniapps.
|
|
98
|
+
// (JSContexts that share a VM share the heap; we want isolation.)
|
|
99
|
+
let vm = JSVirtualMachine()!
|
|
100
|
+
let ctx = JSContext(virtualMachine: vm)!
|
|
101
|
+
|
|
102
|
+
ctx.name = "GlasslyJS: \(id)"
|
|
103
|
+
// Inspectable in dev builds only. iOS 16.4+ guarded.
|
|
104
|
+
#if DEBUG
|
|
105
|
+
if #available(iOS 16.4, *) {
|
|
106
|
+
ctx.isInspectable = true
|
|
107
|
+
}
|
|
108
|
+
#endif
|
|
109
|
+
|
|
110
|
+
// Single-dispatcher bridge. Per Pebble's CrashReproducer doc, never
|
|
111
|
+
// bind individual native callbacks as JSValue properties — JSC's GC
|
|
112
|
+
// races with ARC and crashes. One C-callable function only.
|
|
113
|
+
let dispatch: @convention(block) (String, String, [Any]?) -> Any? = { _, _, _ in
|
|
114
|
+
// Stub: real impl routes to native services.
|
|
115
|
+
// For the spike we just need __dispatch to exist so the
|
|
116
|
+
// workload can call it without throwing.
|
|
117
|
+
NSNull()
|
|
118
|
+
}
|
|
119
|
+
ctx.setObject(dispatch, forKeyedSubscript: "__dispatch" as NSString)
|
|
120
|
+
|
|
121
|
+
// Representative idle workload — what a typical miniapp's
|
|
122
|
+
// background JS does: hold a tiny bit of state, register a
|
|
123
|
+
// listener, periodically poke the bridge.
|
|
124
|
+
let workload = """
|
|
125
|
+
(function () {
|
|
126
|
+
var counter = 0;
|
|
127
|
+
var state = { id: \"\(id)\", startedAt: Date.now(), notes: [] };
|
|
128
|
+
var i = 0;
|
|
129
|
+
function tick() {
|
|
130
|
+
counter++;
|
|
131
|
+
state.notes.push({ at: Date.now(), n: counter });
|
|
132
|
+
if (state.notes.length > 100) state.notes.shift();
|
|
133
|
+
__dispatch('noop', 'tick', [counter]);
|
|
134
|
+
}
|
|
135
|
+
tick();
|
|
136
|
+
// Schedule a periodic tick. We use the host-provided
|
|
137
|
+
// setInterval (a JS shim that calls into native).
|
|
138
|
+
if (typeof setInterval === 'function') {
|
|
139
|
+
setInterval(tick, 5000);
|
|
140
|
+
}
|
|
141
|
+
})();
|
|
142
|
+
"""
|
|
143
|
+
ctx.evaluateScript(workload)
|
|
144
|
+
|
|
145
|
+
// Workload uses setInterval which is a JS shim that we'd build
|
|
146
|
+
// for real — for the spike we just install a Timer-based
|
|
147
|
+
// setInterval that fires the JS callback. The JS code already
|
|
148
|
+
// expects setInterval to exist as a global.
|
|
149
|
+
let setInterval: @convention(block) (JSValue, Double) -> Int = { fn, ms in
|
|
150
|
+
let id = Int.random(in: 1 ... Int.max)
|
|
151
|
+
// Stub: we won't actually fire in the spike, but the JS
|
|
152
|
+
// callback existing is what we want for memory measurement.
|
|
153
|
+
_ = fn // hold a ref to keep the JS callback alive
|
|
154
|
+
_ = ms
|
|
155
|
+
return id
|
|
156
|
+
}
|
|
157
|
+
ctx.setObject(setInterval, forKeyedSubscript: "setInterval" as NSString)
|
|
158
|
+
|
|
159
|
+
// Idle workload Timer on the native side that does NOTHING —
|
|
160
|
+
// it just exists so the context isn't optimized away. The real
|
|
161
|
+
// JS callback (registered above) will be hit by a real
|
|
162
|
+
// setInterval impl in production.
|
|
163
|
+
let timer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { _ in
|
|
164
|
+
// no-op — keep ref alive
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
contexts[id] = (ctx, vm, timer)
|
|
168
|
+
return true
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/// Tear down all contexts. Important: cancel timers, drop refs, force GC.
|
|
173
|
+
@objc static func killAll() {
|
|
174
|
+
queue.sync {
|
|
175
|
+
for (_, entry) in contexts {
|
|
176
|
+
entry.2.invalidate()
|
|
177
|
+
}
|
|
178
|
+
let count = contexts.count
|
|
179
|
+
contexts.removeAll()
|
|
180
|
+
jlog("📊 JSCExperiment: killed all \(count) contexts")
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/// How many contexts are alive right now.
|
|
185
|
+
@objc static func aliveCount() -> Int {
|
|
186
|
+
return queue.sync { contexts.count }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/// Convenience: spawn N + return memory delta vs baseline. Caller
|
|
190
|
+
/// records baseline via MemoryMonitor.currentMemoryMB() before calling.
|
|
191
|
+
@objc static func spawnAndMeasure(count: Int, baselineMB: Double) -> [String: Any] {
|
|
192
|
+
let beforeMB = MemoryMonitor.currentMemoryMB()
|
|
193
|
+
let spawned = spawn(count: count)
|
|
194
|
+
// Tiny settle delay so allocations complete before we read.
|
|
195
|
+
Thread.sleep(forTimeInterval: 0.5)
|
|
196
|
+
let afterMB = MemoryMonitor.currentMemoryMB()
|
|
197
|
+
let perContextMB = spawned > 0 ? (afterMB - beforeMB) / Double(spawned) : 0
|
|
198
|
+
let result: [String: Any] = [
|
|
199
|
+
"spawned": spawned,
|
|
200
|
+
"totalAlive": aliveCount(),
|
|
201
|
+
"baselineMB": baselineMB,
|
|
202
|
+
"beforeMB": beforeMB,
|
|
203
|
+
"afterMB": afterMB,
|
|
204
|
+
"deltaMB": afterMB - beforeMB,
|
|
205
|
+
"perContextMB": perContextMB,
|
|
206
|
+
]
|
|
207
|
+
jlog("📊 JSCExperiment.spawnAndMeasure: \(result)")
|
|
208
|
+
return result
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/// Run a full benchmark sweep: spawn 1, 5, 10, 25, 50 in waves with
|
|
212
|
+
/// 2s settle between, log resident MB before and after each. All
|
|
213
|
+
/// output via jlog so it reaches syslog in release builds.
|
|
214
|
+
@objc static func runBenchmark() {
|
|
215
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
216
|
+
killAll()
|
|
217
|
+
// Clear log file for a fresh run.
|
|
218
|
+
try? FileManager.default.removeItem(at: logFileURL)
|
|
219
|
+
Thread.sleep(forTimeInterval: 1.0)
|
|
220
|
+
let baseline = MemoryMonitor.currentMemoryMB()
|
|
221
|
+
jlog("🧪 JSC-BENCH start; baseline \(String(format: "%.1f", baseline)) MB; logFile=\(logFileURL.path)")
|
|
222
|
+
let waves = [1, 5, 10, 25, 50]
|
|
223
|
+
var prevAlive = 0
|
|
224
|
+
for target in waves {
|
|
225
|
+
let need = target - prevAlive
|
|
226
|
+
if need > 0 {
|
|
227
|
+
let beforeMB = MemoryMonitor.currentMemoryMB()
|
|
228
|
+
_ = spawn(count: need)
|
|
229
|
+
Thread.sleep(forTimeInterval: 1.0)
|
|
230
|
+
let afterMB = MemoryMonitor.currentMemoryMB()
|
|
231
|
+
let perContextOverall = (afterMB - baseline) / Double(target)
|
|
232
|
+
jlog("🧪 JSC-BENCH wave: target=\(target) alive=\(aliveCount()) before=\(String(format: "%.1f", beforeMB))MB after=\(String(format: "%.1f", afterMB))MB delta=\(String(format: "%+.1f", afterMB - beforeMB))MB cumPerCtx=\(String(format: "%.2f", perContextOverall))MB")
|
|
233
|
+
prevAlive = target
|
|
234
|
+
}
|
|
235
|
+
Thread.sleep(forTimeInterval: 2.0)
|
|
236
|
+
}
|
|
237
|
+
let final = MemoryMonitor.currentMemoryMB()
|
|
238
|
+
jlog("🧪 JSC-BENCH done; alive=\(aliveCount()) final=\(String(format: "%.1f", final))MB total-delta=\(String(format: "%+.1f", final - baseline))MB")
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//
|
|
2
|
+
// MemoryMonitor.swift
|
|
3
|
+
// Glassly
|
|
4
|
+
//
|
|
5
|
+
// Memory usage monitoring for leak detection
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
class MemoryMonitor {
|
|
11
|
+
private static var timer: Timer?
|
|
12
|
+
private static var startMemoryMB: Double = 0
|
|
13
|
+
|
|
14
|
+
static func start(intervalSeconds: TimeInterval = 30) {
|
|
15
|
+
stop()
|
|
16
|
+
startMemoryMB = currentMemoryMB()
|
|
17
|
+
Bridge.log("📊 Memory Monitor started - baseline: \(String(format: "%.1f", startMemoryMB)) MB")
|
|
18
|
+
|
|
19
|
+
DispatchQueue.main.async {
|
|
20
|
+
timer = Timer.scheduledTimer(withTimeInterval: intervalSeconds, repeats: true) { _ in
|
|
21
|
+
let current = currentMemoryMB()
|
|
22
|
+
let delta = current - startMemoryMB
|
|
23
|
+
let trend = delta > 50 ? "🔴" : delta > 20 ? "🟡" : "⚪"
|
|
24
|
+
Bridge.log("📊 Memory: \(String(format: "%.1f", current)) MB (Δ \(String(format: "%+.1f", delta)) MB) \(trend)")
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static func stop() {
|
|
30
|
+
timer?.invalidate()
|
|
31
|
+
timer = nil
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static func currentMemoryMB() -> Double {
|
|
35
|
+
var info = mach_task_basic_info()
|
|
36
|
+
var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size) / 4
|
|
37
|
+
let result = withUnsafeMutablePointer(to: &info) {
|
|
38
|
+
$0.withMemoryRebound(to: integer_t.self, capacity: 1) {
|
|
39
|
+
task_info(mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO), $0, &count)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return result == KERN_SUCCESS ? Double(info.resident_size) / 1024 / 1024 : 0
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
final class MessageChunkReassembler {
|
|
4
|
+
private static let chunkTimeoutMs: TimeInterval = 30_000
|
|
5
|
+
private static let maxConcurrentSessions = 10
|
|
6
|
+
|
|
7
|
+
private var activeSessions: [String: ChunkSession] = [:]
|
|
8
|
+
|
|
9
|
+
private var activeBinarySessions: [UInt16: BinarySession] = [:]
|
|
10
|
+
|
|
11
|
+
func addBinaryFragment(msgId: UInt16, fragIdx: Int, fragCount: Int, data: Data) -> Data? {
|
|
12
|
+
cleanupTimedOutSessions()
|
|
13
|
+
|
|
14
|
+
guard fragCount > 0, fragIdx >= 0, fragIdx < fragCount else {
|
|
15
|
+
print("MessageChunkReassembler: Dropping invalid binary fragment for msgId \(msgId)")
|
|
16
|
+
return nil
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if let existing = activeBinarySessions[msgId], existing.fragCount != fragCount {
|
|
20
|
+
activeBinarySessions.removeValue(forKey: msgId)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if activeBinarySessions.count >= Self.maxConcurrentSessions,
|
|
24
|
+
activeBinarySessions[msgId] == nil
|
|
25
|
+
{
|
|
26
|
+
removeOldestBinarySession()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let isNewSession = activeBinarySessions[msgId] == nil
|
|
30
|
+
let session = activeBinarySessions[msgId] ?? BinarySession(msgId: msgId, fragCount: fragCount)
|
|
31
|
+
|
|
32
|
+
guard session.addFragment(index: fragIdx, data: data) else {
|
|
33
|
+
return nil
|
|
34
|
+
}
|
|
35
|
+
if isNewSession {
|
|
36
|
+
activeBinarySessions[msgId] = session
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
guard session.isComplete else {
|
|
40
|
+
return nil
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let reassembled = session.reassemble()
|
|
44
|
+
activeBinarySessions.removeValue(forKey: msgId)
|
|
45
|
+
print("MessageChunkReassembler: Reassembled \(reassembled.count) bytes from \(fragCount) binary fragments")
|
|
46
|
+
return reassembled
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func addChunk(_ info: MessageChunker.ChunkInfo) -> String? {
|
|
50
|
+
cleanupTimedOutSessions()
|
|
51
|
+
|
|
52
|
+
guard !info.chunkId.isEmpty,
|
|
53
|
+
info.totalChunks > 0,
|
|
54
|
+
info.chunkIndex >= 0,
|
|
55
|
+
info.chunkIndex < info.totalChunks
|
|
56
|
+
else {
|
|
57
|
+
print("MessageChunkReassembler: Dropping invalid chunk metadata for \(info.chunkId)")
|
|
58
|
+
return nil
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if let existing = activeSessions[info.chunkId], existing.totalChunks != info.totalChunks {
|
|
62
|
+
print(
|
|
63
|
+
"MessageChunkReassembler: totalChunks mismatch for \(info.chunkId) (expected \(existing.totalChunks), got \(info.totalChunks)); resetting session"
|
|
64
|
+
)
|
|
65
|
+
activeSessions.removeValue(forKey: info.chunkId)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if activeSessions.count >= Self.maxConcurrentSessions,
|
|
69
|
+
activeSessions[info.chunkId] == nil
|
|
70
|
+
{
|
|
71
|
+
removeOldestSession()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let isNewSession = activeSessions[info.chunkId] == nil
|
|
75
|
+
let session = activeSessions[info.chunkId] ?? ChunkSession(
|
|
76
|
+
chunkId: info.chunkId,
|
|
77
|
+
totalChunks: info.totalChunks
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
guard session.addChunk(index: info.chunkIndex, data: info.data) else {
|
|
81
|
+
print("MessageChunkReassembler: Failed to add chunk \(info.chunkIndex) for \(info.chunkId)")
|
|
82
|
+
return nil
|
|
83
|
+
}
|
|
84
|
+
if isNewSession {
|
|
85
|
+
activeSessions[info.chunkId] = session
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
guard session.isComplete else {
|
|
89
|
+
return nil
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let reassembled = session.reassemble()
|
|
93
|
+
activeSessions.removeValue(forKey: info.chunkId)
|
|
94
|
+
print("MessageChunkReassembler: Reassembled \(reassembled.count) bytes from \(info.totalChunks) chunks")
|
|
95
|
+
return reassembled
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func clear() {
|
|
99
|
+
activeSessions.removeAll()
|
|
100
|
+
activeBinarySessions.removeAll()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private func cleanupTimedOutSessions() {
|
|
104
|
+
let now = Date().timeIntervalSince1970 * 1000
|
|
105
|
+
activeSessions = activeSessions.filter { entry in
|
|
106
|
+
now - entry.value.createdAtMs <= Self.chunkTimeoutMs
|
|
107
|
+
}
|
|
108
|
+
activeBinarySessions = activeBinarySessions.filter { entry in
|
|
109
|
+
now - entry.value.createdAtMs <= Self.chunkTimeoutMs
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private func removeOldestBinarySession() {
|
|
114
|
+
guard let oldest = activeBinarySessions.min(by: { $0.value.createdAtMs < $1.value.createdAtMs }) else {
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
activeBinarySessions.removeValue(forKey: oldest.key)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private func removeOldestSession() {
|
|
121
|
+
guard let oldest = activeSessions.min(by: { $0.value.createdAtMs < $1.value.createdAtMs }) else {
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
activeSessions.removeValue(forKey: oldest.key)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private final class ChunkSession {
|
|
128
|
+
let chunkId: String
|
|
129
|
+
let totalChunks: Int
|
|
130
|
+
let createdAtMs: TimeInterval
|
|
131
|
+
private var chunks: [Int: String] = [:]
|
|
132
|
+
|
|
133
|
+
init(chunkId: String, totalChunks: Int) {
|
|
134
|
+
self.chunkId = chunkId
|
|
135
|
+
self.totalChunks = totalChunks
|
|
136
|
+
self.createdAtMs = Date().timeIntervalSince1970 * 1000
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
func addChunk(index: Int, data: String) -> Bool {
|
|
140
|
+
guard index >= 0, index < totalChunks else {
|
|
141
|
+
return false
|
|
142
|
+
}
|
|
143
|
+
chunks[index] = data
|
|
144
|
+
return true
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
var isComplete: Bool {
|
|
148
|
+
chunks.count == totalChunks
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
func reassemble() -> String {
|
|
152
|
+
var result = ""
|
|
153
|
+
for index in 0 ..< totalChunks {
|
|
154
|
+
result += chunks[index] ?? ""
|
|
155
|
+
}
|
|
156
|
+
return result
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private final class BinarySession {
|
|
161
|
+
let msgId: UInt16
|
|
162
|
+
let fragCount: Int
|
|
163
|
+
let createdAtMs: TimeInterval
|
|
164
|
+
private var fragments: [Int: Data] = [:]
|
|
165
|
+
|
|
166
|
+
init(msgId: UInt16, fragCount: Int) {
|
|
167
|
+
self.msgId = msgId
|
|
168
|
+
self.fragCount = fragCount
|
|
169
|
+
self.createdAtMs = Date().timeIntervalSince1970 * 1000
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
func addFragment(index: Int, data: Data) -> Bool {
|
|
173
|
+
guard index >= 0, index < fragCount else { return false }
|
|
174
|
+
fragments[index] = data
|
|
175
|
+
return true
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
var isComplete: Bool {
|
|
179
|
+
fragments.count == fragCount
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
func reassemble() -> Data {
|
|
183
|
+
var result = Data()
|
|
184
|
+
for index in 0 ..< fragCount {
|
|
185
|
+
result.append(fragments[index] ?? Data())
|
|
186
|
+
}
|
|
187
|
+
return result
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|