# How Meetily's Import Module Handles External Audio File Ingestion and Format Detection

> Learn how Meetily's import module ingests and detects external audio file formats using a Rust pipeline. It validates extensions, probes metadata with Symphonia, and decodes large files efficiently.

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

---

**Meetily's import module handles external audio file ingestion and format detection through a Rust-based pipeline in [`frontend/src-tauri/src/audio/import.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/import.rs) that validates file extensions against a whitelist, probes metadata using the Symphonia crate for efficient duration extraction, and falls back to full decoding when necessary, supporting files up to 20 GB.**

Meetily's import module provides a robust backend for ingesting external audio files into the application, implemented in the Zackriya-Solutions/meetily repository. The system leverages Tauri's native dialog capabilities and the Symphonia audio library to detect formats and validate files before processing them for transcription. This technical deep-dive explores the exact mechanisms used to handle file selection, format detection, and the validation pipeline that ensures only compatible audio reaches the transcription engine.

## The Three-Phase Import Architecture

The import pipeline operates through three distinct phases orchestrated by commands defined in [`frontend/src-tauri/src/audio/import.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/import.rs).

### Phase 1: Native File Selection

The process begins when the frontend invokes `select_and_validate_audio_command`, which launches a native file dialog via `tauri_plugin_dialog`. The dialog automatically filters selectable files using the `AUDIO_EXTENSIONS` constant defined in [`constants.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/constants.rs), presenting users with a whitelist of supported formats including MP4, M4A, WAV, MP3, FLAC, OGG, AAC, MKV, WebM, and WMA.

Once the user selects a file, the command returns the path to the Rust backend for validation. This approach ensures that only potentially compatible files reach the validation stage while providing a native OS-level selection experience.

### Phase 2: Validation and Format Detection

The `validate_audio_file` function performs comprehensive validation before any heavy processing occurs. First, it verifies the file exists and checks that its size does not exceed the **20 GB** limit enforced to prevent out-of-memory errors.

Format detection occurs in two stages for efficiency:

1. **Extension validation**: The file extension is normalized to lowercase and compared against the `AUDIO_EXTENSIONS` slice from [`constants.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/constants.rs).
2. **Metadata extraction**: The function calls `extract_duration_from_metadata`, which uses the Symphonia crate to build a `Hint` from the file extension, probe the format, and read `sample_rate` and `n_frames` to calculate duration without decoding audio data.

If Symphonia cannot determine the duration (for example, when frame counts are missing), the system falls back to `decode_audio_file` from [`decoder.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/decoder.rs) for a full decode.

### Phase 3: Import Orchestration

Once validated, `start_import_audio_command` spawns `start_import`, which acquires a guard to ensure only one import runs concurrently. This phase:

- Creates a dedicated meeting folder
- Copies the source file to the new location
- Decodes and resamples audio to **16 kHz mono** format required by Whisper
- Runs Voice Activity Detection (VAD) via `get_speech_chunks_with_progress` from [`vad.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/vad.rs)
- Transcribes speech chunks
- 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

## Technical Implementation of Format Detection

Format detection in Meetily balances speed with accuracy through a tiered approach.

### Extension-Based Whitelist Validation

The authoritative list of supported formats resides in [`frontend/src-tauri/src/audio/constants.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/constants.rs):

```rust
pub const AUDIO_EXTENSIONS: &[&str] = &[
    "mp4", "m4a", "wav", "mp3", "flac", "ogg", "aac", "mkv", "webm", "wma"
];

```

During validation, the system extracts the extension using `path.extension()`, converts it to lowercase, and checks membership in this static slice. This provides instantaneous rejection of unsupported containers before any I/O-intensive operations occur.

### Metadata Probing with Symphonia

