# How Meetily's Import Feature Processes External Audio Files: A Technical Deep Dive

> Explore how Meetily processes external audio files. Discover the technical pipeline for converting MP4 WAV MP3 into searchable meetings with voice-activity detection and transcription.

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

---

**Meetily converts pre-recorded audio files (MP4, WAV, MP3) into fully searchable meetings by running them through a staged pipeline that validates, decodes, resamples, performs voice-activity detection, and transcribes the content using either Whisper or Parakeet engines.**

Meetily, an open-source meeting intelligence platform from Zackriya-Solutions, provides a robust import system that transforms existing recordings into structured meeting data. The import feature processes external audio files through a cancellable, progress-tracked pipeline implemented in Rust within the Tauri backend. This allows users to retroactively analyze interviews, lectures, or archived calls using the same high-quality speech-to-text infrastructure as live recordings.

## Import Pipeline Architecture and Safety Mechanisms

The core import logic resides in **[`frontend/src-tauri/src/audio/import.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/import.rs)**, which implements a stateful workflow guarded by global atomic flags. The system uses **`IMPORT_IN_PROGRESS`** and **`IMPORT_CANCELLED`** flags to ensure only one import runs at a time while allowing safe abortion from the UI.

The **`ImportGuard`** RAII type manages these flags automatically, setting `IMPORT_IN_PROGRESS` on construction and clearing it on drop—even if the thread panics. This prevents zombie states where the application believes an import is still running after a crash.

```rust
// Conceptual usage within start_import_audio_command
let _guard = ImportGuard::new();
// ... pipeline executes ...
// Flag cleared automatically when _guard drops

```

## File Selection and Validation

The import process begins with the **`select_and_validate_audio_command`**, which opens a native file dialog via `tauri_plugin_dialog`. Selected files undergo rigorous validation through **`validate_audio_file`**:

- **Extension checking** against `AUDIO_EXTENSIONS` (MP4, WAV, MP3)
- **Size validation** enforcing a 20 GB maximum limit
- **Duration extraction** using a two-tier approach

For duration detection, the system first attempts **`extract_duration_from_metadata`** using the *symphonia* crate for fast metadata probing. If metadata is unavailable or corrupt, it falls back to a full decode pass, ensuring accurate duration reporting without unnecessary overhead for well-formed files.

## Meeting Folder Initialization and File Handling

Once validated, the pipeline creates a dedicated meeting folder under the user's recordings directory via **`create_meeting_folder`** (defined in [`audio/common.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/audio/common.rs)). This generates a unique subdirectory and initializes a placeholder [`metadata.json`](https://github.com/Zackriya-Solutions/meetily/blob/main/metadata.json) file.

The source audio file is then copied into this folder as `audio.<ext>` using **`std::fs::copy`** wrapped in **`spawn_blocking`**. This prevents the synchronous I/O operation from blocking the Tokio async runtime, maintaining UI responsiveness during large file transfers.

## Audio Decoding and Format Normalization

The copied file proceeds through **`decode_audio_file_with_progress`**, which reads the audio into an `AudioDecoded` struct containing sample rate, channel count, and duration. Progress callbacks emit Tauri events (`import-progress`) with the stage labeled "decoding".

Next, **`to_whisper_format_with_progress`** resamples the audio to Whisper-compatible specifications: **16 kHz sample rate** and **mono channel** format. This standardization ensures optimal transcription accuracy regardless of the source file's original specifications, with progress events emitted under the "resampling" stage.

## Voice Activity Detection and Segment Optimization

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

To prevent transcription truncation artifacts, the pipeline checks for segments exceeding **25 seconds**. Long segments are split at silence boundaries using **`split_segment_at_silence`** (located in [`audio/common.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/audio/common.rs)), optimizing chunk sizes for the transcription engine while preserving semantic boundaries.

## Transcription Engine Selection and Execution

Meetily supports dual transcription backends selected via the `provider` parameter:

- **`WhisperEngine`** — OpenAI's Whisper model, loaded lazily via `get_or_init_whisper`
- **`ParakeetEngine`** — NVIDIA's Parakeet model, initialized via `get_or_init_parakeet`

The chosen engine processes each speech segment asynchronously, returning transcribed text alongside confidence scores. The engine selection occurs at runtime, allowing users to choose between local Whisper inference or GPU-accelerated Parakeet processing without restarting the application.

## Data Persistence and Atomic Output

Successfully transcribed segments are aggregated into `TranscriptSegment` records by **`create_transcript_segments`** (shared utility in [`audio/common.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/audio/common.rs)). The system calculates average confidence scores across all segments to provide an overall quality metric.

Database persistence occurs through **`create_meeting_with_transcripts`**, which executes within a single SQLite transaction using `sqlx`. This ensures atomicity—either the meeting and all transcripts commit together, or the entire operation rolls back on failure.

File outputs use atomic write patterns to prevent corruption:

- **`write_transcripts_json`** and **`write_import_metadata`** create temporary files first
- Upon successful write, files are renamed to [`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)
- This prevents partial JSON files from persisting if the application crashes during I/O

## Frontend Integration and Progress Monitoring

Throughout the pipeline, **`emit_progress`** dispatches Tauri events to the frontend, enabling real-time progress bars. The UI receives `import-progress` events containing:
- `stage`: "copying", "decoding", "resampling", "vad", "transcribing", or "saving"
- `progress_percentage`: 0-100 integer
- `message`: Human-readable status description

Completion triggers an `import-complete` event with the meeting ID and processing statistics. Errors emit `import-error` with diagnostic details, while non-fatal warnings (such as "no speech detected") propagate via `import-warning` events.

Cancellation is supported through **`cancel_import_command`**, which sets `IMPORT_CANCELLED`. Pipeline stages check this flag at safe boundaries, aborting execution and cleaning up the temporary meeting folder if the user requests termination.

### Frontend Implementation Example

To initiate an import from TypeScript:

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

await invoke('start_import_audio_command', {
  sourcePath: '/Users/alice/Downloads/meeting.mp4',
  title: 'Quarterly Review',
  language: 'en',
  model: undefined,      // Use default model
  provider: 'whisper',   // or 'parakeet'
});

```

Listen for progress updates:

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

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

```

Cancel an ongoing import:

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

```

## Summary

- Meetily's import feature converts external audio files into structured meetings using a staged pipeline implemented in **[`frontend/src-tauri/src/audio/import.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/import.rs)**.
- The system enforces **20 GB file limits**, validates formats, and extracts duration using *symphonia* metadata probing with fallback decoding.
- Audio processing includes **16 kHz mono resampling**, **2000 ms VAD redemption time**, and intelligent splitting of segments exceeding **25 seconds**.
- Users can select between **Whisper** and **Parakeet** transcription engines, with lazy initialization and confidence scoring.
- All operations are **cancellable** via global flags, **progress-tracked** through Tauri events, and **atomically persisted** to SQLite and JSON files.

## Frequently Asked Questions

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

Meetily supports MP4, WAV, and MP3 files through the `AUDIO_EXTENSIONS` validation check in `validate_audio_file`. The system uses the *symphonia* crate for format-agnostic metadata extraction and can handle various codecs within these containers, falling back to full decode analysis when metadata probes fail.

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

Files up to **20 GB** are supported. The pipeline uses **`spawn_blocking`** to wrap `std::fs::copy` operations, preventing synchronous I/O from blocking the async runtime. Decoding and resampling occur in streaming fashion with progress callbacks, ensuring the UI remains responsive even when processing multi-hour recordings.

### Can I cancel an audio import after it has started?

Yes. The frontend can invoke **`cancel_import_command`**, which sets the global `IMPORT_CANCELLED` atomic flag. The pipeline checks this flag between stages (copying, decoding, VAD, transcription), aborts cleanly, and removes the partially created meeting folder. The `ImportGuard` RAII type ensures the `IMPORT_IN_PROGRESS` flag clears automatically regardless of cancellation or panic.

### What is the difference between the Whisper and Parakeet transcription providers?

**Whisper** (OpenAI) runs via `WhisperEngine` and provides robust general-purpose transcription suitable for most use cases. **Parakeet** (NVIDIA) runs via `ParakeetEngine` and leverages GPU acceleration for potentially faster inference on compatible hardware. Both engines implement the same async trait interface and return confidence scores, allowing seamless substitution via the `provider` parameter without changing the pipeline logic.