Recursive AI

Voice activity detection in C#

OneSpeech is a free, open-source speech recognition library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies.

Voice activity detection finds speech intervals, not words; input must be mono 8 or 16 kHz PCM. The Silero VAD model is embedded in the package.

Terminal
dotnet add package RecursiveAI.OneSpeech

OneAudio is a dependency of RecursiveAI.OneSpeech; no separate install is needed.

Requires .NET 10 (net10.0); .NET 9 and earlier aren’t supported.

sample.flac is in the zip.

C#
using OneSpeech;
using OneSpeech.Vad;
var clip = OneAudio.Audio.Load("sample.flac",
    new OneAudio.LoadOptions { SampleRate = 16000, Channels = 1 });
using var vad = new SileroVad();
foreach (var interval in vad.Detect(new AudioBuffer(clip.Samples, 16000)))
    Console.WriteLine($"{interval.Start.TotalSeconds:F3}–{interval.End.TotalSeconds:F3}");

Unzip the example, then dotnet run.

Prints:

Text
0.546–2.910

sample.flac is the LibriSpeech test-clean clip 1089-134686-0001: “stuff it into you his belly counselled him”. It is included under CC BY 4.0, credited to Vassil Panayotov, Guoguo Chen, Daniel Povey and Sanjeev Khudanpur (source). The loader converts it to mono 16 kHz PCM. The VAD model is embedded in the package; this example needs no model download.

Detect throws ArgumentException for stereo PCM or a sample rate other than 8,000 or 16,000 Hz.

Variations

Remove the padding around detected speech. Replace the detector construction with:

C#
using var vad = new SileroVad(new SileroVadOptions
{
    SpeechPadding = TimeSpan.Zero
});
Text
0.576–2.880

The short answer

To perform voice activity detection in C#, decode audio to mono PCM at 8 kHz or 16 kHz, create SileroVad, and call Detect. The returned intervals describe speech positions on the original audio clock. They do not contain recognized text or identify speakers.

The complete example loads a real recording, resamples it to the detector’s input format, and prints each interval in seconds. Use those positions to decide which parts of a file to send to another stage. Nothing in this example edits the audio or removes silence.

How do I use Silero VAD in C#?

The package embeds the pinned Silero VAD model, so constructing the detector does not fetch speech-recognition weights. Dispose the detector after processing. Each Detect call starts with fresh recurrent state; you can process independent recordings without carrying state from the previous one.

Audio format matters. Passing stereo samples with a mono label is not downmixing. The example requests one channel and a 16,000 Hz sample rate from the audio loader, then constructs an AudioBuffer with that rate. If you already have normalized mono PCM at a supported rate, pass it directly rather than encoding a temporary WAV file.

The implementation processes 32 ms frames. It zero-pads a final short frame for inference but clips reported intervals to the actual recording duration. Empty input returns no intervals. These details, including the embedded checkpoint and attribution, are documented in Silero voice activity detection.

How do I configure a voice activity detection model?

Use SileroVadOptions when constructing the detector. The default activation probability is 0.5 and the default deactivation probability is 0.35. Separate thresholds prevent a single borderline frame from repeatedly opening and closing speech. A pending silence interval closes speech only after the configured silence duration is reached.

The defaults retain speech strictly longer than 250 ms, require 100 ms of silence to close an interval, and add 30 ms of padding. Padding is clipped at the recording boundaries. When adjacent padding would overlap, the intervening gap is shared. The variation removes padding but does not change the underlying speech decisions.

Choose options using representative recordings: a detector configured for long utterances may omit a short response, while looser settings may retain unwanted sounds. Interval boundaries are model decisions, not word boundaries or proof of a particular sound’s content. If you need uninterrupted frame-level recurrence, CreateState exposes it separately. A state is not thread-safe, must be reset for a new recording, and must not outlive its detector.

VAD is also distinct from diarization. One interval can contain several voices, including simultaneous voices. For who-spoke-when output, use a diarizer; for actual words, add a recognizer. Neither result follows from VAD alone.

All onespeech recipes