@mentra/bluetooth-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +278 -0
- package/android/build.gradle +167 -0
- package/android/lc3Lib/CMakeLists.txt +6 -0
- package/android/lc3Lib/build.gradle +109 -0
- package/android/lc3Lib/proguard-rules.pro +33 -0
- package/android/lc3Lib/src/main/AndroidManifest.xml +2 -0
- package/android/lc3Lib/src/main/cpp/CMakeLists.txt +8 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/CMakeLists.txt +30 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/CMakeLists.txt +7 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.cc +96 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.h +53 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/Makefile.am +6 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h +26 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h.in +26 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/ogg.h +209 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/os_types.h +158 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus.h +981 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_custom.h +342 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_defines.h +799 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_multistream.h +660 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_projection.h +568 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_types.h +166 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.cc +268 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.h +115 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/opus_tools/opus_header.h +59 -0
- package/android/lc3Lib/src/main/cpp/liblc3/CMakeLists.txt +38 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/lc3.h +309 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/lc3_private.h +162 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/rnnoise.h +114 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/CMakeLists.txt +19 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.c +92 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.h +44 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.c +375 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.h +315 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.c +129 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.h +69 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/common.h +148 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.c +70 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.h +43 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/fastmath.h +158 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/lc3.c +702 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.c +893 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.h +111 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_arm.h +506 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_neon.h +281 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/makefile.mk +35 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.c +452 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.h +57 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct_neon.h +296 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/meson.build +46 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.c +61 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.h +57 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.c +880 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.h +103 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.c +904 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.h +119 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.c +3457 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.h +94 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.c +457 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.h +99 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3.cpp +159 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/_kiss_fft_guts.h +182 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/arch.h +261 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.c +279 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.h +59 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/common.h +48 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/compile.sh +3 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/denoise.c +646 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.c +601 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.h +203 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/opus_types.h +159 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.c +526 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.h +149 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.c +178 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.h +69 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.c +11051 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.h +34 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_reader.c +168 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_train.py +66 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/tansig_table.h +45 -0
- package/android/lc3Lib/src/main/java/com/mentra/lc3Lib/Lc3Cpp.java +38 -0
- package/android/lc3Lib/third_party/CMakeLists.txt +23 -0
- package/android/lc3Lib/third_party/CMakeLists_libogg.txt +18 -0
- package/android/lc3Lib/third_party/CMakeLists_libopus.txt +18 -0
- package/android/lc3Lib/third_party/CMakeLists_opus-tools.txt +23 -0
- package/android/lc3Lib/third_party/opus_tools/src/AUTHORS +5 -0
- package/android/lc3Lib/third_party/opus_tools/src/CMakeLists.txt +4 -0
- package/android/lc3Lib/third_party/opus_tools/src/COPYING +371 -0
- package/android/lc3Lib/third_party/opus_tools/src/ChangeLog +3 -0
- package/android/lc3Lib/third_party/opus_tools/src/Makefile.am +42 -0
- package/android/lc3Lib/third_party/opus_tools/src/Makefile.unix +23 -0
- package/android/lc3Lib/third_party/opus_tools/src/NEWS +0 -0
- package/android/lc3Lib/third_party/opus_tools/src/README +0 -0
- package/android/lc3Lib/third_party/opus_tools/src/autogen.sh +115 -0
- package/android/lc3Lib/third_party/opus_tools/src/configure.ac +293 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/arch.h +239 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/audio-in.c +1046 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.c +245 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.h +28 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.c +320 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.h +51 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/lpc.c +157 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/lpc.h +27 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.c +286 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.h +59 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusdec.c +884 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.c +1021 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.h +101 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.c +639 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.h +51 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/os_support.h +167 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/resample.c +1137 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/speex_resampler.h +344 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/stack_alloc.h +115 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.c +125 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.h +62 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.c +223 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.h +60 -0
- package/android/settings.gradle +1 -0
- package/android/src/main/AndroidManifest.xml +40 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +528 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +610 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +1616 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +314 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +1710 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +554 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/ObservableStore.kt +68 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +158 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +934 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/services/Foreground.kt +175 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +1109 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +3974 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3551 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1327 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +6959 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1655 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraosBle.java +53675 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +202 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +224 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/STTTools.kt +340 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +465 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/VadGateSpeechPolicy.kt +221 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/AES.java +106 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/AudioSessionMonitor.kt +189 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/BitmapJavaUtils.java +169 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadService.java +179 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +44 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/G1Text.kt +436 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleRelayNaming.java +29 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleUploadService.java +76 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtils.java +791 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunker.java +186 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/NexSGCUtils.kt +589 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/PhoneAudioMonitor.kt +303 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/SmartGlassesConnectionState.java +9 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/ByteUtilAudioPlayer.java +655 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/Lc3Player.java +441 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/PCMAudioPlayer.java +431 -0
- package/android/src/main/res/values/strings.xml +4 -0
- package/app.plugin.js +1 -0
- package/build/BluetoothSdk.types.d.ts +498 -0
- package/build/BluetoothSdk.types.d.ts.map +1 -0
- package/build/BluetoothSdk.types.js +23 -0
- package/build/BluetoothSdk.types.js.map +1 -0
- package/build/BluetoothSdkModule.d.ts +71 -0
- package/build/BluetoothSdkModule.d.ts.map +1 -0
- package/build/BluetoothSdkModule.js +106 -0
- package/build/BluetoothSdkModule.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +5 -0
- package/build/index.js.map +1 -0
- package/expo-module.config.json +9 -0
- package/ios/BluetoothSdkModule.swift +665 -0
- package/ios/MentraBluetoothSDK.podspec +77 -0
- package/ios/Packages/CoreObjC/CoreObjC.xcodeproj/project.pbxproj +213 -0
- package/ios/Packages/CoreObjC/PcmConverter.h +22 -0
- package/ios/Packages/CoreObjC/PcmConverter.m +266 -0
- package/ios/Packages/CoreObjC/attdet.c +92 -0
- package/ios/Packages/CoreObjC/attdet.h +44 -0
- package/ios/Packages/CoreObjC/bits.c +375 -0
- package/ios/Packages/CoreObjC/bits.h +315 -0
- package/ios/Packages/CoreObjC/bwdet.c +129 -0
- package/ios/Packages/CoreObjC/bwdet.h +69 -0
- package/ios/Packages/CoreObjC/common.h +151 -0
- package/ios/Packages/CoreObjC/energy.c +70 -0
- package/ios/Packages/CoreObjC/energy.h +43 -0
- package/ios/Packages/CoreObjC/fastmath.h +158 -0
- package/ios/Packages/CoreObjC/lc3.c +704 -0
- package/ios/Packages/CoreObjC/lc3.h +313 -0
- package/ios/Packages/CoreObjC/lc3_cpp.h +283 -0
- package/ios/Packages/CoreObjC/lc3_private.h +163 -0
- package/ios/Packages/CoreObjC/ltpf.c +905 -0
- package/ios/Packages/CoreObjC/ltpf.h +111 -0
- package/ios/Packages/CoreObjC/ltpf_arm.h +506 -0
- package/ios/Packages/CoreObjC/ltpf_neon.h +281 -0
- package/ios/Packages/CoreObjC/makefile.mk +35 -0
- package/ios/Packages/CoreObjC/mdct.c +469 -0
- package/ios/Packages/CoreObjC/mdct.h +57 -0
- package/ios/Packages/CoreObjC/mdct_neon.h +296 -0
- package/ios/Packages/CoreObjC/meson.build +61 -0
- package/ios/Packages/CoreObjC/plc.c +61 -0
- package/ios/Packages/CoreObjC/plc.h +57 -0
- package/ios/Packages/CoreObjC/rnnoise.h +114 -0
- package/ios/Packages/CoreObjC/sns.c +880 -0
- package/ios/Packages/CoreObjC/sns.h +103 -0
- package/ios/Packages/CoreObjC/spec.c +907 -0
- package/ios/Packages/CoreObjC/spec.h +119 -0
- package/ios/Packages/CoreObjC/tables.c +3457 -0
- package/ios/Packages/CoreObjC/tables.h +94 -0
- package/ios/Packages/CoreObjC/tns.c +457 -0
- package/ios/Packages/CoreObjC/tns.h +99 -0
- package/ios/Packages/SherpaOnnx/Model/joiner.onnx +0 -0
- package/ios/Packages/SherpaOnnx/Model/tokens.txt +502 -0
- package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +1659 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/cargs.h +162 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/c-api.h +1852 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/cxx-api.h +674 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +44 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/libsherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/sherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/sherpa-onnx.a +0 -0
- package/ios/Packages/VAD/Common/VAD/VADQuality.swift +41 -0
- package/ios/Packages/VAD/Common/VAD/VADState.swift +26 -0
- package/ios/Packages/VAD/Common/VAD/VADStrategy.swift +29 -0
- package/ios/Packages/VAD/Common/VAD/VADType.swift +14 -0
- package/ios/Packages/VAD/Data/Configuration.swift +68 -0
- package/ios/Packages/VAD/Data/FrameSize.swift +39 -0
- package/ios/Packages/VAD/Data/Record.swift +13 -0
- package/ios/Packages/VAD/Data/Result.swift +22 -0
- package/ios/Packages/VAD/Data/SampleRate.swift +48 -0
- package/ios/Packages/VAD/Silero/Model/silero_vad.onnx +0 -0
- package/ios/Packages/VAD/Silero/SileroVAD.swift +284 -0
- package/ios/Packages/VAD/Silero/SileroVADStrategy.swift +64 -0
- package/ios/Packages/libbz2/module.modulemap +5 -0
- package/ios/Packages/libbz2/shim.h +1 -0
- package/ios/Source/Bridge.swift +353 -0
- package/ios/Source/Bridging-Header.h +16 -0
- package/ios/Source/DeviceManager.swift +1478 -0
- package/ios/Source/DeviceStore.swift +295 -0
- package/ios/Source/MentraBluetoothSDK.swift +2439 -0
- package/ios/Source/ObservableStore.swift +88 -0
- package/ios/Source/PrivacyInfo.xcprivacy +23 -0
- package/ios/Source/controllers/ControllerManager.swift +187 -0
- package/ios/Source/controllers/R1.swift +827 -0
- package/ios/Source/services/PhoneMic.swift +662 -0
- package/ios/Source/sgcs/Frame.swift +651 -0
- package/ios/Source/sgcs/G1.swift +2505 -0
- package/ios/Source/sgcs/G2.swift +3730 -0
- package/ios/Source/sgcs/Mach1.swift +543 -0
- package/ios/Source/sgcs/MentraLive.swift +4708 -0
- package/ios/Source/sgcs/MentraNex.swift +2479 -0
- package/ios/Source/sgcs/SGCManager.swift +243 -0
- package/ios/Source/sgcs/Simulated.swift +270 -0
- package/ios/Source/sgcs/mentraos_ble.pb.swift +3811 -0
- package/ios/Source/stt/STTTools.swift +154 -0
- package/ios/Source/stt/SherpaOnnxTranscriber.swift +401 -0
- package/ios/Source/utils/AudioSessionMonitor.swift +283 -0
- package/ios/Source/utils/Constants.swift +74 -0
- package/ios/Source/utils/Enums.swift +95 -0
- package/ios/Source/utils/G1Text.swift +2067 -0
- package/ios/Source/utils/JSCExperiment.swift +241 -0
- package/ios/Source/utils/MemoryMonitor.swift +44 -0
- package/ios/Source/utils/MessageChunker.swift +164 -0
- package/ios/Source/utils/Models.swift +135 -0
- package/ios/Source/utils/PhoneAudioMonitor.swift +226 -0
- package/ios/Source/utils/TarBz2Extractor.swift +206 -0
- package/package.json +78 -0
- package/plugin/build/index.d.ts +6 -0
- package/plugin/build/index.js +12 -0
- package/plugin/build/withAndroid.d.ts +4 -0
- package/plugin/build/withAndroid.js +80 -0
- package/plugin/build/withIos.d.ts +4 -0
- package/plugin/build/withIos.js +64 -0
- package/src/BluetoothSdk.types.ts +581 -0
- package/src/BluetoothSdkModule.ts +259 -0
- package/src/index.ts +4 -0
package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/sherpa-onnx.a
ADDED
|
Binary file
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//
|
|
2
|
+
// VADQuality.swift
|
|
3
|
+
// ios-vad
|
|
4
|
+
//
|
|
5
|
+
// Created by baochuquan on 2024/11/9.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
enum VADQuality: String, CaseIterable {
|
|
11
|
+
case normal = "NORMAL"
|
|
12
|
+
case low_bitrate = "LOW_BITERATE"
|
|
13
|
+
case aggressive = "AGGRESSIVE"
|
|
14
|
+
case very_aggressive = "VERY_AGGRESSIVE"
|
|
15
|
+
|
|
16
|
+
var desc: String {
|
|
17
|
+
rawValue
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
var threshold: Float {
|
|
21
|
+
switch self {
|
|
22
|
+
case .normal: return 0.3
|
|
23
|
+
case .low_bitrate: return 0.7
|
|
24
|
+
case .aggressive: return 0.8
|
|
25
|
+
case .very_aggressive: return 0.90
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
var webrtcMode: Int {
|
|
30
|
+
switch self {
|
|
31
|
+
case .normal: return 0
|
|
32
|
+
case .low_bitrate: return 1
|
|
33
|
+
case .aggressive: return 2
|
|
34
|
+
case .very_aggressive: return 3
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static let webrtc: [VADQuality] = [.normal, .low_bitrate, .aggressive, .very_aggressive]
|
|
39
|
+
static let silero: [VADQuality] = [.normal, .aggressive, .very_aggressive]
|
|
40
|
+
static let yamnet: [VADQuality] = [.normal]
|
|
41
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//
|
|
2
|
+
// VADState.swift
|
|
3
|
+
// ios-vad
|
|
4
|
+
//
|
|
5
|
+
// Created by baochuquan on 2024/11/9.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
enum VADState {
|
|
11
|
+
case start // 开始说话
|
|
12
|
+
case speeching // 说话中
|
|
13
|
+
case end // 结束说话
|
|
14
|
+
case silence // 静默中
|
|
15
|
+
case error // 出错了
|
|
16
|
+
|
|
17
|
+
var desc: String {
|
|
18
|
+
switch self {
|
|
19
|
+
case .start: return "VAD Start"
|
|
20
|
+
case .speeching: return "VAD Speeching"
|
|
21
|
+
case .end: return "VAD End"
|
|
22
|
+
case .silence: return "VAD Silence"
|
|
23
|
+
case .error: return "Error"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//
|
|
2
|
+
// VADStrategy.swift
|
|
3
|
+
// ios-vad
|
|
4
|
+
//
|
|
5
|
+
// Created by baochuquan on 2024/11/9.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
protocol VADStrategy {
|
|
11
|
+
/// vad setup method
|
|
12
|
+
/// - Parameters:
|
|
13
|
+
/// - sampleRate: sample rate
|
|
14
|
+
/// - frameSize: frame size
|
|
15
|
+
/// - quality: vad quality level
|
|
16
|
+
/// - silenceTriggerDurationMs: the minimum duration required to switch from speech to silence. Unit: millisecond.
|
|
17
|
+
/// - speechTriggerDurationMs: the minimum duration required to switch from silence to speech. Unit: millisecond.
|
|
18
|
+
func setup(sampleRate: SampleRate, frameSize: FrameSize, quality: VADQuality, silenceTriggerDurationMs: Int64, speechTriggerDurationMs: Int64)
|
|
19
|
+
|
|
20
|
+
/// vad check result callback
|
|
21
|
+
/// - Parameters:
|
|
22
|
+
/// - pcm: pcm Data
|
|
23
|
+
/// - handler: callback.
|
|
24
|
+
func checkVAD(pcm: [Int16], handler: @escaping (VADState) -> Void)
|
|
25
|
+
|
|
26
|
+
/// current vad state
|
|
27
|
+
/// - Returns: vad state
|
|
28
|
+
func currentState() -> VADState
|
|
29
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Configuration.swift
|
|
3
|
+
// ios-vad
|
|
4
|
+
//
|
|
5
|
+
// Created by baochuquan on 2024/11/9.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
// MARK: - Sample Rate Config
|
|
11
|
+
|
|
12
|
+
struct SampleRateConfiguration: Hashable {
|
|
13
|
+
var selectedOption: SampleRate
|
|
14
|
+
var options: [SampleRate]
|
|
15
|
+
|
|
16
|
+
static let webrtc = SampleRateConfiguration(selectedOption: SampleRate.webrtc[0], options: SampleRate.webrtc)
|
|
17
|
+
|
|
18
|
+
static let silero = SampleRateConfiguration(selectedOption: SampleRate.silero[0], options: SampleRate.silero)
|
|
19
|
+
|
|
20
|
+
static let yamnet = SampleRateConfiguration(selectedOption: SampleRate.yamnet[0], options: SampleRate.yamnet)
|
|
21
|
+
|
|
22
|
+
func frameSizeConfiguration(type: VADType) -> FrameSizeConfiguration {
|
|
23
|
+
let options = selectedOption.frameSizeOptions(type: type)
|
|
24
|
+
return FrameSizeConfiguration(selectedOption: options[0], options: options)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// MARK: - Frame Size Config
|
|
29
|
+
|
|
30
|
+
struct FrameSizeConfiguration: Hashable {
|
|
31
|
+
var selectedOption: FrameSize
|
|
32
|
+
var options: [FrameSize]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// MARK: - Mode Config
|
|
36
|
+
|
|
37
|
+
struct QualityConfiguration: Hashable {
|
|
38
|
+
var selectedOption: VADQuality
|
|
39
|
+
var options: [VADQuality]
|
|
40
|
+
|
|
41
|
+
static let webrtc = QualityConfiguration(
|
|
42
|
+
selectedOption: .very_aggressive,
|
|
43
|
+
options: [
|
|
44
|
+
.normal,
|
|
45
|
+
.low_bitrate,
|
|
46
|
+
.aggressive,
|
|
47
|
+
.very_aggressive,
|
|
48
|
+
]
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
static let silero = QualityConfiguration(
|
|
52
|
+
selectedOption: .normal,
|
|
53
|
+
options: [
|
|
54
|
+
.normal,
|
|
55
|
+
.aggressive,
|
|
56
|
+
.very_aggressive,
|
|
57
|
+
]
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
static let yamnet = QualityConfiguration(
|
|
61
|
+
selectedOption: .normal,
|
|
62
|
+
options: [
|
|
63
|
+
.normal,
|
|
64
|
+
.aggressive,
|
|
65
|
+
.very_aggressive,
|
|
66
|
+
]
|
|
67
|
+
)
|
|
68
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//
|
|
2
|
+
// FrameSize.swift
|
|
3
|
+
// ios-vad
|
|
4
|
+
//
|
|
5
|
+
// Created by baochuquan on 2024/11/9.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
enum FrameSize: Int, CaseIterable {
|
|
11
|
+
case size_80 = 80
|
|
12
|
+
case size_160 = 160
|
|
13
|
+
case size_240 = 240
|
|
14
|
+
case size_320 = 320
|
|
15
|
+
case size_256 = 256
|
|
16
|
+
case size_480 = 480
|
|
17
|
+
case size_512 = 512
|
|
18
|
+
case size_640 = 640
|
|
19
|
+
case size_768 = 768
|
|
20
|
+
case size_960 = 960
|
|
21
|
+
case size_1024 = 1024
|
|
22
|
+
case size_1440 = 1440
|
|
23
|
+
case size_1536 = 1536
|
|
24
|
+
case size_15600 = 15600
|
|
25
|
+
|
|
26
|
+
var desc: String {
|
|
27
|
+
"FRAME_SIZE_\(rawValue)"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static let webrtc_8k: [FrameSize] = [.size_80, .size_160, .size_240]
|
|
31
|
+
static let webrtc_16k: [FrameSize] = [.size_160, .size_320, .size_480]
|
|
32
|
+
static let webrtc_32k: [FrameSize] = [.size_320, .size_640, .size_960]
|
|
33
|
+
static let webrtc_48k: [FrameSize] = [.size_480, .size_960, .size_1440]
|
|
34
|
+
|
|
35
|
+
static let silero_8k: [FrameSize] = [.size_256, .size_512, .size_768]
|
|
36
|
+
static let silero_16k: [FrameSize] = [.size_512, .size_1024, .size_1536]
|
|
37
|
+
|
|
38
|
+
static let yamnet_15k: [FrameSize] = [.size_15600]
|
|
39
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Result.swift
|
|
3
|
+
// ios-vad
|
|
4
|
+
//
|
|
5
|
+
// Created by baochuquan on 2024/11/9.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
enum VADResult {
|
|
11
|
+
case idle
|
|
12
|
+
case speech
|
|
13
|
+
case silence
|
|
14
|
+
|
|
15
|
+
var desc: String {
|
|
16
|
+
switch self {
|
|
17
|
+
case .idle: return "Press button to start VAD!"
|
|
18
|
+
case .speech: return "Speeching"
|
|
19
|
+
case .silence: return "Silence"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SampleRate.swift
|
|
3
|
+
// ios-vad
|
|
4
|
+
//
|
|
5
|
+
// Created by baochuquan on 2024/11/9.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
enum SampleRate: Int, CaseIterable {
|
|
11
|
+
case rate_8k = 8000
|
|
12
|
+
case rate_15K = 15600
|
|
13
|
+
case rate_16k = 16000
|
|
14
|
+
case rate_32k = 32000
|
|
15
|
+
case rate_48k = 48000
|
|
16
|
+
|
|
17
|
+
var desc: String {
|
|
18
|
+
"SAMPLE_RATE_\(rawValue)"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static let webrtc: [SampleRate] = [.rate_8k, .rate_16k, .rate_32k, .rate_48k]
|
|
22
|
+
static let silero: [SampleRate] = [.rate_8k, .rate_16k]
|
|
23
|
+
static let yamnet: [SampleRate] = [.rate_15K]
|
|
24
|
+
|
|
25
|
+
func frameSizeOptions(type: VADType) -> [FrameSize] {
|
|
26
|
+
switch type {
|
|
27
|
+
case .webrtc:
|
|
28
|
+
switch self {
|
|
29
|
+
case .rate_8k: return FrameSize.webrtc_8k
|
|
30
|
+
case .rate_16k: return FrameSize.webrtc_16k
|
|
31
|
+
case .rate_32k: return FrameSize.webrtc_32k
|
|
32
|
+
case .rate_48k: return FrameSize.webrtc_48k
|
|
33
|
+
default: return []
|
|
34
|
+
}
|
|
35
|
+
case .silero:
|
|
36
|
+
switch self {
|
|
37
|
+
case .rate_8k: return FrameSize.silero_8k
|
|
38
|
+
case .rate_16k: return FrameSize.silero_16k
|
|
39
|
+
default: return []
|
|
40
|
+
}
|
|
41
|
+
case .yamnet:
|
|
42
|
+
switch self {
|
|
43
|
+
case .rate_15K: return FrameSize.yamnet_15k
|
|
44
|
+
default: return []
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SileroVAD.swift
|
|
3
|
+
// ios-vad
|
|
4
|
+
//
|
|
5
|
+
// Created by baochuquan on 2024/11/9.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
import onnxruntime_objc
|
|
10
|
+
|
|
11
|
+
public protocol SileroVADDelegate: AnyObject {
|
|
12
|
+
func sileroVADDidDetectSpeechStart()
|
|
13
|
+
func sileroVADDidDetectSpeechEnd()
|
|
14
|
+
func sileroVADDidDetectSpeeching()
|
|
15
|
+
func sileroVADDidDetectSilence()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public class SileroVAD: NSObject {
|
|
19
|
+
private enum State {
|
|
20
|
+
case silence
|
|
21
|
+
case start
|
|
22
|
+
case speeching
|
|
23
|
+
case end
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private class InternalBuffer {
|
|
27
|
+
private let size: Int
|
|
28
|
+
// Use ContiguousArray for better memory layout and to avoid copy-on-write issues
|
|
29
|
+
// when the array buffer is accessed from multiple threads
|
|
30
|
+
private var buffer: ContiguousArray<Bool>
|
|
31
|
+
private let lock = NSLock()
|
|
32
|
+
|
|
33
|
+
init(size: Int) {
|
|
34
|
+
self.size = size
|
|
35
|
+
// Pre-allocate capacity to minimize reallocations
|
|
36
|
+
buffer = ContiguousArray<Bool>()
|
|
37
|
+
buffer.reserveCapacity(size + 1)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func append(_ isSpeech: Bool) {
|
|
41
|
+
lock.lock()
|
|
42
|
+
// Perform all mutations while holding the lock
|
|
43
|
+
if buffer.count >= size {
|
|
44
|
+
// Remove oldest elements to make room
|
|
45
|
+
let removeCount = buffer.count - size + 1
|
|
46
|
+
buffer.removeFirst(removeCount)
|
|
47
|
+
}
|
|
48
|
+
buffer.append(isSpeech)
|
|
49
|
+
lock.unlock()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func isAllSpeech() -> Bool {
|
|
53
|
+
lock.lock()
|
|
54
|
+
// Copy the values we need while holding the lock
|
|
55
|
+
let count = buffer.count
|
|
56
|
+
let targetSize = size
|
|
57
|
+
let allTrue = count == targetSize && !buffer.contains(false)
|
|
58
|
+
lock.unlock()
|
|
59
|
+
return allTrue
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
func isAllNotSpeech() -> Bool {
|
|
63
|
+
lock.lock()
|
|
64
|
+
// Copy the values we need while holding the lock
|
|
65
|
+
let count = buffer.count
|
|
66
|
+
let targetSize = size
|
|
67
|
+
let allFalse = count == targetSize && !buffer.contains(true)
|
|
68
|
+
lock.unlock()
|
|
69
|
+
return allFalse
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 支持两种采样率,不同的采样率时,支持的 windowSizeSmaple 不一样
|
|
74
|
+
// sample rate: 8000; sliceSize: 256/512/768
|
|
75
|
+
// sample rate: 16000; sliceSize: 512/1024/1536
|
|
76
|
+
|
|
77
|
+
static var modelPath: String {
|
|
78
|
+
// Try to find the model in the bundle containing this class (for CocoaPods)
|
|
79
|
+
let bundle = Bundle(for: SileroVAD.self)
|
|
80
|
+
if let path = bundle.path(forResource: "silero_vad", ofType: "onnx") {
|
|
81
|
+
return path
|
|
82
|
+
}
|
|
83
|
+
// Fall back to main bundle
|
|
84
|
+
return Bundle.main.path(forResource: "silero_vad", ofType: "onnx") ?? ""
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public weak var delegate: SileroVADDelegate?
|
|
88
|
+
// 配置参数
|
|
89
|
+
private let sampleRate: Int64
|
|
90
|
+
private let sliceSizeSamples: Int64
|
|
91
|
+
private let threshold: Float
|
|
92
|
+
// 内部状态
|
|
93
|
+
private var state: State = .silence
|
|
94
|
+
private var silenceBuffer: InternalBuffer
|
|
95
|
+
private var speechBuffer: InternalBuffer
|
|
96
|
+
|
|
97
|
+
// 神经网络迭代状态
|
|
98
|
+
private var hidden: [[[Float]]]
|
|
99
|
+
private var cell: [[[Float]]]
|
|
100
|
+
private let hcSize: Int = 2 * 1 * 64
|
|
101
|
+
|
|
102
|
+
private var env: ORTEnv?
|
|
103
|
+
private var session: ORTSession
|
|
104
|
+
|
|
105
|
+
// Pre-allocated buffers to avoid creating new objects every frame (memory leak fix)
|
|
106
|
+
private var inputData: NSMutableData!
|
|
107
|
+
private var srData: NSMutableData!
|
|
108
|
+
private var hData: NSMutableData!
|
|
109
|
+
private var cData: NSMutableData!
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* sampleRate: 16000, 8000
|
|
113
|
+
* sliceSize:
|
|
114
|
+
* - sampleRate: 8000; sliceSize: 256, 512, 768
|
|
115
|
+
* - sampleRate: 16000; sliceSize: 512, 1024, 1536
|
|
116
|
+
*/
|
|
117
|
+
public init(sampleRate: Int64, sliceSize: Int64, threshold: Float, silenceTriggerDurationMs: Int64, speechTriggerDurationMs: Int64, modelPath: String = "") {
|
|
118
|
+
self.sampleRate = sampleRate
|
|
119
|
+
sliceSizeSamples = sliceSize
|
|
120
|
+
self.threshold = threshold
|
|
121
|
+
|
|
122
|
+
let samplesPerMs = sampleRate / 1000
|
|
123
|
+
let silenceBufferSize = Int(ceil(Float(samplesPerMs * silenceTriggerDurationMs) / Float(sliceSize)))
|
|
124
|
+
let speechBufferSize = Int(ceil(Float(samplesPerMs * speechTriggerDurationMs) / Float(sliceSize)))
|
|
125
|
+
silenceBuffer = InternalBuffer(size: silenceBufferSize)
|
|
126
|
+
speechBuffer = InternalBuffer(size: speechBufferSize)
|
|
127
|
+
|
|
128
|
+
hidden = Array(repeating: Array(repeating: Array(repeating: Float(0.0), count: 64), count: 1), count: 2)
|
|
129
|
+
cell = Array(repeating: Array(repeating: Array(repeating: Float(0.0), count: 64), count: 1), count: 2)
|
|
130
|
+
|
|
131
|
+
do {
|
|
132
|
+
env = try? ORTEnv(loggingLevel: .warning)
|
|
133
|
+
let sessionOptions = try? ORTSessionOptions()
|
|
134
|
+
try sessionOptions?.setIntraOpNumThreads(1)
|
|
135
|
+
try sessionOptions?.setGraphOptimizationLevel(.all)
|
|
136
|
+
let path: String
|
|
137
|
+
if modelPath.isEmpty {
|
|
138
|
+
path = Self.modelPath
|
|
139
|
+
} else {
|
|
140
|
+
path = modelPath
|
|
141
|
+
}
|
|
142
|
+
let session = try? ORTSession(env: env!, modelPath: path, sessionOptions: sessionOptions!)
|
|
143
|
+
self.session = session!
|
|
144
|
+
} catch {
|
|
145
|
+
fatalError()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Pre-allocate reusable buffers for ONNX inference (prevents memory leak)
|
|
149
|
+
inputData = NSMutableData(length: Int(sliceSize) * MemoryLayout<Float>.size)!
|
|
150
|
+
srData = NSMutableData(bytes: [sampleRate], length: MemoryLayout<Int64>.size)
|
|
151
|
+
hData = NSMutableData(length: hcSize * MemoryLayout<Float>.size)!
|
|
152
|
+
cData = NSMutableData(length: hcSize * MemoryLayout<Float>.size)!
|
|
153
|
+
|
|
154
|
+
super.init()
|
|
155
|
+
debugLog("SampleRate = \(sampleRate); sliceSize = \(sliceSize); threshold = \(threshold); silenceTriggerDurationMs = \(silenceTriggerDurationMs); speechTriggerDurationMs = \(speechTriggerDurationMs)")
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public func resetState() {
|
|
159
|
+
hidden = Array(repeating: Array(repeating: Array(repeating: Float(0.0), count: 64), count: 1), count: 2)
|
|
160
|
+
cell = Array(repeating: Array(repeating: Array(repeating: Float(0.0), count: 64), count: 1), count: 2)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
public func predict(data: [Float]) throws {
|
|
164
|
+
let inputShape: [NSNumber] = [1, NSNumber(value: sliceSizeSamples)]
|
|
165
|
+
|
|
166
|
+
// Copy input data into pre-allocated buffer (reuse buffer to avoid memory leak)
|
|
167
|
+
data.withUnsafeBytes { ptr in
|
|
168
|
+
inputData.replaceBytes(in: NSRange(location: 0, length: inputData.length), withBytes: ptr.baseAddress!)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Copy hidden state into pre-allocated buffer
|
|
172
|
+
let flatHidden = hidden.flatMap { $0.flatMap { $0 } }
|
|
173
|
+
flatHidden.withUnsafeBytes { ptr in
|
|
174
|
+
hData.replaceBytes(in: NSRange(location: 0, length: hData.length), withBytes: ptr.baseAddress!)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Copy cell state into pre-allocated buffer
|
|
178
|
+
let flatCell = cell.flatMap { $0.flatMap { $0 } }
|
|
179
|
+
flatCell.withUnsafeBytes { ptr in
|
|
180
|
+
cData.replaceBytes(in: NSRange(location: 0, length: cData.length), withBytes: ptr.baseAddress!)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Create tensors from pre-allocated buffers (ORTValue creation is unavoidable but buffers are reused)
|
|
184
|
+
let inputTensor = try ORTValue(tensorData: inputData, elementType: .float, shape: inputShape)
|
|
185
|
+
let srTensor = try ORTValue(tensorData: srData, elementType: .int64, shape: [1])
|
|
186
|
+
let hTensor = try ORTValue(tensorData: hData, elementType: .float, shape: [2, 1, 64])
|
|
187
|
+
let cTensor = try ORTValue(tensorData: cData, elementType: .float, shape: [2, 1, 64])
|
|
188
|
+
|
|
189
|
+
let outputTensor = try session.run(
|
|
190
|
+
withInputs: ["input": inputTensor, "sr": srTensor, "h": hTensor, "c": cTensor],
|
|
191
|
+
outputNames: ["output", "hn", "cn"],
|
|
192
|
+
runOptions: nil
|
|
193
|
+
)
|
|
194
|
+
guard let outputValue = outputTensor["output"], let hiddenValue = outputTensor["hn"], let cellValue = outputTensor["cn"] else {
|
|
195
|
+
throw NSError(domain: "VadIterator", code: 1, userInfo: nil)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
let outputData = try outputValue.tensorData() as Data
|
|
199
|
+
let probability = outputData.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) -> Float in
|
|
200
|
+
let floatBuffer = buffer.bindMemory(to: Float.self)
|
|
201
|
+
return floatBuffer[0]
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
let hc_shape = (2, 1, 64)
|
|
205
|
+
|
|
206
|
+
let hiddenData = try hiddenValue.tensorData() as Data
|
|
207
|
+
hiddenData.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) in
|
|
208
|
+
let floatBuffer = buffer.bindMemory(to: Float.self)
|
|
209
|
+
for i in 0 ..< hc_shape.0 {
|
|
210
|
+
for j in 0 ..< hc_shape.1 {
|
|
211
|
+
for k in 0 ..< hc_shape.2 {
|
|
212
|
+
hidden[i][j][k] = floatBuffer[i * hc_shape.1 * hc_shape.2 + j * hc_shape.2 + k]
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
let cellData = try cellValue.tensorData() as Data
|
|
219
|
+
cellData.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) in
|
|
220
|
+
let floatBuffer = buffer.bindMemory(to: Float.self)
|
|
221
|
+
for i in 0 ..< hc_shape.0 {
|
|
222
|
+
for j in 0 ..< hc_shape.1 {
|
|
223
|
+
for k in 0 ..< hc_shape.2 {
|
|
224
|
+
cell[i][j][k] = floatBuffer[i * hc_shape.1 * hc_shape.2 + j * hc_shape.2 + k]
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
let isSpeech = probability > threshold
|
|
231
|
+
if isSpeech {
|
|
232
|
+
debugLog("\(timestamp()) prob -> \(probability), true")
|
|
233
|
+
} else {
|
|
234
|
+
debugLog("\(timestamp()) prob -> \(probability)")
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// 缓存结果
|
|
238
|
+
silenceBuffer.append(isSpeech)
|
|
239
|
+
speechBuffer.append(isSpeech)
|
|
240
|
+
// 状态迁移
|
|
241
|
+
switch state {
|
|
242
|
+
case .silence:
|
|
243
|
+
if speechBuffer.isAllSpeech() {
|
|
244
|
+
state = .start
|
|
245
|
+
delegate?.sileroVADDidDetectSpeechStart()
|
|
246
|
+
state = .speeching
|
|
247
|
+
delegate?.sileroVADDidDetectSpeeching()
|
|
248
|
+
}
|
|
249
|
+
case .speeching:
|
|
250
|
+
if silenceBuffer.isAllNotSpeech() {
|
|
251
|
+
state = .end
|
|
252
|
+
delegate?.sileroVADDidDetectSpeechEnd()
|
|
253
|
+
state = .silence
|
|
254
|
+
delegate?.sileroVADDidDetectSilence()
|
|
255
|
+
}
|
|
256
|
+
default:
|
|
257
|
+
break
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
private func timestamp() -> String {
|
|
262
|
+
let date = Date()
|
|
263
|
+
let dateFormatter = DateFormatter()
|
|
264
|
+
dateFormatter.dateFormat = "HH:mm:ss.SSS"
|
|
265
|
+
return dateFormatter.string(from: date)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private func debugLog(_: String) {
|
|
269
|
+
#if DEBUG
|
|
270
|
+
// print("[Silero VAD]: " + content)
|
|
271
|
+
#endif
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
public extension Data {
|
|
276
|
+
/// 针对采样位数为 16 位的情况
|
|
277
|
+
func int16Array() -> [Int16] {
|
|
278
|
+
var array = [Int16](repeating: 0, count: count / MemoryLayout<Int16>.stride)
|
|
279
|
+
_ = array.withUnsafeMutableBytes {
|
|
280
|
+
self.copyBytes(to: $0, from: 0 ..< count)
|
|
281
|
+
}
|
|
282
|
+
return array
|
|
283
|
+
}
|
|
284
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SileroVADStrategy.swift
|
|
3
|
+
// ios-vad
|
|
4
|
+
//
|
|
5
|
+
// Created by baochuquan on 2024/11/10.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
// MARK: - SileroVADStrategy
|
|
11
|
+
|
|
12
|
+
class SileroVADStrategy: VADStrategy {
|
|
13
|
+
private var sileroVAD: SileroVAD?
|
|
14
|
+
private var state: VADState = .silence
|
|
15
|
+
private var handler: ((VADState) -> Void)?
|
|
16
|
+
|
|
17
|
+
func setup(sampleRate: SampleRate, frameSize: FrameSize, quality: VADQuality, silenceTriggerDurationMs: Int64, speechTriggerDurationMs: Int64) {
|
|
18
|
+
sileroVAD = SileroVAD(
|
|
19
|
+
sampleRate: Int64(sampleRate.rawValue),
|
|
20
|
+
sliceSize: Int64(frameSize.rawValue),
|
|
21
|
+
threshold: quality.threshold,
|
|
22
|
+
silenceTriggerDurationMs: silenceTriggerDurationMs,
|
|
23
|
+
speechTriggerDurationMs: speechTriggerDurationMs
|
|
24
|
+
)
|
|
25
|
+
sileroVAD?.delegate = self
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
func checkVAD(pcm: [Int16], handler: @escaping (VADState) -> Void) {
|
|
29
|
+
self.handler = handler
|
|
30
|
+
let data: [Float] = pcm.map { Float($0) / 32768.0 } // normalize
|
|
31
|
+
|
|
32
|
+
do {
|
|
33
|
+
try sileroVAD?.predict(data: data)
|
|
34
|
+
} catch _ {
|
|
35
|
+
fatalError()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
func currentState() -> VADState {
|
|
40
|
+
return state
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
extension SileroVADStrategy: SileroVADDelegate {
|
|
45
|
+
func sileroVADDidDetectSpeechStart() {
|
|
46
|
+
state = .start
|
|
47
|
+
handler?(.start)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
func sileroVADDidDetectSpeechEnd() {
|
|
51
|
+
state = .end
|
|
52
|
+
handler?(.end)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
func sileroVADDidDetectSilence() {
|
|
56
|
+
state = .silence
|
|
57
|
+
handler?(.silence)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
func sileroVADDidDetectSpeeching() {
|
|
61
|
+
state = .speeching
|
|
62
|
+
handler?(.speeching)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#include <bzlib.h>
|