Summary
On Windows, a Realtek HD Audio (UAD) microphone endpoint delivers digital silence (all zeros) to Handy because Handy captures in IEEE float32 (F32). Every other app (Discord, Windows sound test) works because they capture in the native mix format (PCM). No error is raised anywhere — the stream opens and "receives samples", but the buffers are zeros.
Affected macOS? unknown — this is Windows/WASAPI-specific.
Environment
- Windows 11, Handy v0.9.7 (also reproduced on latest main)
- Device: Realtek(R) Audio —
{26dcfe71-da32-496e-9316-98d428f2a969} - Endpoint mix format:
48000 Hz, 32-bit, 2 ch, WAVEFORMATEXTENSIBLE - Preceded by installing and later uninstalling NVIDIA Broadcast (suspected to have left the Realtek capture APO/effects path in a state where float clients get silence).
ConsentStore(per-app mic privacy) values verified — not the cause.
Evidence
Handy log (v0.9.7, both "Default" and explicitly selected mic)
[recorder][INFO] Using device: Ok("Микрофон (Realtek(R) Audio)")
Sample rate: 48000
Channels: 2
Format: F32
... first audio samples arrived ... after stream start (20.0ms drained)
...
VAD at stop: withheld tail ... 0 voiced
Recording stopped and samples retrieved in ..., sample count: 0
Recording produced no audio samples; skipping persistenceSo the capture stream runs, callback fires, ring buffer fills — but every frame is silent → VAD 0 voiced → nothing persisted, level meter dead.
Independent WASAPI shared-mode capture test (C# / NAudio 2.2.1), same device
| client format (shared mode) | result |
|---|---|
| mix format (48000/32-bit/extensible) | signal |
32-bit PCM WAVEFORMATEX 48000/2 | signal |
IEEE float 48000/2 (also with/without AUTOCONVERTPCM) | all zeros, no error |
| IEEE float 44100/2, IEEE float 48000/1 mono | all zeros |
| 16-bit PCM 48000/2 | all zeros |
| exclusive mode (any format) | init error E_INVALIDARG |
Only the exact native mix format and 32-bit PCM delivered real audio; every differing client format initialized successfully but produced pure zeros.
Root cause (hypothesis)
AudioRecorder::get_preferred_config deliberately prioritises sample formats:
// Prioritize F32 > I16 > I32 > others
let score = |fmt: cpal::SampleFormat| match fmt {
cpal::SampleFormat::F32 => 4,
cpal::SampleFormat::I16 => 3,
cpal::SampleFormat::I32 => 2,
_ => 1,
};On WASAPI shared mode the audio engine buffers should contain the mix stream in the client's requested format, but on this driver an IEEE-float client gets an all-zero buffer while a PCM/mix-format client gets real audio. cpal opens F32 without error, logs Format: F32, and Handy then processes silence as if it were speech input.
Suggested fix (upstream)
In get_preferred_config (src-tauri/src/audio_toolkit/audio/recorder.rs), prefer the device's native default_input_config() (the mix format) on Windows/WASAPI instead of hunting for F32 — i.e. stop overriding the mix format selection with the F32 preference. F32 preference (from #393) was added for quality on platforms where it maps to the device's native format; on Windows it can request a client format that Realtek's APO graph does not actually deliver.
At minimum: if the device's default_input_config() sample format differs from the "best" scored format, use the default config on Windows.
Reproduction
mictest — tiny console app (dotnet + NAudio 2.2.1) with the test matrix above:
using System;
using System.Collections.Generic;
using System.Threading;
using NAudio.Wave;
using NAudio.CoreAudioApi;
class Program
{
static double Rms(float[] samples)
{
double sum = 0;
foreach (var s in samples) sum += (double)s * s;
return Math.Sqrt(sum / Math.Max(1, samples.Length));
}
static void CaptureTest(string label, MMDevice device, WaveFormat fmt)
{
Console.WriteLine("TEST: " + label);
var cap = new WasapiCapture(device);
if (fmt != null) cap.WaveFormat = fmt;
var rmsList = new List<double>();
cap.DataAvailable += (s, e) =>
{
var floats = new float[e.BytesRecorded / 4];
Buffer.BlockCopy(e.Buffer, 0, floats, 0, e.BytesRecorded);
rmsList.Add(Rms(floats));
};
cap.StartRecording();
Thread.Sleep(3000);
cap.StopRecording();
while (cap.CaptureState == CaptureState.Capturing) Thread.Sleep(50);
double avg = rmsList.Count > 0 ? 0 : 0;
foreach (var r in rmsList) avg += r;
avg /= Math.Max(1, rmsList.Count);
Console.WriteLine($" blocks={rmsList.Count} avgRMS={avg:F6} => {(avg > 0.002 ? "SIGNAL" : "SILENT/ALL-ZERO")}");
cap.Dispose();
}
static void Main()
{
var enumerator = new MMDeviceEnumerator();
var def = enumerator.GetDefaultAudioEndpoint(DataFlow.Capture, Role.Console);
Console.WriteLine(def.FriendlyName + " mix=" + def.AudioClient.MixFormat);
Console.WriteLine("-- speak into the mic during each window --");
CaptureTest("mix format (works, real audio)", def, null);
CaptureTest("IEEE float 48000/2 (Handy/cpal) => silence", def, WaveFormat.CreateIeeeFloatWaveFormat(48000, 2));
CaptureTest("32-bit PCM 48000/2 (works)", def, new WaveFormat(48000, 32, 2));
}
}Result on the affected machine:
TEST: mix format (works, real audio) => SIGNAL
TEST: IEEE float 48000/2 (Handy/cpal) => SILENT/ALL-ZERO
TEST: 32-bit PCM 48000/2 (works) => SIGNALActivity
3@NikoTiN161 can you try this build and see if it helps
@cjpais This version also doesn’t work. Sorry, I probably didn’t do enough tests with my agent. In general, enabling effects and Voice Clarity breaks my microphone. Even the test recording in Windows stops working, although the recording bar moves. But other apps like Discord or the browser work with any settings. The agent said it’s due to different capture technologies — Discord has a more modern stack.
Reported workaround from the affected user, confirming the root-cause hypothesis:
So it is the device effects (Realtek APO: Voice clarity et al.) that zero out capture for float32/shared-mode clients while PCM/mix-format clients are unaffected. Worth reflecting in the fix: on Windows, either use the native mix format / default config, or advise disabling device effects.