@mentra/bluetooth-sdk 0.1.5 → 0.1.7
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 +45 -27
- package/android/build.gradle +2 -9
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +53 -36
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +22 -9
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +25 -36
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +9 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +68 -56
- package/android/src/main/java/com/mentra/bluetoothsdk/audio/AudioModels.kt +125 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +209 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/connection/ConnectionModels.kt +78 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +4 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +2 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/events/BluetoothEvents.kt +72 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/internal/MapParsing.kt +132 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/requests/DisplayRequests.kt +39 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +2 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +168 -10
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +7 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +3 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +607 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/status/RuntimeState.kt +201 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/status/WifiHotspotStatus.kt +173 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamModels.kt +348 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +1 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/types/DeviceModels.kt +75 -0
- package/build/BluetoothSdk.types.d.ts +46 -20
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js +1 -0
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_private/BluetoothSdkModule.d.ts +6 -5
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
- package/build/_private/BluetoothSdkModule.js +40 -5
- package/build/_private/BluetoothSdkModule.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -2
- package/build/index.js.map +1 -1
- package/build/react/useMentraBluetooth.d.ts +5 -3
- package/build/react/useMentraBluetooth.d.ts.map +1 -1
- package/build/react/useMentraBluetooth.js +15 -4
- package/build/react/useMentraBluetooth.js.map +1 -1
- package/ios/BluetoothSdkModule.swift +45 -28
- package/ios/MentraBluetoothSDK.podspec +0 -3
- package/ios/Source/Audio/AudioModels.swift +159 -0
- package/ios/Source/Bridge.swift +22 -11
- package/ios/Source/Camera/CameraModels.swift +248 -0
- package/ios/Source/Connection/ScanSession.swift +27 -0
- package/ios/Source/DeviceManager.swift +20 -97
- package/ios/Source/DeviceStore.swift +13 -4
- package/ios/Source/Errors/BluetoothError.swift +19 -0
- package/ios/Source/Events/BluetoothEvents.swift +149 -0
- package/ios/Source/Internal/BluetoothAvailability.swift +58 -0
- package/ios/Source/Internal/ValueParsing.swift +90 -0
- package/ios/Source/MentraBluetoothSDK.swift +50 -2150
- package/ios/Source/Requests/DisplayRequests.swift +58 -0
- package/ios/Source/Status/DeviceStatus.swift +471 -0
- package/ios/Source/Status/RuntimeState.swift +359 -0
- package/ios/Source/Status/WifiHotspotStatus.swift +326 -0
- package/ios/Source/Streaming/StreamModels.swift +436 -0
- package/ios/Source/Types/DeviceModels.swift +134 -0
- package/ios/Source/controllers/ControllerManager.swift +3 -3
- package/ios/Source/controllers/R1.swift +1 -1
- package/ios/Source/sgcs/G1.swift +1 -1
- package/ios/Source/sgcs/G2.swift +99 -39
- package/ios/Source/sgcs/Mach1.swift +1 -1
- package/ios/Source/sgcs/MentraLive.swift +109 -12
- package/ios/Source/sgcs/MentraNex.swift +1 -1
- package/ios/Source/sgcs/SGCManager.swift +11 -3
- package/ios/Source/sgcs/Simulated.swift +2 -2
- package/ios/Source/stt/SherpaOnnxTranscriber.swift +1 -4
- package/package.json +1 -1
- package/src/BluetoothSdk.types.ts +48 -28
- package/src/_private/BluetoothSdkModule.ts +47 -21
- package/src/index.ts +6 -4
- package/src/react/useMentraBluetooth.ts +19 -7
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +0 -1810
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/VadGateSpeechPolicy.kt +0 -221
- package/ios/Packages/VAD/Common/VAD/VADQuality.swift +0 -41
- package/ios/Packages/VAD/Common/VAD/VADState.swift +0 -26
- package/ios/Packages/VAD/Common/VAD/VADStrategy.swift +0 -29
- package/ios/Packages/VAD/Common/VAD/VADType.swift +0 -14
- package/ios/Packages/VAD/Data/Configuration.swift +0 -68
- package/ios/Packages/VAD/Data/FrameSize.swift +0 -39
- package/ios/Packages/VAD/Data/Record.swift +0 -13
- package/ios/Packages/VAD/Data/Result.swift +0 -22
- package/ios/Packages/VAD/Data/SampleRate.swift +0 -48
- package/ios/Packages/VAD/Silero/Model/silero_vad.onnx +0 -0
- package/ios/Packages/VAD/Silero/SileroVAD.swift +0 -284
- package/ios/Packages/VAD/Silero/SileroVADStrategy.swift +0 -64
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
package com.mentra.bluetoothsdk.stt
|
|
2
|
-
|
|
3
|
-
import android.content.Context
|
|
4
|
-
import android.util.Log
|
|
5
|
-
import com.konovalov.vad.silero.Vad
|
|
6
|
-
import com.konovalov.vad.silero.VadSilero
|
|
7
|
-
import com.konovalov.vad.silero.config.FrameSize
|
|
8
|
-
import com.konovalov.vad.silero.config.Mode
|
|
9
|
-
import com.konovalov.vad.silero.config.SampleRate
|
|
10
|
-
import java.nio.ByteBuffer
|
|
11
|
-
import java.nio.ByteOrder
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* VadGateSpeechPolicy handles Voice Activity Detection using Silero VAD.
|
|
15
|
-
*
|
|
16
|
-
* Features:
|
|
17
|
-
* - Dynamic VAD check throttling (adjusts frequency based on silence duration)
|
|
18
|
-
* - 8-second silence timeout before declaring "not speaking"
|
|
19
|
-
* - Bypass modes for debugging and PCM streaming
|
|
20
|
-
* - 512-sample frame size (matches Sherpa-ONNX requirements)
|
|
21
|
-
*
|
|
22
|
-
* Ported from android_core VadGateSpeechPolicy.java
|
|
23
|
-
*/
|
|
24
|
-
class VadGateSpeechPolicy(private val context: Context) {
|
|
25
|
-
companion object {
|
|
26
|
-
private const val TAG = "VadGateSpeechPolicy"
|
|
27
|
-
|
|
28
|
-
// Total required silence duration
|
|
29
|
-
private const val REQUIRED_SILENCE_DURATION_MS = 8000L
|
|
30
|
-
|
|
31
|
-
// Dynamic VAD check intervals
|
|
32
|
-
private const val INITIAL_SILENCE_VAD_INTERVAL_MS = 50L // Check frequently at first
|
|
33
|
-
private const val MEDIUM_SILENCE_VAD_INTERVAL_MS = 100L // Medium frequency after some time
|
|
34
|
-
private const val LONG_SILENCE_VAD_INTERVAL_MS =
|
|
35
|
-
200L // Less frequent after extended silence
|
|
36
|
-
|
|
37
|
-
// Thresholds for switching intervals
|
|
38
|
-
private const val MEDIUM_SILENCE_THRESHOLD_MS =
|
|
39
|
-
20000L // Switch to medium interval after 20s
|
|
40
|
-
private const val LONG_SILENCE_THRESHOLD_MS = 60000L // Switch to long interval after 60s
|
|
41
|
-
|
|
42
|
-
private const val FRAME_SIZE = 512
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
private var vad: VadSilero? = null
|
|
46
|
-
private var isCurrentlySpeech = false
|
|
47
|
-
private var bypassVadForDebugging = false
|
|
48
|
-
private var bypassVadForPCM = false
|
|
49
|
-
|
|
50
|
-
// Timestamp of the last detected speech
|
|
51
|
-
private var lastSpeechDetectedTime = 0L
|
|
52
|
-
// Throttle timer for silence VAD checks
|
|
53
|
-
private var lastVadCheckTime = 0L
|
|
54
|
-
|
|
55
|
-
/** Initialize the Silero VAD model */
|
|
56
|
-
fun init(blockSizeSamples: Int) {
|
|
57
|
-
startVad()
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
private fun startVad() {
|
|
61
|
-
try {
|
|
62
|
-
// Set internal silence duration very low; external logic manages the full required
|
|
63
|
-
// silence duration
|
|
64
|
-
vad =
|
|
65
|
-
Vad.builder()
|
|
66
|
-
.setContext(context)
|
|
67
|
-
.setSampleRate(SampleRate.SAMPLE_RATE_16K)
|
|
68
|
-
.setFrameSize(FrameSize.FRAME_SIZE_512)
|
|
69
|
-
.setMode(Mode.NORMAL)
|
|
70
|
-
.setSilenceDurationMs(50)
|
|
71
|
-
.setSpeechDurationMs(50)
|
|
72
|
-
.build()
|
|
73
|
-
|
|
74
|
-
Log.d(TAG, "VAD initialized successfully")
|
|
75
|
-
} catch (e: Exception) {
|
|
76
|
-
Log.e(TAG, "Failed to initialize VAD", e)
|
|
77
|
-
vad = null
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** Check if audio should be passed to the recognizer based on VAD state */
|
|
82
|
-
fun shouldPassAudioToRecognizer(): Boolean {
|
|
83
|
-
// CRITICAL: Handle VAD null case
|
|
84
|
-
if (vad == null) {
|
|
85
|
-
return bypassVadForDebugging || bypassVadForPCM || true
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return bypassVadForDebugging || bypassVadForPCM || isCurrentlySpeech
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/** Process audio bytes through VAD to detect speech */
|
|
92
|
-
fun processAudioBytes(bytes: ByteArray, offset: Int, length: Int) {
|
|
93
|
-
val now = System.currentTimeMillis()
|
|
94
|
-
|
|
95
|
-
// If in speech state and it hasn't been 8 seconds since the last speech was detected, skip
|
|
96
|
-
// processing
|
|
97
|
-
if (isCurrentlySpeech && (now - lastSpeechDetectedTime < REQUIRED_SILENCE_DURATION_MS)) {
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Calculate silence duration
|
|
102
|
-
val silenceDuration = now - lastSpeechDetectedTime
|
|
103
|
-
|
|
104
|
-
// Determine which VAD interval to use based on silence duration
|
|
105
|
-
val currentVadInterval =
|
|
106
|
-
when {
|
|
107
|
-
silenceDuration < MEDIUM_SILENCE_THRESHOLD_MS -> INITIAL_SILENCE_VAD_INTERVAL_MS
|
|
108
|
-
silenceDuration < LONG_SILENCE_THRESHOLD_MS -> MEDIUM_SILENCE_VAD_INTERVAL_MS
|
|
109
|
-
else -> LONG_SILENCE_VAD_INTERVAL_MS
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// During silence, throttle VAD checks based on the dynamic interval
|
|
113
|
-
if (!isCurrentlySpeech && (now - lastVadCheckTime < currentVadInterval)) {
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
lastVadCheckTime = now
|
|
117
|
-
|
|
118
|
-
val audioBytesFull = bytesToShort(bytes)
|
|
119
|
-
val totalSamples = audioBytesFull.size
|
|
120
|
-
|
|
121
|
-
if (totalSamples % FRAME_SIZE != 0) {
|
|
122
|
-
Log.e(
|
|
123
|
-
TAG,
|
|
124
|
-
"Invalid audio frame size: $totalSamples samples. Needs to be multiple of $FRAME_SIZE."
|
|
125
|
-
)
|
|
126
|
-
return
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
val currentVad =
|
|
130
|
-
vad
|
|
131
|
-
?: run {
|
|
132
|
-
Log.w(TAG, "VAD not initialized, skipping audio processing")
|
|
133
|
-
return
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
var previousSpeechState = isCurrentlySpeech
|
|
137
|
-
|
|
138
|
-
// Process each 512-sample frame
|
|
139
|
-
val numFrames = totalSamples / FRAME_SIZE
|
|
140
|
-
for (i in 0 until numFrames) {
|
|
141
|
-
val currentTime = System.currentTimeMillis()
|
|
142
|
-
val startIdx = i * FRAME_SIZE
|
|
143
|
-
val audioFrame = audioBytesFull.copyOfRange(startIdx, startIdx + FRAME_SIZE)
|
|
144
|
-
val detectedSpeech = currentVad.isSpeech(audioFrame)
|
|
145
|
-
|
|
146
|
-
if (detectedSpeech) {
|
|
147
|
-
isCurrentlySpeech = true
|
|
148
|
-
// Update the last speech detection timestamp
|
|
149
|
-
lastSpeechDetectedTime = currentTime
|
|
150
|
-
} else {
|
|
151
|
-
// If no speech detected, and 8 seconds have elapsed since the last speech, mark as
|
|
152
|
-
// silence
|
|
153
|
-
if (currentTime - lastSpeechDetectedTime >= REQUIRED_SILENCE_DURATION_MS) {
|
|
154
|
-
isCurrentlySpeech = false
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (isCurrentlySpeech != previousSpeechState) {
|
|
159
|
-
Log.d(
|
|
160
|
-
TAG,
|
|
161
|
-
"Speech detection changed to: ${if (isCurrentlySpeech) "SPEECH" else "SILENCE"}"
|
|
162
|
-
)
|
|
163
|
-
previousSpeechState = isCurrentlySpeech
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/** Convert byte array (PCM16LE) to short array */
|
|
169
|
-
private fun bytesToShort(bytes: ByteArray): ShortArray {
|
|
170
|
-
val shorts = ShortArray(bytes.size / 2)
|
|
171
|
-
ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts)
|
|
172
|
-
return shorts
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/** Stop VAD and release resources */
|
|
176
|
-
fun stop() {
|
|
177
|
-
try {
|
|
178
|
-
vad?.close()
|
|
179
|
-
vad = null
|
|
180
|
-
Log.d(TAG, "VAD stopped and resources released")
|
|
181
|
-
} catch (e: Exception) {
|
|
182
|
-
Log.e(TAG, "Error stopping VAD", e)
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/** Reset VAD state */
|
|
187
|
-
fun reset() {
|
|
188
|
-
isCurrentlySpeech = false
|
|
189
|
-
lastSpeechDetectedTime = 0
|
|
190
|
-
lastVadCheckTime = 0
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/** Change bypass VAD for debugging state */
|
|
194
|
-
fun changeBypassVadForDebugging(bypass: Boolean) {
|
|
195
|
-
bypassVadForDebugging = bypass
|
|
196
|
-
Log.d(TAG, "Bypass VAD for debugging: $bypass")
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/** Change bypass VAD for PCM streaming state */
|
|
200
|
-
fun changeBypassVadForPCM(bypass: Boolean) {
|
|
201
|
-
Log.d(TAG, "VAD PCM Bypass State Change: $bypassVadForPCM -> $bypass")
|
|
202
|
-
bypassVadForPCM = bypass
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/** Handle microphone state changes */
|
|
206
|
-
fun microphoneStateChanged(state: Boolean) {
|
|
207
|
-
if (!state) {
|
|
208
|
-
// Microphone turned off: force immediate silence
|
|
209
|
-
isCurrentlySpeech = false
|
|
210
|
-
lastSpeechDetectedTime = 0
|
|
211
|
-
lastVadCheckTime = 0
|
|
212
|
-
|
|
213
|
-
// Optionally flush the VAD's internal state by processing a silent frame
|
|
214
|
-
vad?.let { vadInstance ->
|
|
215
|
-
val silentFrame = ShortArray(FRAME_SIZE)
|
|
216
|
-
vadInstance.isSpeech(silentFrame)
|
|
217
|
-
}
|
|
218
|
-
Log.d(TAG, "Microphone turned off; forced state to SILENCE.")
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
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
|