package com.sherpaonnxofflinestt /** * TEN-VAD: Voice Activity Detection wrapper * * Ultra-low latency ML-based speech detection with 10ms frame processing. */ class TenVad( private val hopSize: Int = 160, // 10ms at 16kHz private val threshold: Float = 0.5f ) { private var handle: Long = 0 init { System.loadLibrary("ten_vad_jni") handle = nativeCreate(hopSize, threshold) if (handle == 0L) { throw RuntimeException("Failed to create TEN-VAD instance") } } /** * Process audio samples through VAD * * @param samples Audio samples (int16, 16kHz, mono). Length must equal hopSize. * @return Pair of (probability: Float, isSpeech: Boolean) or null on error */ fun process(samples: ShortArray): VadResult? { if (handle == 0L) return null if (samples.size != hopSize) { throw IllegalArgumentException("Audio samples length (${samples.size}) must equal hopSize ($hopSize)") } val result = nativeProcess(handle, samples) ?: return null return VadResult( probability = result[0], isSpeech = result[1] > 0.5f ) } /** * Release resources */ fun destroy() { if (handle != 0L) { nativeDestroy(handle) handle = 0 } } /** * Get TEN-VAD version */ fun getVersion(): String = nativeGetVersion() /** * Check if VAD is initialized */ fun isInitialized(): Boolean = handle != 0L // Native methods private external fun nativeCreate(hopSize: Int, threshold: Float): Long private external fun nativeProcess(handle: Long, audioData: ShortArray): FloatArray? private external fun nativeDestroy(handle: Long) private external fun nativeGetVersion(): String companion object { const val SAMPLE_RATE = 16000 const val DEFAULT_HOP_SIZE = 160 // 10ms at 16kHz const val DEFAULT_THRESHOLD = 0.5f } } /** * VAD processing result */ data class VadResult( val probability: Float, val isSpeech: Boolean )