NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev
Very simple interface to provide a stream of audio data for processing/visualising in Flutter
Last release 1 months ago
14 Aug 2026
Ships unpredictably
gaps range from 9 days to 2.5 years
Nearly every release is documented
notes for 29 of 29 stable releases
Nothing withdrawn
no release was ever pulled
7 years old
29 releases · first in 2020
One column per quarter.
Web: fixed system/tab audio capture breaking against newer package:web versions — the plugin's local getDisplayMedia interop extension could collide w
package:web
versions — the plugin's local getDisplayMedia interop extension could
collide with the instance member declared by newer typed bindings, selecting
an incompatible method. The extension member is now bound explicitly via
@JS('getDisplayMedia') under a distinct Dart name (#50).AudioIoConfig now enforces its numeric field invariants in all build modes: outputBufferDuration must be a positive, finite number of seconds. Previou
AudioIoConfig now enforces its numeric field invariants in all build
modes: outputBufferDuration must be a positive, finite number of seconds.
Previously only a debug assert guarded it, which is stripped in
release/profile builds, so an out-of-range value (0, negative, NaN, infinity)
reached the native ring sizing and could cause a native crash or undefined
behaviour with no signal to the caller. AudioIo.startWith now throws an
ArgumentError for such values before the config reaches the engine
(mirroring the sample-rate-mismatch contract guard). Valid and null values
are unchanged (#9).startWith accepts any supported AudioIoSampleRate
on the web without throwing (the earlier allowSampleRateMismatch guard is
gone). Input PCM16 (inputBytes) is emitted at the requested rate and output
PCM16 (outputBytes) at the requested rate is up/downsampled to the browser
rate on the way to the speakers: the AudioWorklet converts between the
browser rate and the 48 kHz engine contract on the rendering thread and the
Dart Pcm16Adapters / PushResampler convert between the contract and the
requested rate. This landed with the asymmetric-rate work (#41); this change
adds regression tests that pin the web input/output resampling paths
(up/down/equal rate) so the acceptance criteria stay covered. Resolves #8.AudioIoConfig gains optional
inputSampleRate / outputSampleRate; each direction resamples to and from
the fixed 48 kHz engine contract independently, so callers can run e.g. a
16 kHz mic and a 24 kHz speaker (OpenAI Realtime / Gemini Live). sampleRate
is retained as a shorthand that sets both — either field falls back to it
when omitted, so existing single-rate callers are unchanged (#41).FlutterBinaryMessenger. AudioIoThreading.audioIsolate
now works on iOS and macOS (the transport can run off the root isolate);
previously Apple platforms silently fell back to the main isolate because
platform→Dart pushed channel messages only deliver to the root isolate. The
engine lifecycle (start/stop/permissions/latency/format) stays on the method
channel. Removed the input/output binary channels, the DataBufferPool, and
the main-thread dispatch and per-sample Float64 conversion from the realtime
sink render block — capture is now Float32 straight into a lock-free ring.
Public API unchanged.AudioIoConfig.inputSource: AudioIoInputSource.systemAudio captures the machine's audio mix instead
of the microphone. On the web this uses getDisplayMedia — startWith
triggers the browser share picker (Chromium only; Firefox/Safari return no
audio track and the input stream emits an AudioIoException with
isSystemAudioUnsupported). Clicking "Stop sharing" completes the input
stream. The example app gains a Microphone / System-audio toggle. Desktop
legs (Windows WASAPI loopback #33, macOS Core Audio taps #32) share the
same API.AudioIoConfig.outputBufferDuration (and
AudioIo.requestOutputBufferDuration) size the output ring in seconds of
the 48 kHz playback contract, independent of the frame duration / latency.
Latency-sensitive callers can cap queued output low so a barge-in
(clearOutput) drops less stale audio, while burst producers (e.g. Gemini
Live) can size it high enough that a multi-second response is not dropped.
Implemented on all back ends (iOS, macOS, web, and the FFI back ends —
Android, Windows, Linux, including the dedicated audio isolate). Each back
end enforces a small safety floor, so smaller values are clamped up. When
unset (the default) every back end keeps its existing sizing — no
behaviour change. Resolves #12.Web: microphone capture moved off the deprecated main-thread ScriptProcessorNode onto an input AudioWorkletProcessor that resamples to the 48 kHz cont…
AudioIoConfig.threading: AudioIoThreading.audioIsolate runs device polling and native buffer
copies on a spawned isolate on the FFI back ends (Android, Windows,
Linux), so audio transport is immune to main-isolate jank. The default
stays AudioIoThreading.mainIsolate and unsupported platforms fall back
to it; the Stream/Sink API still surfaces on the main isolate.outputBytes now happen inside the
output AudioWorklet on the audio rendering thread, and chunks cross to it
as transferable buffers instead of structured clones — the main-thread
cost per output chunk drops to one copy plus a postMessage, fixing
underruns under heavy UI load. Float64 output is likewise resampled in
the worklet.getFormat). Input delivery no longer boxes every
sample into a growable List<double>.start() was silently dropped.pcm16BytesToFloat64 / float64ToPcm16Bytes use typed-array views on
little-endian hosts instead of per-sample ByteData calls.ffiPlugin: true without a
pluginClass). The previous declaration referenced a Kotlin plugin class
that does not exist, which newer Flutter versions reject as a deleted
Android v1 embedding plugin. The plugin build also moved to
compileSdk 35 and no longer applies its own Kotlin plugin
(Flutter built-in Kotlin compatibility).Swift Package Manager support for the iOS and macOS plugins, alongside the existing CocoaPods support (no consumer changes required — apps keep using
ios/audio_io/Sources/audio_io/ and
macos/audio_io/Sources/audio_io/, with a Package.swift per platform. The
podspecs now reference the new source location, so both build systems work.AudioIoPlugin.h/.m) was removed and the iOS pluginClass is now
SwiftAudioIoPlugin (which already implemented register(with:)). No Dart
API changes.PCM16 streaming and configurable sample rates: new AudioIo.startWith taking an AudioIoConfig (AudioIoFormat.float64 / pcm16, AudioIoSampleRate.rate160
AudioIo.startWith
taking an AudioIoConfig (AudioIoFormat.float64 / pcm16,
AudioIoSampleRate.rate16000 / rate24000 / rate48000, latency
preset). The engine keeps its fixed 48 kHz contract internally; the new
byte streams are resampled to and from the requested rate, so callers can
work in the rate their API expects (e.g. 16 kHz in / 24 kHz out for
Gemini Live).AudioIo.inputBytes (Int16 little-endian PCM16 input
Stream<Uint8List>) and AudioIo.outputBytes (PCM16 output
Sink<Uint8List>), active after startWith with AudioIoFormat.pcm16.
Both are broadcast streams, so the adapters survive a stop -> startWith
restart (previously the single-subscription output controller threw
Bad state: Stream has already been listened to on the second
startWith).AudioIo.clearOutput(): discards audio queued for playback but not yet
rendered, for immediate barge-in / interruption handling. Wired across
the native (iOS/macOS/Android/desktop) and web back ends.AudioIo.currentConfig: the AudioIoConfig passed to the most recent
startWith, or null after start() / stop().macOS/iOS: the output source node is now pinned to the 48 kHz mono Float64 contract format instead of inheriting the INPUT device's sample rate. Previ
getFormat()
reports the real device rate under output.deviceSampleRate. The ring
is sized from the contract rate on every path (it previously shrank
after route changes), requestFrameDuration while running restarts the
engine instead of swapping the ring under the live render thread, the
iOS session preferred rate no longer drifts to the last input rate, the
input buffer pool is sized after the device rate is known and guarded
by os_unfair_lock instead of a render-thread DispatchQueue.sync,
and the engine-reconfiguration observer is scoped to this plugin's
engine.start() calls now share one start attempt (the web
fires a lifecycle resume on every window focus, which could race a
widget-init start into two AudioContexts and a StateError on the
second output listen); stop() waits for an in-flight start before
tearing down. getFormat() reports which output path is active under
output.backend (audioWorklet / scriptProcessor / inactive).AudioWorkletNode when available. The
worklet owns a ring buffer drained on the dedicated audio rendering
thread, so main-thread jank (heavy frames, GC pauses) can no longer
glitch playback. Pushed 48 kHz audio is resampled to the device rate on
the push path before being posted to the worklet. Browsers without
AudioWorklet fall back to the ScriptProcessor path below; microphone
input continues to use a (lazy, input-only) ScriptProcessorNode.removeAt(0) per
sample inside the audio callback) with an O(1) Float32List ring buffer,
and replaced per-sample JS interop with bulk copyToChannel /
typed-array copies. Fixes crackling and dropouts under load.getFormat() reports the device
rate under output.deviceSampleRate.input is listened to;
output-only apps no longer trigger a permission prompt.requestFrameDuration(double seconds) so clients can size
the native output ring buffer; the latency presets now route through it.Fixed compile error in resetAudio() caused by start() signature change
Bug Fix
Performance, Stability & Error Handling Update
Performance, Stability & Error Handling Update
Permission Handling:
Threading Fix:
API Additions:
Critical Memory Leak Fixes:
Performance Improvements:
Bug Fixes:
Platform Improvements:
Code Quality:
Diagnostics:
Added Android platform support using miniaudio C++ library via FFI
Multi-Platform Release
Platform Support:
Added macOS platform support with full audio input/output capabilities
Major Update
Small performance improvement Remove fonts from example Bump SDK version
Small performance improvement Remove fonts from example Bump SDK version
Fix dangling pointer
Fix dangling pointer
Performance improvement
Performance improvement
Cleanup Added null safety
Cleanup Added null safety
Bugfix Using detected input sample rate rather than fixed sample rate
Bugfix Using detected input sample rate rather than fixed sample rate
Bugfix Better way to detect changes in audio format, removed old methods
Bugfix Better way to detect changes in audio format, removed old methods
Bugfix Fixed issue with route swapping from speaker to headphones
Bugfix Fixed issue with route swapping from speaker to headphones
Bugfix Fix bug which stopped audio when coming back from background
Bugfix Fix bug which stopped audio when coming back from background
Performance Fixing Dart side audio format to double (everything is 64bit these days, 64bit is great for processing) Optimised data conversion
Performance Fixing Dart side audio format to double (everything is 64bit these days, 64bit is great for processing) Optimised data conversion
New Interface Added inteface for getting format and buffer size selection (audio frame size) Using serial queue for read and writes to buffer
New Interface Added inteface for getting format and buffer size selection (audio frame size) Using serial queue for read and writes to buffer
Improvement Handle audio interruptions Using simpler binary message system to send data (2x cpu optimisation) Replaced invoking method with binary mes
Improvement Handle audio interruptions Using simpler binary message system to send data (2x cpu optimisation) Replaced invoking method with binary message for output audio Less format conversions when sending data in and out Prep work for upcoming buffer and samplerate selection features
Improvement Handle audio session changes Reset audio when entering foreground
Improvement Handle audio session changes Reset audio when entering foreground
Rollback 0.0.6
Rollback 0.0.6
Improvement Main thread call for sink removed (attempt to reduce latency introduced in 0.0.5)
Improvement Main thread call for sink removed (attempt to reduce latency introduced in 0.0.5)
Bugfix Thread safety - memory leak fixed :)
Bugfix Thread safety - memory leak fixed :)
Improvement Allow muliple listeners on audio input
Improvement Allow muliple listeners on audio input
Bugfix Fix 32-64bit mismatch of data.
Bugfix Fix 32-64bit mismatch of data.
Input from mic at fixed sample rate and buffer size, output fixed at mono at the same sample rate as input. Simple quick and dirty ringbuffer for outp
Kiss MVP release
Input from mic at fixed sample rate and buffer size, output fixed at mono at the same sample rate as input. Simple quick and dirty ringbuffer for output (needs optimisation)
Kiss release Input from mic at fixed sample rate and buffer size, no output
Kiss release Input from mic at fixed sample rate and buffer size, no output
Your coding agent can read these notes before it upgrades. Set up the MCP server →