miniaudio_player banner

miniaudio_player

pub package License: MIT Platform Dart FFI Tests

An ultra-low-resource, high-performance cross-platform audio player and DSP engine for Flutter and Dart. Powered by the industry-standard miniaudio C engine, Sonic DSP, and Dart Native Assets with 100% pure FFI bindings.

Engineered from the ground up for professional electroacoustic fidelity, sub-millisecond command latency, deterministic real-time execution ($\mathcal{O}(1)$), and zero UI stutter by leveraging miniaudio's dedicated real-time native OS audio threads.


miniaudio_player - Audio Player Controls
miniaudio_player - Real-Time Reactive Visualizer


✨ Features at a Glance

  • ⚑ Strict Real-Time Determinism ($\mathcal{O}(1)$) & Zero Allocations: Direct native C memory management guarantees 0 dynamic heap allocations in the real-time audio thread, ensuring completely glitch-free audio playback even under intense UI activity or system load.
  • πŸ”€ 100% Pure FFI & Zero-Isolate Architecture: Commands execute directly via FFI in sub-microseconds without message-passing latency or Dart VM isolate memory bloat. Automatic resource management via NativeFinalizer prevents native memory leaks.
  • πŸ›‘οΈ Hardware-Grade Output Limiter (True-Peak Soft-Knee): True-Peak brickwall limiter operating before DAC handoff. Mathematically transparent in the linear zone ($|x| \le 0.95$ FS) with 0.00000% THD and 141.4 dB SNR, smoothly compressing digital overshoots (+3.5 dBFS capped safely at 0.996 FS) to eliminate digital clipping.
  • 🎧 Binaural Headphone Crossfeed (Bauer bs2b): Acoustic speaker crosstalk emulation for fatigue-free headphone listening with standard Moffat-Bauer and Chu Moy presets.
  • πŸŽ›οΈ Standard ISO 266 10-Band Parametric Equalizer: Native Direct Form II Transposed (DF2T) biquad cascade centered at standard preferred 1/1 octave frequencies (31Hz to 16kHz) with analytical RBJ curves (0.00 dB analytical error) and built-in acoustic presets (Rock, Pop, Jazz, Classical, Bass Boost, Flat).
  • πŸ“ˆ Real-Time Reactive Visualizer & Spectrum Analyzer: 10-band hardware BPF filter bank embedded directly in the native C playback pipeline matching the ISO 266 equalizer, stereo VU meters (L/R), RMS, and peak metrics (< 0.5% CPU active, 0% idle CPU via automatic on-demand streaming at ~30 fps).
  • πŸ”‡ Dynamic Silence Skipping & Edge Trimming: Native C real-time silence detector upstream of time-stretching and EQ. Trims lead-in/lead-out silence for gapless music and dynamically skips conversational pauses for podcasts and audiobooks with a 5ms anti-click crossfade ramp and cumulative saved time tracking.
  • 🎚️ Mono Downmix, Channel Balance & Stereo Spatializer: Built-in channel routing for mono accessibility, precision stereo balance panning, and stereo field widening.
  • πŸ“Š Unified Single-Pass Audio Analysis (Loudness, ReplayGain & Waveform): High-speed, non-blocking offline analysis in a single decoding pass on background native C OS threads (< 100 KB constant RAM). Computes ITU-R BS.1770-4 / EBU R128 loudness (LUFS), true peak, recommended gain (dB), anti-clipping defense, and normalized amplitude waveform points for UI seekbars without spawning Dart Isolates or freezing Flutter frames.
  • πŸš€ High-Definition Pitch & Speed (Sonic DSP): Real-time time-stretching and independent pitch shifting (0.25x to 4.0x rate, 0.5x to 2.0x pitch) with pristine acoustic clarity and seamless rate transitions.
  • πŸ”Œ Dynamic Audio Device Routing: Real-time switching between audio output endpoints (speakers, wired headphones, Bluetooth A2DP/SCO) with automatic hotplug detection and seamless reconnection recovery across all supported platforms.
  • 🌐 Background Playback & Standalone Isolate Support: Fully compatible with background audio services (e.g. audio_service, flutter_background_service) and standalone Dart isolates thanks to a 100% pure FFI design.
  • πŸ“¦ Extensive Audio Codec Support: Built-in native decoding for MP3, WAV, FLAC, OGG, Opus, AAC, M4A (AAC & ALAC), AIFF, W64, and more without external system dependencies.
  • πŸ”„ Dual State Paradigm: Access synchronous instant state snapshots (player.state.*) or listen to reactive broadcast streams (player.stream.*).

πŸš€ Performance & Architecture

1. Audio DSP Processing Chain

The native DSP pipeline inside ma_equalizer_node_process_pcm_frames is ordered strategically to maximize signal-to-noise ratio, minimize phase distortion, and guarantee headroom before final DAC output:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                                Audio PCM Frames In                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                            β”‚
                                            β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚    1. Preamp & ReplayGain Volume Ramping      β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                            β”‚
                                            β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚       2. Stereo Balance / Panning Pan         β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                            β”‚
                                            β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚          3. Mono Downmixing (Optional)        β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                            β”‚
                                            β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚     4. Binaural Crossfeed (Bauer bs2b)        β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                            β”‚
                                            β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚         5. Stereo Spatializer / Widener       β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                            β”‚
                                            β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚  6. 10-Band Biquad Cascade SIMD (DF2T, RBJ)   β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚                               β”‚
                            β–Ό                               β–Ό
      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
      β”‚  7. Visualizer Tap (10-Band BPF)  β”‚   β”‚  8. Master Volume Fader   β”‚
      β”‚     (On-Demand Seqlock Telemetry) β”‚   β”‚     (Steady-State Bypass) β”‚
      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                            β”‚
                                                            β–Ό
                                      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                      β”‚ 9. True-Peak Soft-Knee Limiter    β”‚
                                      β”‚    (Branchless SSE/NEON Safeguard)β”‚
                                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                            β”‚
                                                            β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                             Hardware Audio DMA Output                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Multi-Threaded Lock-Free Architecture

Unlike traditional plugins that hop through platform channels with UI thread contention and serialization overhead, miniaudio_player separates execution across three fully decoupled asynchronous domains:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                             Flutter UI / Dart Main Thread                              β”‚
β”‚  β€’ Sub-microsecond direct FFI invocations (< 1 Β΅s latency)                             β”‚
β”‚  β€’ Reactive broadcast telemetry streams (player.stream.*)                              β”‚
β”‚  β€’ Automatic memory cleanup via NativeFinalizer (Finalizable)                          β”‚
β”‚  β€’ Single-call atomic status snapshot (miniaudio_player_get_status)                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–²β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚ Commands                               β”‚ Seqlock Telemetry
                        β”‚ (play, seek, eq...)                    β”‚ (Atomic 56-byte snapshot)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚     C Background Decoder Worker Thread         β”‚   β”‚   RT Audio Device Callback Thread β”‚
β”‚  β€’ Asynchronous multi-codec file decoding      β”‚   β”‚  β€’ High-priority OS real-time RT  β”‚
β”‚  β€’ FTZ/DAZ denormal purging (map_disable_...)  β”‚   β”‚  β€’ 0 heap allocations (O(1))      β”‚
β”‚  β€’ Sonic varispeed with 64K frame headroom     β”‚   β”‚  β€’ Lock-free SPSC ring buffer readβ”‚
β”‚  β€’ Pre-faulted cache-aligned buffers (64B)     β”‚   β”‚  β€’ Complete DSP processing chain  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚  β€’ Branchless True-Peak limiter   β”‚
                        β”‚ SPSC Commit                β”‚  β€’ Seqlock write (< 2 cycles)     β”‚
                        β–Ό                            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚ Lock-Free SPSC Ring Bufferβ”‚
          β”‚ (64-byte Cache-Line Split)β”‚
          β”‚ worker_is_sleeping flag   β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. Zero UI Thread Blocking: All decoding, Sonic time-stretching, equalizer filtering, and audio output run on dedicated native OS audio threads with real-time priority. Commands (play, pause, seek, setVolume, setEqualizer) execute in sub-microseconds without dropping Flutter frames.
  2. Zero Dynamic Memory Allocations in RT: Real-time audio callbacks operate in $\mathcal{O}(1)$ time without calling malloc, free, or OS memory allocators.
  3. Lock-Free Seqlock Synchronization: Telemetry data (visualizer, VU levels, position) is written atomically inside a minimal 56-byte critical section (< 2 CPU cycles) with explicit hardware memory barriers (DMB ISH on ARM, compiler fences on x86 TSO).
  4. Priority Inversion Protection: The RT thread signals the decoder worker via atomic flag check (worker_is_sleeping) with hysteresis, completely bypassing POSIX mutex acquisitions.

3. Low-Level Platform Engineering & Microarchitecture

For systems engineers, embedded developers, and performance specialists, miniaudio_player incorporates enterprise-grade low-level optimizations across target operating systems and CPU architectures:

  • Android 15+ 16 KB ELF Page Alignment:
    • Enforces -Wl,-z,max-page-size=16384 link flags via Dart Native Assets (hook/build.dart) to comply strictly with Android 15's mandatory 16 KB kernel memory page requirements.
    • Generates optimized ARM NEON vfpv4 vectorization on 32-bit ARM (armeabi-v7a) and AArch64 SIMD instructions on 64-bit devices.
  • Pure C JNI Android Bridge (Zero MethodChannels & Zero Kotlin):
    • Interfaces directly with Android's AudioManager and AudioDeviceInfo using an autonomous embedded C JNI bridge.
    • Requires zero Kotlin code in MainActivity.kt and eliminates Flutter MethodChannel IPC bottlenecks.
    • Autonomous 6-tier JavaVM discovery across Android API 21 through 35+ (via JNI_OnLoad, libnativehelper.so, libart.so, and dl_iterate_phdr linker memory traversal).
    • Acquires application context via reflection on ActivityThread.currentApplication(), enabling headless background execution.
    • Automatically handles AAUDIO_SERVICE_EVENT_DISCONNECTED (-899) route changes during Bluetooth hotplug events without audio stalls.
  • Windows WASAPI MMCSS Pro Audio & 1 ms High-Precision Timers:
    • Automatically registers audio threads with the Windows Multimedia Class Scheduler Service (MMCSS) via AvSetMmThreadCharacteristicsA("Pro Audio") for guaranteed real-time scheduling priority.
    • Enforces 1 ms Win32 timer resolution using timeBeginPeriod(1) (and clean release via timeEndPeriod(1)), eliminating decoder starvation caused by default 15.6 ms Windows sleep jitter.
  • Universal Hardware FTZ/DAZ Denormal Mitigation:
    • Systematically executes map_disable_denormals() on all worker and real-time audio threads.
    • Configures Flush-to-Zero (FTZ) and Denormals-are-Zero (DAZ) bits directly in CPU control registers (x86/x86_64 MXCSR 0x8040, ARM64 FPCR, ARMv7 FPSCR, and MSVC _controlfp_s).
    • Completely prevents 100x CPU penalties and audio glitching during decaying IIR filter tails.
  • Microarchitectural Concurrency & Atomic Memory Barriers:
    • Weak memory model support on ARM64/ARMv7: explicit hardware release (DMB ISH) and acquire (DMB ISHLD) barriers, plus pipeline yield instructions (isb; yield).
    • Total Store Order (TSO) on x86/x86_64: pure compiler barriers (__atomic_thread_fence / _ReadWriteBarrier), eliminating bus-locking _mm_mfence instructions and saving 30–100 CPU cycles per read.
    • Lock-free Seqlock (src/map_seqlock.h): pre-check backoff loop and local staging struct, reducing the writer critical section to a single atomic 56-byte snapshot (< 2 CPU cycles), certified over 35+ million concurrent contention reads.
  • Strict Real-Time Determinism & Zero Heap Allocations:
    • Audio callback runs in $\mathcal{O}(1)$ time with 0 dynamic heap allocations, empirically verified via memory interceptor wrappers (--wrap=malloc/calloc/realloc/free).
    • Cache-line 64-byte alignment (MAP_ALIGN_CACHE_LINE, ma_aligned_malloc) preventing multi-core false sharing on ring buffer cursors.
    • Contiguous 64-frame SIMD processing with delay registers ($s_1, s_2$) hoisted into CPU vector registers.

πŸ“Š Platform Support Matrix

