miniaudio_dart 1.0.5 copy "miniaudio_dart: ^1.0.5" to clipboard
miniaudio_dart: ^1.0.5 copied to clipboard

A high-level real-time audio playback library based on Miniaudio.

miniaudio_dart #

A implementation for miniaudio supporting native and web platforms.

pub package


Web setup #

Include the loader (do NOT defer) in web/index.html:

<script src="assets/packages/miniaudio_dart_web/js/miniaudio_dart_web.loader.js"></script>

Inside the onload bootstrap add:

await _miniaudio_dart.loader.load();

This package uses SharedArrayBuffer; enable cross‑origin isolation:

  • Cross-Origin-Opener-Policy: same-origin
  • Cross-Origin-Embedder-Policy: require-corp

Core concepts #

Component Purpose
Engine Playback device + sound management
Sound Decoded or raw PCM (supports loop + loop delay)
StreamPlayer Low latency push of Float32 interleaved frames
Recorder Capture microphone to ring buffer or file
Generator Procedural waveform / noise source

New / changed APIs (device + stream management) #

Playback (output) devices #

await engine.enumeratePlaybackDevices();                // List (name,isDefault)
await engine.selectPlaybackDeviceByIndex(index);        // Switch (invalidates sounds)
await engine.switchPlaybackDevice(index);               // Simple convenience
await engine.switchPlaybackDeviceAndRebuild(index);     // Rebind loaded sounds
await engine.switchPlaybackDevicePreservingMonitoring(
  index: index,
  monitorPlayer: streamPlayer,
  recorder: recorder,
  rebindSounds: true,
);
engine.playbackDeviceChanges().listen(...);             // Polling stream

Notes:

  • Raw switch invalidates existing native sound objects; use one of the “switch*AndRebuild / PreservingMonitoring” helpers for transparent recovery.
  • StreamPlayers are recreated internally when using switchPlaybackDevicePreservingMonitoring.
  • Web: enumeration returns a single logical “Default Output”; switching is a no‑op.

Capture (input) devices #

await recorder.enumerateInputDevices();                 // List (name,isDefault)
await recorder.switchInputDevicePreservingStream(index);// Minimal interruption
recorder.inputDeviceChanges().listen(...);              // Polling stream

Notes:

  • Switching input preserves ring buffer when format/channels unchanged.
  • Web: single “Default Input”; switching is a no‑op.

Monitoring (record → playback) #

await recorder.initStream(sampleRate: 48000, channels: 1);
recorder.start();

final monitor = StreamPlayer(mainEngine: engine);
await recorder.enableMonitoring(monitor);
monitor.volume = 0.8;

When switching only output device:

await engine.switchPlaybackDevicePreservingMonitoring(
  index: newIdx,
  recorder: recorder,
  monitorPlayer: monitor,
  rebindSounds: true,
);

Recorder keeps capturing; monitor player is rebuilt quickly.

Sound looping #

sound.playLooped(delay: Duration(milliseconds: 500));
sound.stop();   // Resets position (loop delay cleared)
sound.pause();  // Keeps position (loop disabled)

Rebinding sounds after device change #

Performed automatically by:

  • switchPlaybackDeviceAndRebuild
  • switchPlaybackDevicePreservingMonitoring (rebindSounds: true)

Web implementation is a no‑op (single logical device).


Quick usage snippets #

Engine + Sound #

final engine = Engine();
await engine.init();    // optional periodMs arg
await engine.start();

final audioData = AudioData(bytes: myUint8List); // Provide decoded or encoded data
final sound = await engine.loadSound(audioData);

sound.volume = 0.5;
sound.playLooped(delay: Duration(seconds: 1));
await Future.delayed(Duration(seconds: 3));
sound.stop();

Enumerate & switch output (with rebuild) #

final devices = await engine.enumeratePlaybackDevices();
for (var i=0; i<devices.length; i++) {
  print('$i: ${devices[i].$1}${devices[i].$2 ? " (default)" : ""}');
}
await engine.switchPlaybackDeviceAndRebuild(targetIndex);

Recorder streaming + monitoring #

final recorder = Recorder(mainEngine: engine);
await recorder.initStream(sampleRate: 48000, channels: 1);
recorder.start();

final monitor = StreamPlayer(mainEngine: engine);
await recorder.enableMonitoring(monitor);

recorder.stream(intervalMs: 20).listen((chunk) {
  // chunk = Float32List interleaved frames
});

Switch input device seamlessly #

final inputs = await recorder.enumerateInputDevices();
await recorder.switchInputDevicePreservingStream(newIndex);

Streams & polling #

Device change polling (output):

engine.playbackDeviceChanges(interval: Duration(seconds: 2))
  .listen((list) => print('Playback devices updated: $list'));

Input devices:

recorder.inputDeviceChanges().listen((list) {
  print('Input devices: $list');
});

Limitations / platform notes #

  • Output device switch requires rebuilding native ma_engine; helpers wrap rebind/recreate.
  • StreamPlayer currently supports only AudioFormat.float32.
  • Format / channel changes during input switch are not auto‑negotiated (stop + re‑init required).
  • Web: real multi‑device selection not available; APIs return single logical devices; rebind is no‑op.
  • Loop delay not accounted in Sound.duration.

Generator example #

final generator = Generator();
await generator.initEngine();
await generator.init(AudioFormat.float32, 2, 48000, 5);

generator.setWaveform(WaveformType.sine, 440.0, 0.4);
generator.start();

generator.stream(chunkSizeMs: 50).listen((buf) {
  // Process Float32 samples
});

Building #

git submodule update --init --recursive
cd miniaudio_dart_ffi/src/build
# Web
emcmake cmake ..
cmake --build .
# Native (clean build)
rm -rf *
cmake ..
cmake --build .

Regenerate bindings:

cd ../../..
dart run ffigen

TODO #

  • ✅ Sound loop clarity
  • ✅ Playback device enumeration / switching
  • ✅ Input device enumeration / seamless switching
  • ✅ Stream monitoring preservation on output switch
  • ❌ Graceful handling when no devices present

Troubleshooting #

Issue Cause Fix
Silence after output switch Not using rebuild helper Use switchPlaybackDeviceAndRebuild
Recorder stops after output switch Old manual teardown Use switchPlaybackDevicePreservingMonitoring
Web start exception (autoplay) No user gesture Call engine.start() after user interaction
Access violation native Pointer size mismatch (old FFI) Rebuild + update binding functions

License #

(Keep original license notice here if applicable.)

0
likes
80
points
140
downloads

Publisher

unverified uploader

Weekly Downloads

A high-level real-time audio playback library based on Miniaudio.

Documentation

API reference

License

MIT (license)

Dependencies

flutter, miniaudio_dart_ffi, miniaudio_dart_platform_interface, miniaudio_dart_web

More

Packages that depend on miniaudio_dart