How Meetily Implements Real-Time Audio Level Monitoring During Recording
Meetily's audio level monitoring system captures microphone input via Rust's CPAL library, calculates RMS and peak levels every 100 milliseconds, and streams the data to a React frontend through Tauri events to render live visual meters.
Meetily, the open-source meeting recorder from Zackriya-Solutions, provides immediate visual feedback on microphone input health through a sophisticated real-time audio level monitoring pipeline. This system bridges low-level audio processing in Rust with a React-based user interface, enabling users to verify microphone levels and adjust gain before or during recording sessions.
Rust Backend: Audio Capture and Level Calculation
Initializing the AudioLevelMonitor
The core monitoring logic resides in src-tauri/src/audio/level_monitor.rs. The AudioLevelMonitor struct creates a CPAL input stream for each selected device, configured to process audio callbacks via the process_audio_levels function. The implementation builds a thread-safe data pipeline using Arc<Mutex<Vec<AudioLevelData>>> to share calculated metrics across async boundaries.
// src-tauri/src/audio/level_monitor.rs (excerpt)
let stream = device.build_input_stream(
&stream_config,
move |data: &[f32], _| {
process_audio_levels(data, channels, &device_name, &device_type, level_data_clone.clone());
},
|err| error!("Audio stream error: {}", err),
None,
)?;
stream.play()?;
RMS and Peak Processing
Within each audio callback, the system converts multi-channel PCM data to mono before computing two essential metrics: RMS (root mean square) representing average power, and peak indicating maximum amplitude. These values determine the visual height of the level bars and the position of the peak marker in the UI.
Emitting Tauri Events
A dedicated Tokio task packages the current AudioLevelData into an AudioLevelUpdate struct and emits it via Tauri's event system every 100 milliseconds. The emission continues while AudioLevelState.is_monitoring remains true, delivering roughly ten updates per second to the frontend.
// Periodic emission from src-tauri/src/audio/level_monitor.rs
tokio::spawn(async move {
let mut interval = interval(Duration::from_millis(100));
while AUDIO_LEVEL_STATE.is_monitoring.load(Ordering::SeqCst) {
interval.tick().await;
app_handle.emit("audio-levels", &update).ok();
}
});
Frontend Integration: React and Tauri Events
Starting the Monitoring Session
The DeviceSelection component in frontend/src/components/DeviceSelection.tsx initiates monitoring by invoking the Tauri command start_audio_level_monitoring with the selected device names. This triggers the Rust backend to begin CPAL stream processing and the 100ms emission loop.
// Inside DeviceSelection.tsx
const startAudioLevelMonitoring = async () => {
const deviceNames = inputDevices.map(d => d.name);
await invoke('start_audio_level_monitoring', { deviceNames });
setIsMonitoring(true);
setShowLevels(true);
};
Listening for Real-Time Updates
The frontend registers an event listener using listen('audio-levels', …) (implemented around lines 74-90 of DeviceSelection.tsx). Each incoming payload replaces the component's audioLevels Map, keyed by device name, triggering React re-renders with fresh RMS and peak values.
useEffect(() => {
const unlisten = await listen<AudioLevelUpdate>('audio-levels', event => {
const levels = new Map<string, AudioLevelData>();
event.payload.levels.forEach(l => levels.set(l.device_name, l));
setAudioLevels(levels);
});
return () => unlisten?.();
}, [isMonitoring]);
Visualizing Levels in the UI
Rendering Audio Meters
Level visualization occurs in frontend/src/components/AudioLevelMeter.tsx, where the AudioLevelMeter and CompactAudioLevelMeter components receive data from the audioLevels Map. The system renders a distinct meter for each input device, allowing users to monitor multiple microphones simultaneously.
{showLevels && inputDevices.map(dev => (
<AudioLevelMeter
key={dev.name}
rmsLevel={audioLevels.get(dev.name)?.rms_level ?? 0}
peakLevel={audioLevels.get(dev.name)?.peak_level ?? 0}
isActive={audioLevels.get(dev.name)?.is_active ?? false}
deviceName={dev.name}
size="small"
/>
))}
Logarithmic Scaling and Color Coding
To ensure low-level sounds remain visible, the meter applies log10 logarithmic scaling to raw amplitude values. The UI renders a color gradient transitioning from green through yellow to red based on intensity, with an optional thin marker indicating peak levels. An isActive flag drives a pulsing activity dot that confirms the microphone is detecting sound above the noise floor.
User Controls and Lifecycle
Users control the monitoring lifecycle through explicit Tauri commands. Invoking start_audio_level_monitoring activates the CPAL streams and begins the emission loop, while stop_audio_level_monitoring halts processing and clears visual indicators. This architecture allows users to verify microphone health, check for hardware issues, and optimize gain staging before initiating full recording sessions.
Summary
- Meetily's real-time audio level monitoring combines Rust's CPAL library with Tauri's event bridge to deliver approximately ten updates per second to the React frontend.
- The
AudioLevelMonitorstruct insrc-tauri/src/audio/level_monitor.rscalculates RMS and peak values from raw PCM samples and emits them via theaudio-levelsevent every 100 milliseconds. - The
DeviceSelectioncomponent listens for these events infrontend/src/components/DeviceSelection.tsxand maintains a Map ofAudioLevelDatakeyed by device name to drive component re-renders. - The
AudioLevelMetercomponent applies logarithmic scaling and color coding (green to red) to visualize microphone levels, with anisActiveflag controlling a pulsing activity indicator.
Frequently Asked Questions
How often does Meetily update the audio level meters?
The system calculates levels continuously in the Rust audio callback but packages and emits updates via the audio-levels Tauri event every 100 milliseconds, resulting in approximately ten visual updates per second during recording or monitoring sessions.
What audio metrics does the system calculate for visualization?
According to the source code in src-tauri/src/audio/level_monitor.rs, the system computes RMS (root mean square) for average power and peak (maximum amplitude) for spike detection, converting multi-channel input to mono before performing calculations.
Can users monitor multiple microphones simultaneously?
Yes. The AudioLevelMonitor maintains a Vec<AudioLevelData> within a shared Arc<Mutex<...>> structure, and the frontend renders an AudioLevelMeter component for each device in the audioLevels Map, enabling parallel visualization of multiple audio sources.
How does the frontend know when audio is actually being detected?
The Rust backend sets an is_active boolean flag in the AudioLevelData struct when the input signal exceeds a defined threshold. The React frontend uses this flag to display a pulsing activity dot alongside the logarithmically-scaled level bars, providing immediate confirmation that the microphone is capturing sound.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →