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

> Resolve audio capture problems on macOS Windows and Linux for Meetily. Learn to debug with Rust logging check permissions verify devices and monitor buffers for common issues.

- Repository: [Zackriya Solutions/meetily](https://github.com/Zackriya-Solutions/meetily)
- Tags: how-to-guide
- Published: 2026-07-14

---

**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:

- **macOS** – Uses [`audio/devices/platform/macos.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/audio/devices/platform/macos.rs) with CoreAudio and ScreenCaptureKit APIs.
- **Windows** – Uses [`audio/devices/platform/windows.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/audio/devices/platform/windows.rs) with WASAPI for loopback capture.
- **Linux** – Uses [`audio/devices/platform/linux.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/audio/devices/platform/linux.rs) with ALSA/PulseAudio fallback logic.

## 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`](https://github.com/Zackriya-Solutions/meetily/blob/main/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`](https://github.com/Zackriya-Solutions/meetily/blob/main/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`](https://github.com/Zackriya-Solutions/meetily/blob/main/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:

   ```bash
   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`](https://github.com/Zackriya-Solutions/meetily/blob/main/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`](https://github.com/Zackriya-Solutions/meetily/blob/main/audio/devices/platform/linux.rs) prefers PulseAudio, falling back to ALSA. Run:

   ```bash
   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:

```bash
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:

```javascript
await invoke('refresh_audio_devices');

```

Capture a single chunk to verify microphone levels:

```javascript
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:

```javascript
await invoke('force_flush_and_stop');

```

### Rust Debug Logging

Print ring-buffer status from a debug build:

```rust
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`](https://github.com/Zackriya-Solutions/meetily/blob/main/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`](https://github.com/Zackriya-Solutions/meetily/blob/main/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`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/devices/platform/linux.rs) | ALSA/PulseAudio discovery |
| Device discovery helper | [`frontend/src-tauri/src/audio/devices/discovery.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/devices/discovery.rs) | Cross-platform device listing for UI |
| Ring-buffer & mixing | [`frontend/src-tauri/src/audio/pipeline.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/pipeline.rs) | `AudioMixerRingBuffer`, `ProfessionalAudioMixer`, overflow handling |
| Capture & processing | [`frontend/src-tauri/src/audio/pipeline.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/pipeline.rs) | `AudioCapture` struct, resampling, noise suppression |
| VAD & pipeline flow | [`frontend/src-tauri/src/audio/pipeline.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/pipeline.rs) | `AudioPipeline` impl, `ContinuousVadProcessor` |
| Pipeline management | [`frontend/src-tauri/src/audio/pipeline.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/pipeline.rs) | `AudioPipelineManager`, `force_flush_and_stop` (lines 28-66) |
| Diagnostics utility | [`frontend/src-tauri/src/audio/diagnostics.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/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`](https://github.com/Zackriya-Solutions/meetily/blob/main/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`](https://github.com/Zackriya-Solutions/meetily/blob/main/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')`.