How Meetily's Incremental Audio Saver Handles Checkpointing During Recording

Meetily's IncrementalAudioSaver writes 30-second audio checkpoints to disk during recording, then merges them into a final file when the session ends, ensuring no data is lost even if the app crashes.

The incremental saver is a Rust component in the Zackriya-Solutions/meetily desktop app that enables long-duration audio recording without excessive memory consumption. By persisting audio segments as .mp4 checkpoints every 30 seconds, the system maintains durability guarantees while keeping the working memory footprint minimal.

Core Architecture Components

IncrementalAudioSaver — Buffer Management and Checkpoint Writing

Located in src-tauri/src/audio/incremental_saver.rs, this struct is the heart of the checkpointing system:

  • Maintains a checkpoint_buffer for accumulating incoming audio samples
  • Computes checkpoint_interval_samples based on a 30-second threshold (1,440,000 samples at 48 kHz)
  • Triggers save_checkpoint() when the buffer reaches the interval threshold

When triggered, the saver encodes the buffer to MP4 via FFmpeg and writes it to .checkpoints/audio_chunk_{:03}.mp4, incrementing a counter for the next segment.

RecordingSaver — Ownership and Audio Routing

In src-tauri/src/audio/recording_saver.rs, the saver holds an optional Arc<AsyncMutex<IncrementalAudioSaver>>:

// Instantiated when meeting starts with auto_save = true
IncrementalAudioSaver::new(meeting_folder, sample_rate)

// Each incoming chunk flows through
incremental_saver.save_chunk(audio_data)

This wrapper handles the meeting folder lifecycle and delegates checkpoint decisions to the inner saver.

RecordingManager — Lifecycle Control

The src-tauri/src/audio/recording_manager.rs module determines whether checkpointing is enabled via the auto_save flag. When a meeting stops, it orchestrates finalize_recording to trigger the merge process.

Checkpoint Lifecycle: From Initialization to Cleanup

1. Initialization

When a meeting folder is created, the saver ensures a hidden .checkpoints/ subdirectory exists:

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

2. Chunk Accumulation

Incoming f32 PCM samples append to checkpoint_buffer. The saver tracks total_samples continuously.

3. Checkpoint Trigger

At 1,440,000 samples (30 seconds of 48 kHz audio), the threshold fires:

if total_samples >= self.checkpoint_interval_samples {
    self.save_checkpoint()?;
}

4. Saving Individual Checkpoints

The save_checkpoint() method in incremental_saver.rs handles encoding:

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));
    // FFmpeg encoding: checkpoint_buffer → MP4
    // ...
    self.checkpoint_count += 1;
    info!("Saved checkpoint {}: {:.2}s of audio", self.checkpoint_count, /* ... */);
    Ok(())
}

5. Finalization and Merging

On stop_meeting(), the saver:

  • Writes any remaining buffer as a final checkpoint
  • Generates an FFmpeg concat list (concat_list.txt)
  • Merges all chunks into audio.mp4 in the meeting folder

6. Cleanup

Post-merge, the .checkpoints/ directory is removed to reclaim disk space.

Crash Recovery Commands

Three Tauri commands in src-tauri/src/lib.rs expose checkpoint functionality to the frontend:

Command Purpose
has_audio_checkpoints Verifies if .checkpoints/ contains recoverable files
recover_audio_from_checkpoints Merges orphaned checkpoints after a crash
cleanup_checkpoints Removes temporary files following successful recovery

Frontend invocation example:

// React component recovering a crashed session
await invoke('recover_audio_from_checkpoints', {
  meetingFolder: '/path/to/Meetily/Meetings/Team Standup'
});

Sample Integration Code

Starting a checkpoint-enabled recording:

let mut saver = RecordingSaver::new(base_folder)?;
saver.start_meeting("Team Standup", true)?; // `true` enables checkpointing

// During recording
saver.save_audio_chunk(AudioData { samples: my_samples })?;

// End and merge
saver.stop_meeting()?; // Produces final `audio.mp4`

Summary

  • IncrementalAudioSaver in src-tauri/src/audio/incremental_saver.rs buffers audio and writes 30-second MP4 checkpoints
  • Checkpointing activates when auto_save = true in RecordingManager
  • The .checkpoints/ folder contains sequentially numbered audio_chunk_{:03}.mp4 files
  • FFmpeg concatenation merges checkpoints into a single audio.mp4 on stop
  • Three Tauri commands enable crash recovery without data loss

Frequently Asked Questions

How often does Meetily save audio checkpoints?

Every 30 seconds of recorded audio. At the default 48 kHz sample rate, this equals 1,440,000 samples accumulated in checkpoint_buffer before save_checkpoint() triggers.

What happens if Meetily crashes during a recording?

Already-written checkpoints in .checkpoints/ remain intact. Use the recover_audio_from_checkpoints command to merge them into a complete audio.mp4 file. No audio captured before the crash is lost.

Why does the incremental saver use MP4 instead of raw PCM?

MP4 provides compressed, seekable storage with FFmpeg compatibility. This keeps checkpoint files smaller than uncompressed audio while enabling efficient concatenation during finalization.

Where are checkpoint files stored during recording?

In a hidden .checkpoints/ subdirectory inside the meeting folder. The path is constructed as meeting_folder.join(".checkpoints") and cleaned up automatically after successful merge.

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 →