Audio Player Capability Android ^1 Windows ^2 Linux iOS macOS
Native Audio Backend AAudio / OpenSL ES WASAPI Pro Audio PulseAudio / ALSA CoreAudio CoreAudio
Playback & Streaming βœ… βœ… βœ… βœ… βœ…
10-Band Equalizer (ISO 266) βœ… βœ… βœ… βœ… βœ…
True-Peak Limiter (Soft-Knee) βœ… βœ… βœ… βœ… βœ…
Binaural Crossfeed (Bauer bs2b) βœ… βœ… βœ… βœ… βœ…
Mono Downmix & Stereo Balance βœ… βœ… βœ… βœ… βœ…
Stereo Spatializer / Widener βœ… βœ… βœ… βœ… βœ…
Real-Time Reactive Visualizer βœ… βœ… βœ… βœ… βœ…
Silence Detection & Skipping βœ… βœ… βœ… βœ… βœ…
Audio Analysis (LUFS & Waveform) βœ… βœ… βœ… βœ… βœ…
Speed & Pitch Scaling (Sonic DSP) βœ… βœ… βœ… βœ… βœ…
Dynamic Device Routing βœ… βœ… βœ… βœ… βœ…
Background Playback & Isolates βœ… βœ… βœ… βœ… βœ…

^1: Android: Device discovery uses an autonomous pure C JNI bridge with zero MethodChannels and no Kotlin glue code. Binaries are compiled with -Wl,-z,max-page-size=16384 for Android 15+ 16 KB memory page compatibility and ARM NEON SIMD.

^2: Windows: Audio threads automatically engage MMCSS Pro Audio real-time scheduling (AvSetMmThreadCharacteristicsA) and 1 ms high-precision timer resolution (timeBeginPeriod(1)).


πŸ“¦ Supported Audio Formats

Format Extensions Decoding Backend
MPEG Audio .mp3, .mp2, .mp1 Native miniaudio (dr_mp3)
Waveform Audio .wav, .bwf, .rifx, .w64, .rf64 Native miniaudio (dr_wav)
FLAC .flac Native miniaudio (dr_flac)
Ogg Vorbis .ogg, .oga Native miniaudio (stb_vorbis)
Opus .opus Native Opus decoder (libopus)
Apple Lossless / AAC .m4a, .aac Native ALAC / Helix AAC
Audio Interchange .aif, .aiff, .aifc Native miniaudio

πŸ› οΈ Getting Started

Add miniaudio_player to your pubspec.yaml:

flutter pub add miniaudio_player

Or for pure Dart projects:

dart pub add miniaudio_player

πŸ’» Usage Examples

1. Basic Playback & Global Configuration

Basic Audio Playback Controls

import 'package:miniaudio_player/miniaudio_player.dart';

void main() async {
  // Optional: configure global defaults before instantiating players
  MiniaudioPlayer.config(
    defaultBufferSize: 0, // 0 = native device default
    logLevel: MiniaudioLogLevel.info,
  );

  final player = MiniaudioPlayer();

  // Open an audio file and start playback immediately
  await player.action.open('/path/to/song.flac', autoPlay: true);

  // Playback controls
  await player.action.pause();
  await player.action.play();
  await player.action.seek(const Duration(seconds: 45));
  await player.action.setVolume(0.85);

  // Clean up resources when finished (also safely garbage collected via NativeFinalizer)
  await player.dispose();
}

2. Complete DSP Chain (Limiter, Crossfeed, Mono, Balance & Spatializer)

Complete DSP Chain - Limiter, Crossfeed, Mono, Balance & Spatializer

// 1. Hardware Output Limiter (True-Peak soft-knee protection against digital clipping)
await player.action.setLimiter(true);

// 2. Binaural Crossfeed (Bauer bs2b: reduces headphone fatigue)
await player.action.setCrossfeed(CrossfeedMode.moffatBauer); // or CrossfeedMode.chuMoy

// 3. Mono Downmixing (for single speakers or accessibility)
await player.action.setMono(true);

// 4. Stereo Balance Panning (-1.0 full left, 0.0 center, +1.0 full right)
await player.action.setBalance(-0.25);

// 5. Stereo Spatializer (widens the acoustic stereo image)
await player.action.setSpatializer(enabled: true, width: 1.4);

// 6. Preamp Gain & ReplayGain Normalization with anti-clipping defense
await player.action.setPreamp(2.0); // +2.0 dB manual preamp
await player.action.setReplayGain(
  gainDb: -4.5,
  peak: 0.98,
  preampDb: 0.0,
  preventClipping: true,
);

3. Standard ISO 266 10-Band Parametric Equalizer

Shape frequency response in real time across the 10 ISO 266 standard octave bands (31Hz, 63Hz, 125Hz, 250Hz, 500Hz, 1kHz, 2kHz, 4kHz, 8kHz, 16kHz) from -24.0 dB to +24.0 dB:

Standard ISO 266 10-Band Parametric Equalizer

// Apply built-in acoustic presets
await player.action.setEqualizer(Equalizer.rock);
await player.action.setEqualizer(Equalizer.bassBoost);
await player.action.setEqualizer(Equalizer.jazz);
await player.action.setEqualizer(Equalizer.classical);
await player.action.setEqualizer(Equalizer.pop);
await player.action.setEqualizer(Equalizer.flat);

// Or create a custom equalizer configuration
final customEq = Equalizer(
  hz31: 4.5,   // Sub-bass boost (low-shelf)
  hz63: 3.0,   // Warmth
  hz125: 1.5,
  hz250: 0.0,
  hz500: -1.0,
  hz1k: -0.5,  // Tame mid-range harshness
  hz2k: 1.0,
  hz4k: 2.5,   // Presence
  hz8k: 3.5,   // Treble air
  hz16k: 4.0,  // High-shelf sparkle
);
await player.action.setEqualizer(customEq);

4. Real-Time Reactive Visualizer & Spectrum Analyzer

Build dynamic spectrum analyzers, frequency visualizers, and stereo VU meters. Subscribing to the stream automatically enables native C filtering, and unsubscribing keeps idle CPU strictly at 0%:

Real-Time Reactive Visualizer - 10-Band BPF Filter Bank & Stereo VU Meters

// 1. Listen to real-time visualizer data (~30 fps updates)
final subscription = player.stream.visualizer.listen((data) {
  // 10 frequency bands (0.0 to 1.0) matching the 10-band equalizer:
  print('Sub-bass (31Hz): ${data.hz31}');
  print('Midrange (1kHz): ${data.hz1k}');
  print('Treble (16kHz):  ${data.hz16k}');

  // Stereo channel amplitudes:
  print('VU Left: ${data.left}, VU Right: ${data.right}');

  // Global energy metrics:
  print('RMS: ${data.rms}, Peak: ${data.peak}');
});

// 2. Synchronous snapshot access:
final current = player.state.visualizer;
print('Current spectrum: ${current.bands}');

// 3. Stop observing: native DSP filtering stops automatically (0% idle CPU)
await subscription.cancel();

5. Native Silence Detection & Dynamic Skipping

Eliminate pauses and silent gaps in real time without audio glitches or pops, protected by a smooth 5ms anti-click crossfade:

Smart Silence Skipping Controls

// 1. Quick enable with standard defaults (-45 dB threshold, 300ms min silence, 50ms padding)
await player.action.setSkipSilence(true);

// 2. Podcast & Audiobook mode: skips in-between speech pauses
await player.action.setSilenceConfig(
  const SilenceSkipConfig.continuous(
    thresholdDb: -45.0,
    minSilenceDuration: Duration(milliseconds: 300),
    padding: Duration(milliseconds: 50),
  ),
);

// 3. Music Album mode: trims lead-in and lead-out silence only
await player.action.setSilenceConfig(
  const SilenceSkipConfig.trimEdges(thresholdDb: -50.0),
);

// 4. Combined mode: trims edges AND skips continuous pauses
await player.action.setSilenceConfig(const SilenceSkipConfig.all());

// 5. Track accumulated saved time synchronously or reactively:
print('Total time saved: ${player.state.silenceSavedDuration.inSeconds}s');

player.stream.silenceSavedDuration.listen((saved) {
  print('Saved time updated: ${saved.inMilliseconds} ms');
});

6. Unified Single-Pass Audio Analysis (Loudness & Waveform)

Analyze a track's acoustic properties, ITU-R BS.1770-4 / EBU R128 loudness, and visual waveform envelope in a single decoding pass on a background native OS worker thread (zero Dart Isolates, 0 ms UI blocking, preserving 60/120 fps):

Unified Audio Analysis - Waveform & ReplayGain

// 1. Non-blocking asynchronous analysis (native background OS thread)
final analysis = await MiniaudioPlayer.analyzeAudio(
  '/path/to/song.flac',
  replayGain: true,       // Loudness analysis
  waveform: true,         // Waveform envelope extraction
  waveformPoints: 100,    // Number of points to extract
  targetLufs: -18.0,      // Reference loudness (-18.0 ReplayGain, -14.0 streaming)
);

// 2. Fundamental audio metrics:
print('Duration: ${analysis.duration}');
print('Sample Rate: ${analysis.sampleRate} Hz');
print('Channels: ${analysis.channels}');
print('Bitrate: ${analysis.bitrate ~/ 1000} kbps');
print('True Peak: ${analysis.peak}');

// 3. ReplayGain & Volume Normalization:
if (analysis.replayGain != null) {
  final rg = analysis.replayGain!;
  print('Integrated Loudness: ${rg.lufs} LUFS');
  print('Recommended Gain: ${rg.gainDb} dB');

  // Convert to linear volume with built-in anti-clipping defense:
  final linearVolume = rg.getRecommendedVolume(preventClipping: true);
  await player.action.setVolume(linearVolume);
}

// 4. Waveform seekbar rendering:
if (analysis.waveform != null) {
  final wf = analysis.waveform!;
  print('Waveform points (${wf.length}): ${wf.points}');

  // Sample height at 50% progress or at current playback position:
  final midHeight = wf.getPointAtProgress(0.5); // 0.0 to 1.0
  final currentHeight = wf.getPointAtPosition(player.state.position, analysis.duration);
}

Note: For CLI tools or batch preprocessing scripts, use the synchronous variant: MiniaudioPlayer.analyzeAudioSync(...).


7. Audio Output Device Selection & Dynamic Routing

Enumerate and switch hardware audio devices dynamically at runtime across Android, Windows, Linux, macOS, and iOS with zero configuration and no MethodChannels:

Hardware Audio Output Device & Buffer Size Selection

// 1. Enumerate available audio playback devices
final devices = await MiniaudioPlayer.getAudioDevices();

for (final device in devices) {
  // Use device.displayName directly in UI selectors (DropdownButton, ListTile)
  print('Device: ${device.displayName} (ID: ${device.id})');
}

// 2. Switch playback to a specific hardware output
await player.action.setDevice(devices[1]);

// 3. Return to automatic system default routing
await player.action.setDevice(AudioDevice.auto);

// 4. Listen to native device hotplug and route changes:
MiniaudioPlayer.getAudioDevicesStream().listen((updatedDevices) {
  print('Device list updated: ${updatedDevices.length} devices found');
});

Flutter UI Dropdown Binding with Localized Labels

// Optional: configure localized display name resolver globally
MiniaudioPlayer.config(
  defaultDeviceDisplayNameResolver: (resolvedName) =>
      resolvedName.isEmpty ? 'Predeterminado' : 'Predeterminado ($resolvedName)',
);

// Bind directly to Flutter DropdownButton:
DropdownButton<AudioDevice>(
  value: player.state.audioDevice,
  items: devices.map((device) {
    return DropdownMenuItem(
      value: device,
      child: Text(device.displayName),
    );
  }).toList(),
  onChanged: (newDev) {
    if (newDev != null) player.action.setDevice(newDev);
  },
)

8. Reactive Streams & Synchronous State

miniaudio_player offers both real-time broadcast streams and synchronous getters for effortless UI binding:

// Synchronous snapshot access:
print('Is Playing: ${player.state.playing}');
print('Current Position: ${player.state.position}');
print('Track Duration: ${player.state.duration}');
print('Bitrate: ${player.state.audioBitrate} kbps');
print('Active Device: ${player.state.audioDevice.displayName}');
print('Limiter Enabled: ${player.state.limiterEnabled}');

// Reactive broadcast streams:
player.stream.position.listen((pos) => print('Position: $pos'));
player.stream.playing.listen((playing) => print('Playing: $playing'));
player.stream.completed.listen((done) => print('Playback finished!'));
player.stream.equalizer.listen((eq) => print('Equalizer updated: $eq'));
player.stream.audioDevice.listen((dev) => print('Device switched: ${dev.displayName}'));

Using with Flutter StreamBuilder:

StreamBuilder<Duration>(
  stream: player.stream.position,
  builder: (context, snapshot) {
    final position = snapshot.data ?? Duration.zero;
    final total = player.state.duration;
    return Text('${position.inMinutes}:${(position.inSeconds % 60).toString().padLeft(2, '0')} / '
                '${total.inMinutes}:${(total.inSeconds % 60).toString().padLeft(2, '0')}');
  },
)

9. High-Fidelity Speed & Pitch Control (Sonic DSP)

Playback Adjustments - Volume, Rate & Pitch Control

// Playback rate: 0.25x (slow) to 4.0x (fast) without changing pitch
await player.action.setRate(1.5);

// Pitch scaling: 0.5x to 2.0x without changing playback speed
await player.action.setPitch(1.2);

10. Optional: Running Inside a Background Isolate

Because miniaudio_player uses 100% pure Dart FFI without platform channel restrictions, it can be instantiated inside a standalone background Dart Isolate or headless background service (audio_service, flutter_background_service, Isolate.spawn):

import 'dart:isolate';
import 'package:miniaudio_player/miniaudio_player.dart';

void audioWorkerIsolate(SendPort sendPort) async {
  final commandPort = ReceivePort();
  sendPort.send(commandPort.sendPort);

  final player = MiniaudioPlayer();

  player.stream.position.listen((pos) {
    sendPort.send({'event': 'position', 'value': pos.inMilliseconds});
  });

  player.stream.completed.listen((done) {
    if (done) sendPort.send({'event': 'completed'});
  });

  await for (final message in commandPort) {
    if (message is Map) {
      switch (message['command']) {
        case 'open':
          await player.action.open(message['path'] as String, autoPlay: true);
          break;
        case 'pause':
          await player.action.pause();
          break;
        case 'resume':
          await player.action.play();
          break;
        case 'stop':
          await player.action.stop();
          break;
        case 'dispose':
          await player.dispose();
          commandPort.close();
          return;
      }
    }
  }
}

🀝 Contributing

Contributions, bug reports, and feature requests are very welcome!
Feel free to open an issue or submit a pull request on GitHub.


πŸ“„ License & Third-Party Acknowledgements

This project is licensed under the MIT License - see the LICENSE file for complete details.

Third-Party Native Libraries & Decoders

miniaudio_player bundles and links specialized native C libraries to provide out-of-the-box decoding and DSP without external system dependencies. Each component remains governed by its respective author's license:

Component Author / Organization License Source Location Description
miniaudio David Reid Choice of Public Domain or MIT-0 src/miniaudio.h Audio engine, OS device routing, mixing, and built-in decoders (dr_mp3, dr_wav, dr_flac).
Sonic DSP Bill Cox Apache License 2.0 src/sonic/ Real-time high-fidelity time stretching and pitch scaling.
minimp4 lieff, aspt CC0 1.0 Universal (Public Domain) src/decoders/minimp4/ Lightweight MP4 / M4A ISO container demuxer.
ALAC Decoder David Hammerton MIT License src/decoders/alac/ Apple Lossless Audio Codec (ALAC) frame decoder.
stb_vorbis Sean Barrett Public Domain / MIT src/decoders/stb_vorbis.c Ogg Vorbis audio decoding backend.
libogg Xiph.Org Foundation BSD 3-Clause src/decoders/libogg/ Ogg container bitstream and framing parsing.
libopus (Opus & SILK) Xiph.Org Foundation, Skype Limited, Arm Limited BSD 3-Clause src/decoders/libopus/ High-definition Opus audio decoding pipeline.
Helix AAC Decoder RealNetworks, Inc. RealNetworks Public Source License (RPSL v1.0) src/decoders/helix-aac/ Fixed-point HE-AAC audio decoder.

βš–οΈ Permissive Licensing & Commercial Use

  • Unrestricted Commercial & Proprietary Usage: Because miniaudio_player is distributed under the permissive MIT License, you are completely free to integrate, bundle, and distribute it in commercial, closed-source, proprietary, or open-source Flutter applications without copyleft restrictions.
  • Third-Party Attribution: All bundled third-party libraries retain their original author notices, copyrights, and permissive licenses (MIT, MIT-0, Apache 2.0, BSD-3-Clause, CC0, and RPSL).

Libraries

miniaudio_player
Ultra-low-resource cross-platform audio player using miniaudio and Sonic DSP via Dart Native Assets.
miniaudio_player_bindings_generated