# How Meetily's Audio Level Monitoring Provides Real-Time Feedback During Recording

> Discover how Meetily's audio level monitoring delivers real-time feedback for better recordings. Learn about its use of CPAL, RMS/peak calculations, and Tauri event bus for live meters.

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

---

**Meetily captures audio samples from input devices using CPAL, calculates RMS and peak levels every 100ms, and pushes updates to the React frontend via Tauri's `audio-levels` event bus to render live meters.**

Meetily is an open-source meeting recording application built with Tauri (Rust) and React. Its **audio level monitoring** system bridges the native audio layer with the UI, providing visual feedback during recording sessions by translating raw audio samples into device-specific level data.

## Architecture of the Audio Level Pipeline

The monitoring system follows a six-stage pipeline that moves data from the hardware audio interface to the React component tree. This architecture ensures low-latency updates while maintaining thread safety across the Rust-JavaScript boundary.

### Stage 1: Initiating Monitoring via Tauri Command

The process begins when the React frontend invokes the **`start_audio_level_monitoring`** command defined in [`frontend/src-tauri/src/lib.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/lib.rs). This command accepts a vector of device names and forwards the request to the monitoring implementation.

```rust
#[tauri::command]
async fn start_audio_level_monitoring<R: Runtime>(
    app: AppHandle<R>,
    device_names: Vec<String>,
) -> Result<(), String> {
    audio::simple_level_monitor::start_monitoring(app, device_names)
        .await
        .map_err(|e| format!("Failed to start audio level monitoring: {}", e))
}

```

### Stage 2: Capturing Audio with CPAL

Inside [`frontend/src-tauri/src/audio/level_monitor.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/level_monitor.rs), the system uses **CPAL** (Cross-Platform Audio Library) to discover and open streams for each requested input device. For every device, a CPAL stream is created with a callback that receives raw audio samples.

Before processing, the **`audio_to_mono`** helper function from [`frontend/src-tauri/src/audio/audio_processing.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/audio_processing.rs) flattens multi-channel audio into mono. This ensures consistent level calculations regardless of whether the source is mono, stereo, or multi-channel.

### Stage 3: Calculating RMS and Peak Levels

The stream callback processes samples through **`process_audio_levels`** to compute two key metrics:

- **RMS (Root-Mean-Square)**: The effective average level of the audio signal
- **Peak**: The maximum amplitude value in the sample window

The system also sets an **`is_active`** flag when RMS exceeds `0.001`, filtering out background noise.

### Stage 4: Aggregating State and Scheduling Emission

Processed data flows into a shared `Arc<Mutex<Vec<AudioLevelData>>>` that collects updates from all active streams. A background task running on a 100ms interval reads this vector, clears it, and packages the data into an `AudioLevelUpdate` struct containing a Unix-epoch timestamp and the level vector.

### Stage 5: Emitting Events to the Frontend

The aggregated update is emitted via Tauri's event bus using `app_handle.emit("audio-levels", &update)`. This occurs in [`frontend/src-tauri/src/audio/level_monitor.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/level_monitor.rs):

```rust
let update = AudioLevelUpdate {
    timestamp: SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_millis() as u64,
    levels,
};

if let Err(e) = app_handle_clone.emit("audio-levels", &update) {
    error!("Failed to emit audio levels: {}", e);
}

```

### Stage 6: Consuming Updates in the React UI

In [`frontend/src/components/DeviceSelection.tsx`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src/components/DeviceSelection.tsx), the React component registers a listener for the `audio-levels` event using Tauri's `listen` API:

```tsx
import { listen } from '@tauri-apps/api/event';
import type { AudioLevelUpdate, AudioLevelData } from '@/types';

const [audioLevels, setAudioLevels] = useState<Map<string, AudioLevelData>>(new Map());

useEffect(() => {
  let unlisten: (() => void) | undefined;

  const setup = async () => {
    unlisten = await listen<AudioLevelUpdate>('audio-levels', event => {
      const map = new Map<string, AudioLevelData>();
      event.payload.levels.forEach(l => map.set(l.device_name, l));
      setAudioLevels(map);
    });
  };
  setup();

  return () => unlisten?.();
}, []);

```

The component converts the payload array into a `Map<string, AudioLevelData>` keyed by device name, enabling O(1) access when rendering individual meter components.

## Thread Safety and State Management

The implementation uses several concurrency primitives to ensure safe operation:

- **`Arc<Mutex<...>>`**: Device names and CPAL streams reside inside thread-safe containers, allowing the async background task to read and write while the main Tauri thread handles commands.
- **`AtomicBool`**: The `AUDIO_LEVEL_STATE.is_monitoring` flag enables fast start/stop control without race conditions.
- **100ms Tick**: The fixed emission interval balances real-time responsiveness with CPU usage, preventing event flooding that could overwhelm the frontend.

## Development Fallback with Synthetic Data

For scenarios where full audio hardware access isn't available (e.g., development or CI environments), [`frontend/src-tauri/src/audio/simple_level_monitor.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/simple_level_monitor.rs) provides a simplified implementation. This module generates synthetic level data on the same 100ms schedule and emits identical `audio-levels` events, ensuring the UI logic remains testable without actual audio hardware.

## Frontend Integration Example

To start monitoring from the TypeScript frontend:

```typescript
// Invoke the Tauri command with chosen device names
await invoke('start_audio_level_monitoring', {
  device_names: ['Built-in Microphone', 'BlackHole 2ch']
});

```

The `audioLevels` state map can then drive visual components:

```tsx
{audioLevels.get('Built-in Microphone')?.is_active && (
  <div className="recording-indicator">Recording</div>
)}

```

## Summary

- Meetily's **audio level monitoring** uses CPAL to capture raw samples from selected input devices.
- The Rust backend in [`level_monitor.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/level_monitor.rs) calculates **RMS** and **peak** levels every 100ms.
- Updates flow through Tauri's **`audio-levels`** event bus to the React frontend.
- The **DeviceSelection** component maintains a `Map` of device levels in state for efficient rendering.
- Thread-safe state management using `Arc<Mutex<...>>` and `AtomicBool` prevents race conditions.
- A **synthetic monitor** in [`simple_level_monitor.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/simple_level_monitor.rs) supports development without hardware.

## Frequently Asked Questions

### How does Meetily calculate audio levels from raw samples?

The system computes **RMS** (root-mean-square) for effective average loudness and tracks **peak** amplitude for maximum values. Both metrics are calculated after converting multi-channel audio to mono using the `audio_to_mono` helper, ensuring consistent readings across different device configurations.

### What is the latency between audio input and UI updates?

The pipeline delivers updates every **100ms** via Tauri's event bus. This interval provides near real-time visual feedback while preventing excessive CPU usage or frontend re-renders that could impact performance during recording sessions.

### Can the audio level monitoring run without actual hardware?

Yes. The repository includes [`frontend/src-tauri/src/audio/simple_level_monitor.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/simple_level_monitor.rs), which generates synthetic level data and emits the same `audio-levels` events. This allows UI development and testing in environments without audio input devices.

### How does the frontend distinguish between active and inactive audio sources?

Each `AudioLevelData` payload includes an **is_active** boolean field that is set to `true` when the RMS level exceeds `0.001`. This threshold filters out background noise and silent inputs, allowing the UI to highlight only devices receiving actual audio signals.