Cloud transcription is convenient until you have a recording you'd rather not upload: a lecture, a client call, a voice note. So I built Extracter , an open-source Flutter app that turns any audio or video file into text entirely on the device. No account, no analytics, and no network at all once a model is downloaded.
It runs on Android, iOS and macOS today (Windows and Linux build scripts exist but haven't been tested yet). This post walks through how it works, and the one native bug that taught me more about Dart isolates than any documentation.
The architecture
audio/video file → FFmpeg (decode-only) → 16 kHz mono PCM → whisper.cpp → segments → Flutter UI
Enter fullscreen mode
Exit fullscreen mode
The heavy lifting lives in a small FFI plugin, extracter_native , with one C ABI shared by every platform:
ex_job_start(media, model, language, translate, threads) starts a job on a native worker thread and returns an id.
ex_job_cancel(id) is idempotent.
The worker posts events back to Dart: progress,…