The `extract_duration_from_metadata` function (lines 192-250 in [`import.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/import.rs)) implements efficient format detection:

```rust
pub fn extract_duration_from_metadata(path: &Path) -> Result<f64> {
    let file = File::open(path)?;
    let mss = MediaSourceStream::new(Box::new(file), Default::default());
    
    // Build hint from file extension
    let mut hint = Hint::new();
    if let Some(ext) = path.extension() {
        hint.with_extension(&ext.to_string_lossy());
    }
    
    // Probe format and read metadata
    let probed = symphonia::default::get_probe()
        .format(&hint, mss, &Default::default(), Default::default())?;
        
    // Calculate duration from sample_rate and n_frames
    // ...
}

```

This approach reads only container metadata, making it suitable for multi-gigabyte files where full decoding would be prohibitively expensive.

### Fallback Full-Decode Strategy

When metadata probing fails, the system invokes `decode_audio_file` from [`decoder.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/decoder.rs). This function performs a complete decode to determine duration and validate format integrity. While more resource-intensive, this fallback ensures compatibility with malformed or complex audio files that report incomplete metadata headers.

## Code Implementation Examples

### Frontend File Selection

React/TypeScript code that triggers the import dialog:

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

interface AudioFileInfo {
  path: string;
  filename: string;
  duration_seconds: number;
  size_bytes: number;
  format: string;
}

async function pickAudioFile() {
  const info = await invoke<AudioFileInfo | null>('select_and_validate_audio_command');
  if (!info) {
    console.log('User cancelled selection');
    return;
  }
  console.log(`Selected ${info.format} file: ${info.filename}, duration: ${info.duration_seconds}s`);
}

```

### Backend Validation Logic

The core validation function in [`frontend/src-tauri/src/audio/import.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/import.rs):

```rust
pub fn validate_audio_file(path: &Path) -> Result<AudioFileInfo> {
    // Verify file exists
    if !path.exists() {
        return Err(anyhow!("File does not exist: {}", path.display()));
    }

    // Validate extension against whitelist
    let extension = path.extension()
        .and_then(|e| e.to_str())
        .map(|e| e.to_lowercase())
        .unwrap_or_default();

    if !AUDIO_EXTENSIONS.contains(&extension.as_str()) {
        return Err(anyhow!("Unsupported format: .{} not in supported list", extension));
    }

    // Size guard (20 GB limit)
    let metadata = fs::metadata(path)?;
    if metadata.len() > 20 * 1024 * 1024 * 1024 {
        return Err(anyhow!("File exceeds 20 GB limit"));
    }

    // Attempt metadata extraction, fallback to decode
    let duration_seconds = match extract_duration_from_metadata(path) {
        Ok(d) => d,
        Err(_) => decode_audio_file(path)?.duration_seconds,
    };

    Ok(AudioFileInfo {
        path: path.to_string_lossy().to_string(),
        filename: path.file_name().unwrap().to_string_lossy().to_string(),
        duration_seconds,
        size_bytes: metadata.len(),
        format: extension.to_uppercase(),
    })
}

```

### Drag-and-Drop Validation

For files dropped onto the application:

```rust
#[tauri::command]
pub async fn validate_audio_file_command(path: String) -> Result<AudioFileInfo, String> {
    validate_audio_file(Path::new(&path))
        .map_err(|e| e.to_string())
}

```

## Summary

- **Meetily's import module** uses a three-phase pipeline (selection, validation, orchestration) implemented in [`frontend/src-tauri/src/audio/import.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/import.rs)
- **Format detection** relies on extension whitelisting from [`constants.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/constants.rs) followed by Symphonia metadata probing, with full-decode fallback for edge cases
- **File size limits** of 20 GB prevent memory exhaustion during processing
- **Supported formats** include MP4, M4A, WAV, MP3, FLAC, OGG, AAC, MKV, WebM, and WMA
- **Final processing** converts all valid audio to 16 kHz mono and applies VAD before transcription

## Frequently Asked Questions

### What audio formats does Meetily support?

Meetily supports MP4, M4A, WAV, MP3, FLAC, OGG, AAC, MKV, WebM, and WMA files. The authoritative list is defined in the `AUDIO_EXTENSIONS` constant in [`frontend/src-tauri/src/audio/constants.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/constants.rs). The system validates extensions case-insensitively before attempting any format detection.

### How does Meetily detect audio formats without decoding the entire file?

The system uses the Symphonia crate's `extract_duration_from_metadata` function to probe file headers and metadata. This creates a `Hint` from the file extension, probes the format, and reads `sample_rate` and `n_frames` to calculate duration without loading audio samples into memory. This approach handles multi-gigabyte files efficiently.

### What happens if Symphonia cannot read the audio metadata?

When metadata extraction fails (typically due to missing frame counts or malformed headers), Meetily falls back to `decode_audio_file` from [`decoder.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/decoder.rs). This performs a full audio decode to determine the duration and validate the file. While more resource-intensive, this fallback ensures compatibility with problematic files that would otherwise be rejected.

### Is there a file size limit for imported audio?

Yes, Meetily enforces a **20 GB** limit during the validation phase in `validate_audio_file`. Files exceeding this size are rejected immediately to prevent out-of-memory errors during the subsequent decode, resample, and VAD processing stages. This guard is checked after extension validation but before any metadata extraction occurs.