How to Debug Audio Capture Issues on macOS, Windows, and Linux for Meetily

To debug audio capture issues in Meetily, enable Rust debug logging, check platform-specific device permissions, verify virtual audio devices are recognized, and monitor the AudioMixerRingBuffer for overflow warnings that indicate sample-rate mismatches or jitter.

Meetily captures two audio streams—microphone input and system audio output—through a Rust-based Tauri core located in frontend/src-tauri/src/audio/. Understanding how to debug audio capture issues on macOS, Windows, and Linux for Meetily requires familiarity with the platform-specific device enumeration modules and the unified mixing pipeline that processes both streams before Whisper transcription.

Understanding Meetily’s Audio Architecture

The capture pipeline routes audio from device-specific backends through a series of processing stages before reaching the transcription engine.

Core Processing Components

  • AudioCapture – Handles device-specific capture, mono conversion, optional resampling, noise suppression, high-pass filtering, and EBU-R128 loudness normalization (microphone only).
  • AudioMixerRingBuffer – Maintains separate FIFO buffers for mic and system audio, aligns them into 50 ms windows, and emits warnings on overflow.
  • ProfessionalAudioMixer – Performs soft-clipping mixing that scales the system stream to approximately 70% to prevent hard clipping.
  • AudioPipeline – Receives mixed windows, runs the voice-activity detector (VAD), forwards speech segments to Whisper, and streams mixed audio to the WAV recorder.

Platform-Specific Backends

While the mixing logic remains cross-platform, device discovery differs by operating system:

Common Audio Capture Failure Modes

Recognizing symptom patterns helps isolate whether the issue stems from permissions, device enumeration, or signal processing.

Symptom Likely Cause Investigation Location
No microphone data – silent transcript Permission denied, wrong input device, or device not found AudioCapture.handle_stream_error and device list in audio/devices/discovery.rs
System audio missing – only mic heard Virtual audio device not installed or filtered out by should_include_output_device audio/devices/platform/macos.rs (device filtering logic)
Audio garbled or speed-up Sample-rate mismatch on Bluetooth or low-rate devices AudioCapture.needs_resampling and persistent resampler in pipeline.rs
Choppy or distorted mix Ring-buffer overflow or jitter on system stream AudioMixerRingBuffer.add_samples warnings and max_buffer_size calculations
Transcription never fires VAD not detecting speech due to high redemption time or wrong sample-rate AudioPipeline::run and ContinuousVadProcessor::new initialization

Platform-Specific Debugging Steps

macOS

  1. Verify permissions – Both Microphone and Screen Recording permissions must be granted in System Settings. Errors surface in AudioCapture.handle_stream_error as PermissionDenied.

  2. Check virtual audio devices – System capture requires a virtual loopback device such as BlackHole. The macOS device filter in should_include_output_device excludes names containing "speakers" but should list BlackHole.

  3. Monitor ring-buffer health – Run with debug logging enabled:

    RUST_LOG=app_lib::audio=debug ./clean_run.sh

    Look for buffer status messages:

    
    📊 Ring buffer status: mic=1234 samples, sys=5678 samples (max=9600)
    ⚠️ Microphone buffer overflow …
    

    Frequent overflow indicates jitter; increase max_buffer_size in AudioMixerRingBuffer::new or check CPU load.

  4. Inspect resampling – Bluetooth headsets often report 16 kHz. If you see:

    
    ⚠️ SAMPLE RATE MISMATCH DETECTED …
    

    The persistent resampler in AudioCapture will convert to 48 kHz. Absence of this warning suggests the device already reports the correct rate.

Windows

  1. Enumerate devices – Open the Audio → Device panel in the UI. The list is built by audio/devices/platform/windows.rs. Missing devices indicate WASAPI subsystem issues, often driver-related.

  2. Configure loopback capture – System audio uses WASAPI loopback. Ensure the output device is not a "speakers" entry filtered by the same exclusion logic used on macOS.

  3. Address latency – Windows exclusive mode can introduce high latency. Reduce logging verbosity and watch for buffer overflow warnings identical to the macOS debugging procedure.

Linux

  1. Verify PulseAudio/ALSA – Device discovery in audio/devices/platform/linux.rs prefers PulseAudio, falling back to ALSA. Run:

    pactl list short sources
    pactl list short sinks

    Ensure expected devices appear in the output.

  2. Check user permissions – The binary must run as a user in the audio group. Running with sudo is only recommended for testing; otherwise, expect PermissionDenied errors in logs.

  3. Manage jitter – Linux system capture often exhibits larger jitter, triggering ring-buffer overflow warnings more frequently. Temporarily raise window_ms in AudioMixerRingBuffer::new (line 28) to 100 ms for debugging purposes.

