audio_flutter_linux 0.1.0
audio_flutter_linux: ^0.1.0 copied to clipboard
Linux implementation of audio_flutter capture and PCM playback over PulseAudio and PipeWire.
audio_flutter_linux #
Linux implementation of the audio_flutter platform contract: microphone and
system-audio capture, plus PCM playback, over the PulseAudio/PipeWire
command-line tools.
The package contains no native code. Capture spawns parecord and falls
back to pw-record; playback spawns paplay and falls back to pw-play. Both
are asked for signed 16-bit little-endian PCM at the requested rate and channel
count, which this package converts to and from the float32 frames the contract
carries. Registration is dartPluginClass only — there is no C++ registrant to
build.
Targeting #
PulseAudio exposes one flat source namespace: hardware inputs
(alsa_input.*) and sink monitors (alsa_output.*.monitor) are both sources
addressable by name. PlatformCaptureRequest.inputDeviceId therefore carries a
PulseAudio source name for both capture kinds:
| Capture kind | inputDeviceId set |
inputDeviceId null |
|---|---|---|
microphone |
that source is recorded | the tool's own default input |
systemAudio |
that source is recorded (normally a .monitor) |
the default sink's monitor, resolved with pactl get-default-sink |
No new request field was added: a separate sourceId would duplicate
inputDeviceId on a platform where both kinds address the same namespace, and
it would collide in name with PlatformCaptureSessionInfo.sourceId, which
already means something else.
listAudioInputDevices() returns the non-monitor sources.
listSystemAudioSources() — a Linux-only addition, not part of the platform
contract — returns the monitors, so a UI can offer them for selection.
PlatformCaptureRequest.processIds has no Linux equivalent and is ignored;
listAudioProcesses() is always empty, because a monitor mixes a whole sink and
there is nothing analogous to a Core Audio per-process tap.
Permissions #
Linux has no system-audio permission gate: monitor sources are readable by any
client of the running sound server. isSystemAudioCaptureSupported() reports
whether a capture tool and pactl are installed, and
requestSystemAudioCapturePermission() mirrors it. Both answer "is the
mechanism present", never "did a user grant something".
Format support #
Formats map straight onto process arguments (--rate, --channels), so any
rate up to 192 kHz and up to 32 channels is accepted. Combinations PulseAudio
cannot express — or a frame duration too short to hold one whole sample frame —
are rejected from prepareCapture/preparePlayback with a
LinuxAudioFormatException rather than failing mid-capture.
Health #
captureEvents reports starting, then running with receivingAudio: true
once bytes actually arrive. A source that starts cleanly but delivers nothing
fails after two seconds with code SystemCaptureDead, matching the Darwin
watchdog. An unexpected tool exit fails with CaptureProcessExited and an
excerpt of the child's stderr. The child's stderr is always drained, because an
unread pipe fills its kernel buffer and blocks the process.
Backpressure #
readCaptureFrames pulls from a bounded ring sized by
maxBufferedDuration ÷ frameDuration, honouring every
PlatformCaptureOverflowPolicy. Frame sequence and sampleOffset are
assigned as audio is produced, so they keep advancing across drops and the
frame delivered after a gap reports droppedFramesBefore. Playback
backpressure is the child's stdin: every write awaits its flush.
Status #
Not yet validated against a real PulseAudio or PipeWire server. Every command line, parse, and lifecycle path is unit-tested through an injected process seam, and that suite runs on any host — but no audio has been captured or played on Linux hardware. Treat argument compatibility across PulseAudio and PipeWire versions, monitor availability, and end-to-end latency as unverified until that run happens.
Attribution #
Command assembly, pactl parsing, monitor resolution, the capture-tool
fallback order, and the always-drain-stderr rule are derived from Control
Center, MIT © 2026 Samuel Alev. See NOTICE.