How Incremental Audio Saving with Checkpoints Works in Meetily

The Meetily desktop app prevents data loss during long recording sessions by writing 30-second MP4 checkpoint files to disk every 1,440,000 samples, then merging them into a single final audio file when the session ends.

Incremental audio saving with checkpoints is a fault-tolerance mechanism implemented in the Rust-based core of Zackriya-Solutions/meetily. Instead of holding the entire recording in memory, the system periodically flushes buffered audio to disk as discrete checkpoint files, ensuring that even if the application crashes, the already-captured audio remains recoverable.

Core Architecture

The implementation spans four layers across the Tauri-based backend. Each layer has a distinct responsibility in the checkpoint lifecycle.

IncrementalAudioSaver (incremental_saver.rs)

The IncrementalAudioSaver struct in frontend/src-tauri/src/audio/incremental_saver.rs manages the raw audio buffer and checkpoint persistence. It maintains a checkpoint_buffer vector that accumulates incoming f32 PCM samples and calculates the threshold for flushing data based on the configured sample rate.

Key responsibilities include:

  • Calculating checkpoint_interval_samples (30 seconds at 48 kHz = 1,440,000 samples)
  • Encoding buffered samples to MP4 format using FFmpeg
  • Naming checkpoint files sequentially as audio_chunk_{:03}.mp4 inside a hidden .checkpoints/ directory
  • Generating the FFmpeg concat list (concat_list.txt) during finalization

RecordingSaver (recording_saver.rs)

Located at frontend/src-tauri/src/audio/recording_saver.rs, the RecordingSaver owns an Arc<AsyncMutex<IncrementalAudioSaver>> (named incremental_saver). This wrapper instantiates the saver when a meeting starts with the auto_save flag enabled and forwards each incoming audio chunk via save_chunk().

The saver handles meeting folder creation and ensures the .checkpoints/ subdirectory exists before recording begins.

RecordingManager (recording_manager.rs)

The RecordingManager in frontend/src-tauri/src/audio/recording_manager.rs controls the high-level recording lifecycle. It evaluates the auto_save parameter to determine whether checkpointing should be activated for a session and triggers the finalization sequence (finalize_recording) when the user stops recording.

Tauri Command Layer (lib.rs)

Three commands exposed in frontend/src-tauri/src/lib.rs allow the React frontend to interact with the checkpoint system:

  • has_audio_checkpoints – Verifies if checkpoint files exist for a given meeting folder
  • recover_audio_from_checkpoints – Merges existing checkpoints into a single audio file after a crash
  • cleanup_checkpoints – Removes the .checkpoints/ directory following successful finalization

The Checkpoint Lifecycle

The incremental audio saving process follows a strict six-stage pipeline to ensure data integrity.

1. Initialization

When RecordingSaver::start_meeting is invoked with auto_save = true, the system creates a hidden subdirectory inside the meeting folder:

let checkpoints_dir = meeting_folder.join(".checkpoints");
std::fs::create_dir_all(&checkpoints_dir)?;

This directory stores temporary MP4 segments until finalization.

2. Chunk Accumulation

As audio data arrives from the capture device, samples are appended to the checkpoint_buffer:

// Inside incremental_saver.rs
self.checkpoint_buffer.extend_from_slice(&audio_samples);
self.total_samples += audio_samples.len();

The buffer grows until it reaches the calculated threshold.

3. Checkpoint Trigger

The saver continuously compares total_samples against checkpoint_interval_samples. When the buffer contains 30 seconds of audio (1,440,000 samples at 48 kHz), the system triggers a flush.

4. Saving a Checkpoint

The save_checkpoint() method encodes the buffer to MP4 and writes it to disk:

fn save_checkpoint(&mut self) -> Result<()> {
    if self.checkpoint_buffer.is_empty() {
        warn!("Attempted to save empty checkpoint, skipping");
        return Ok(());
    }
    let checkpoint_path = self.checkpoints_dir
        .join(format!("audio_chunk_{:03}.mp4", self.checkpoint_count));
    
    // Encode checkpoint_buffer to MP4 via FFmpeg
    encode_to_mp4(&self.checkpoint_buffer, &checkpoint_path)?;
    
    self.checkpoint_count += 1;
    self.checkpoint_buffer.clear();
    info!("Saved checkpoint {} to {:?}", self.checkpoint_count, checkpoint_path);
    Ok(())
}

Each checkpoint is an independent, playable MP4 file.

5. Finalization

When the user stops the recording, finalize_recording performs three operations:

  1. Saves any remaining data in checkpoint_buffer as a final checkpoint
  2. Generates a concat_list.txt file listing all checkpoints in sequence
  3. Invokes FFmpeg with the concat demuxer to produce audio.mp4 in the meeting root:
ffmpeg -f concat -safe 0 -i concat_list.txt -c copy audio.mp4

6. Cleanup

After successful merging, the system removes the .checkpoints/ directory to reclaim disk space.

Crash Recovery and Data Integrity

If the application terminates unexpectedly, the checkpoint files persist on disk. The frontend can detect and recover this data using Tauri commands:

// React component checking for recoverable audio
const hasCheckpoints = await invoke('has_audio_checkpoints', {
  meetingFolder: '/path/to/Meetily/Meetings/Team Standup'
});

if (hasCheckpoints) {
  await invoke('recover_audio_from_checkpoints', {
    meetingFolder: '/path/to/Meetily/Meetings/Team Standup'
  });
}

The recovery process executes the same FFmpeg concatenation routine used during normal finalization, ensuring consistent output regardless of how the recording ended.

Implementation Code Examples

Starting a Recording with Checkpoints Enabled

use meetily::audio::RecordingSaver;

// Initialize saver with base storage folder
let mut saver = RecordingSaver::new("/home/user/Meetily")?;

// Start meeting with auto_save = true to enable checkpoints
saver.start_meeting("Q4 Planning Session", true)?;

// Audio chunks are automatically checkpointed every 30 seconds
saver.save_audio_chunk(AudioData { samples: pcm_data })?;

Recovering Audio After a Crash

import { invoke } from '@tauri-apps/api/core';

async function recoverSession(meetingPath: string): Promise<void> {
  const exists = await invoke('has_audio_checkpoints', {
    meetingFolder: meetingPath
  });
  
  if (exists) {
    await invoke('recover_audio_from_checkpoints', {
      meetingFolder: meetingPath
    });
    await invoke('cleanup_checkpoints', {
      meetingFolder: meetingPath
    });
  }
}

Internal Checkpoint Saving Logic

// From incremental_saver.rs - threshold checking
fn process_audio_chunk(&mut self, samples: &[f32]) -> Result<()> {
    self.checkpoint_buffer.extend_from_slice(samples);
    
    if self.checkpoint_buffer.len() >= self.checkpoint_interval_samples {
        self.save_checkpoint()?;
    }
    Ok(())
}

Summary

  • Incremental audio saving with checkpoints in Meetily prevents data loss by flushing 30-second MP4 segments to disk instead of storing the entire recording in memory.
  • The IncrementalAudioSaver manages buffer thresholds (1,440,000 samples) and FFmpeg encoding in frontend/src-tauri/src/audio/incremental_saver.rs.
  • Checkpoint files follow the naming pattern audio_chunk_{:03}.mp4 and reside in a hidden .checkpoints/ folder until finalization.
  • The RecordingSaver and RecordingManager coordinate to enable checkpointing via the auto_save flag and handle the concatenation of segments into a final audio.mp4.
  • Three Tauri commands—has_audio_checkpoints, recover_audio_from_checkpoints, and cleanup_checkpoints—provide the frontend with tools for crash recovery and cleanup.

Frequently Asked Questions

How often does Meetily save audio checkpoints?

Meetily saves audio checkpoints every 30 seconds of recorded audio. At the default 48 kHz sample rate, this translates to every 1,440,000 samples. This interval balances data safety with disk I/O overhead, ensuring minimal audio loss in case of crashes while maintaining performance.

What happens if Meetily crashes during a recording?

If the application crashes, the checkpoint files already written to the .checkpoints/ directory remain intact on disk. When the app restarts, the frontend can call the recover_audio_from_checkpoints command, which uses FFmpeg to concatenate all existing audio_chunk_{:03}.mp4 files into a complete audio.mp4 file. Only the audio recorded since the last checkpoint (maximum 30 seconds) is lost.

Where are the checkpoint files stored?

Checkpoint files are stored in a hidden subdirectory named .checkpoints/ inside the specific meeting folder. For example, if your meeting is named "Team Standup," the checkpoints reside at ~/Meetily/Meetings/Team Standup/.checkpoints/audio_chunk_000.mp4. This location is created automatically when a meeting starts with auto_save enabled.

How does the final audio file get created from checkpoints?

During finalization, the IncrementalAudioSaver first writes any remaining buffered audio as a final checkpoint. It then generates an FFmpeg concat list (concat_list.txt) enumerating all checkpoint files in sequence. Finally, it executes ffmpeg -f concat -safe 0 -i concat_list.txt -c copy audio.mp4 to produce a single concatenated file without re-encoding, preserving original quality and maximizing performance.

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 →