Diagnostic Commands and Tools

Environment Variable Diagnostics

Enable periodic buffer health reporting:

export MEETILY_AUDIO_DIAGNOSTICS=1
RUST_LOG=debug ./clean_run.sh

Expected output:


🔊 Diagnostics: mic_buffer=3420, sys_buffer=4000, sample_rate=48000

These values confirm whether buffers stay within the configured max_buffer_size (approximately 400 ms).

Tauri Frontend Commands

Trigger device refresh from the developer console:

await invoke('refresh_audio_devices');

Capture a single chunk to verify microphone levels:

let chunk = await invoke('capture_one_chunk', { device_type: 'Microphone' });
let rms = Math.sqrt(chunk.data.reduce((s, x) => s + x*x, 0) / chunk.data.length);
console.log('Microphone RMS:', rms);

Force flush a hung pipeline:

await invoke('force_flush_and_stop');

Rust Debug Logging

Print ring-buffer status from a debug build:

debug!("Ring buffer status: mic={} sys={}", self.mic_buffer.len(), self.system_buffer.len());

Key Source Files for Debugging

Component File Path Purpose
Device enumeration (macOS) frontend/src-tauri/src/audio/devices/platform/macos.rs Lists input/output devices, filters built-in speakers
Device enumeration (Windows) frontend/src-tauri/src/audio/devices/platform/windows.rs WASAPI implementation and loopback capture
Device enumeration (Linux) frontend/src-tauri/src/audio/devices/platform/linux.rs ALSA/PulseAudio discovery
Device discovery helper frontend/src-tauri/src/audio/devices/discovery.rs Cross-platform device listing for UI
Ring-buffer & mixing frontend/src-tauri/src/audio/pipeline.rs AudioMixerRingBuffer, ProfessionalAudioMixer, overflow handling
Capture & processing frontend/src-tauri/src/audio/pipeline.rs AudioCapture struct, resampling, noise suppression
VAD & pipeline flow frontend/src-tauri/src/audio/pipeline.rs AudioPipeline impl, ContinuousVadProcessor
Pipeline management frontend/src-tauri/src/audio/pipeline.rs AudioPipelineManager, force_flush_and_stop (lines 28-66)
Diagnostics utility frontend/src-tauri/src/audio/diagnostics.rs Optional periodic logging of buffer health

Summary

  • Enable debug logging with RUST_LOG=app_lib::audio=debug to expose buffer overflows, permission errors, and sample-rate mismatches.
  • Verify platform permissions: macOS requires Screen Recording and Microphone access; Linux requires membership in the audio group; Windows requires functional WASAPI drivers.
  • Check virtual devices on macOS (BlackHole) and ensure system audio devices aren't filtered by should_include_output_device.
  • Monitor AudioMixerRingBuffer for overflow warnings that indicate jitter or mismatched sample rates between microphone and system streams.
  • Use force flush (force_flush_and_stop) to recover from pipeline hangs without restarting the application.

Frequently Asked Questions

Why is my microphone working but system audio is missing?

Missing system audio usually indicates the virtual loopback device is not installed or has been filtered out. On macOS, verify BlackHole is installed and appears in the device list; the macOS implementation in audio/devices/platform/macos.rs filters out devices with "speakers" in the name, so BlackHole must be explicitly selected. On Windows, ensure the WASAPI loopback device is not disabled, and on Linux, verify the PulseAudio monitor source exists with pactl list.

How do I fix choppy or distorted audio in Meetily?

Choppy audio typically results from AudioMixerRingBuffer overflow, visible in logs as warnings from add_samples. This occurs when the system audio stream jitters or when CPU load prevents timely processing. Increase max_buffer_size in AudioMixerRingBuffer::new or reduce the redemption time in ContinuousVadProcessor::new to decrease latency.

What causes the "SAMPLE RATE MISMATCH" warning?

This warning appears in AudioCapture when a device reports a sample rate other than 48 kHz, such as 16 kHz Bluetooth headsets. The persistent resampler in pipeline.rs automatically converts the stream, but the warning confirms the conversion is active. If the warning is absent despite using a Bluetooth device, the device may be inadvertently reporting 48 kHz through system interpolation.

How do I force stop the audio pipeline if the app hangs?

If the application hangs during shutdown, the pipeline is likely waiting for a flush signal. Trigger the Tauri command force_flush_and_stop, which sends three special AudioChunk structures with chunk_id = u64::MAX to force the AudioPipeline to terminate immediately. This command is available via the UI "Force stop" button or programmatically through await invoke('force_flush_and_stop').

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →