# How Meetily's Audio Import System Processes Existing Audio Files: A Technical Deep Dive

> Explore Meetily's audio import system. Learn how it processes existing MP4 WAV and MP3 files transforming them into transcribed meetings via a robust pipeline.

- Repository: [Zackriya Solutions/meetily](https://github.com/Zackriya-Solutions/meetily)
- Tags: deep-dive
- Published: 2026-07-06

---

**Meetily's audio import system converts pre-recorded audio files (MP4, WAV, MP3) into fully transcribed meetings through a staged, cancellable pipeline that validates, decodes, resamples, and transcribes content using the same high-quality infrastructure as live capture.**

Meetily is an open-source meeting assistant that enables users to retroactively import existing recordings. The import pipeline is implemented in [`frontend/src-tauri/src/audio/import.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/import.rs) and follows a robust async workflow that handles files up to 20 GB while providing real-time progress updates to the frontend.

## Safety and Concurrency Controls

The pipeline begins with **safety guards** to prevent race conditions and ensure clean cancellation. The system uses two global atomic flags: `IMPORT_IN_PROGRESS` and `IMPORT_CANCELLED`. These ensure only one import runs simultaneously and allow the UI to abort jobs safely.

The `ImportGuard` RAII type in [`import.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/import.rs) automatically sets the in-progress flag on construction and clears it on drop, preventing stray flags even if a panic occurs. This pattern guarantees that the `IMPORT_IN_PROGRESS` flag is always properly reset when the guard goes out of scope, regardless of how the function exits.

## File Validation and Meeting Setup

**File selection** starts with the `select_and_validate_audio_command` function, which opens a native file dialog via `tauri_plugin_dialog`. The selected path undergoes rigorous validation through `validate_audio_file`, which checks:

- File existence and readability
- Supported extensions (defined in `AUDIO_EXTENSIONS`)
- File size limits (maximum 20 GB)
- Audio duration extraction

Duration detection first attempts a fast metadata probe using the **symphonia** crate via `extract_duration_from_metadata`, falling back to a full decode only when necessary. This optimization prevents unnecessary I/O for large files.

Once validated, `create_meeting_folder` (from [`audio/common.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/audio/common.rs)) generates a unique sub-directory under the user's default recordings folder and initializes a placeholder [`metadata.json`](https://github.com/Zackriya-Solutions/meetily/blob/main/metadata.json). The source audio is then copied into this folder as `audio.<ext>` using `std::fs::copy` wrapped in `tokio::spawn_blocking` to avoid blocking the async runtime.

## Audio Processing Pipeline

The system processes audio through three distinct stages to prepare it for transcription.

### Decoding and Resampling

The `decode_audio_file_with_progress` function reads the copied file into an `AudioDecoded` struct containing sample rate, channel count, and duration. Progress callbacks emit Tauri events with the stage identifier "decoding".

Next, `to_whisper_format_with_progress` converts the decoded audio to **16 kHz mono PCM**, the format required by Whisper. This resampling stage reports progress under the "resampling" stage name.

### Voice Activity Detection

The resampled audio flows into `get_speech_chunks_with_progress` (implemented in [`audio/vad.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/audio/vad.rs)). For batch imports, the VAD uses a **redemption time of 2000 ms**—longer than live capture—to bridge natural pauses in speech and reduce fragmentation. The function returns a vector of `SpeechSegment` structs containing raw samples and timestamps.

### Segment Optimization

To improve transcription quality, the pipeline splits overly long segments. The `split_segment_at_silence` function (from [`audio/common.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/audio/common.rs)) divides any VAD segment exceeding **25 seconds** at detected silence boundaries. This prevents truncation artifacts and ensures the transcription engine receives optimally sized chunks.

## Transcription and Persistence

### Engine Selection

The system supports multiple transcription backends via the `provider` parameter. Based on this argument, the pipeline lazily initializes either the `WhisperEngine` via `get_or_init_whisper` or the `ParakeetEngine` via `get_or_init_parakeet`. Both engines implement the same async interface, receiving speech segments and returning transcribed text with confidence scores.

### Transcript Construction

As transcriptions complete, `create_transcript_segments` (from [`audio/common.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/audio/common.rs)) aggregates the results. It calculates average confidence scores across all segments and transforms the raw output into structured `TranscriptSegment` records ready for storage.

### Database and File Output

The `create_meeting_with_transcripts` function persists everything within a single SQLite transaction using `sqlx`. It inserts a new meeting row and associated transcript rows atomically.

Simultaneously, the pipeline writes [`transcripts.json`](https://github.com/Zackriya-Solutions/meetily/blob/main/transcripts.json) and [`metadata.json`](https://github.com/Zackriya-Solutions/meetily/blob/main/metadata.json) to the meeting folder using temporary files and atomic rename operations. This ensures that partial writes never corrupt the meeting data if the system crashes during export.

## Progress Events and Cancellation

Throughout the pipeline, `emit_progress` sends `import-progress` events to the frontend, enabling progress bars that display stages: "copying", "decoding", "resampling", "vad", "transcribing", and "saving". On completion, the system emits an `import-complete` event containing the meeting ID and processing statistics.

The **cancellation system** checks `IMPORT_CANCELLED` at every stage boundary. When the user triggers `cancel_import_command`, the flag flips and the pipeline aborts at the next checkpoint, cleaning up the temporary meeting folder and returning an "Import cancelled" error via the `import-error` event. Non-fatal warnings, such as "no speech detected", propagate through `import-warning` events without terminating the process.

## Frontend Integration

Integrating the import system requires invoking Tauri commands and listening to events. The following examples demonstrate the TypeScript implementation.

### Starting an Import

To initiate processing, invoke the `start_import_audio_command` with the source path and metadata:

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

const sourcePath = '/Users/alice/Downloads/meeting.mp4';
const title = 'Quarterly Review';
const language = 'en';
const model = undefined;  // Uses default model
const provider = 'whisper';  // or 'parakeet'

await invoke('start_import_audio_command', {
  sourcePath,
  title,
  language,
  model,
  provider,
});

```

This command is defined at the bottom of [`frontend/src-tauri/src/audio/import.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/import.rs) and launches the async import job immediately.

### Monitoring Progress

Listen to `import-progress` events to update the UI:

```typescript
import { listen } from '@tauri-apps/api/event';

listen('import-progress', (event) => {
  const { stage, progress_percentage, message } = event.payload as {
    stage: string;
    progress_percentage: number;
    message: string;
  };
  console.log(`[${stage}] ${progress_percentage}% – ${message}`);
});

```

Similar listeners handle `import-complete`, `import-error`, and `import-warning` events to manage success states and error recovery.

### Cancelling Imports

To abort an ongoing import:

```typescript
await invoke('cancel_import_command');

```

This flips the `IMPORT_CANCELLED` flag, causing the pipeline to terminate gracefully at the next checkpoint.

## Summary

- **Meetily's audio import system** processes existing MP4, WAV, and MP3 files through a staged pipeline that reuses the live-capture infrastructure while optimizing for batch processing.
- **Safety mechanisms** like `ImportGuard` and atomic flags prevent concurrent imports and ensure clean cancellation even during panics.
- **Validation** checks file size (≤20 GB), extensions, and duration using fast metadata probes before copying the source into a dedicated meeting folder.
- **Processing stages** include decoding to raw PCM, resampling to 16 kHz mono, voice-activity detection with 2000 ms redemption time, and segment splitting at 25-second boundaries.
- **Transcription** supports both Whisper and Parakeet engines, with results persisted atomically to SQLite and JSON files.
- **Real-time communication** occurs through Tauri events, providing progress updates and supporting mid-process cancellation.

## Frequently Asked Questions

### What audio formats does Meetily support for import?

Meetily supports common formats including MP4, WAV, and MP3. The specific extensions allowed are defined in the `AUDIO_EXTENSIONS` constant within [`frontend/src-tauri/src/audio/import.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/import.rs). The validation layer confirms format support before processing begins.

### How does Meetily handle large audio files during import?

The system imposes a 20 GB file size limit validated during the initial `validate_audio_file` check. Large files are processed efficiently through streaming decoding and resampling, with progress events emitted at each stage to keep the UI responsive. File copying operations run in `spawn_blocking` threads to prevent async runtime blocking.

### Can I cancel an import while it's processing?

Yes. The import pipeline checks the `IMPORT_CANCELLED` atomic flag at every stage boundary. Invoking `cancel_import_command` sets this flag, causing the pipeline to abort at the next checkpoint, clean up the temporary meeting folder, and emit an `import-error` event with the message "Import cancelled".

### Does importing reuse the same transcription quality as live recording?

Absolutely. The import system utilizes the identical decoding, VAD, and transcription infrastructure as live capture. However, it optimizes for batch processing with a longer 2000 ms VAD redemption time to bridge natural pauses in pre-recorded content, and it splits segments longer than 25 seconds to prevent truncation artifacts.