| name | flutter-soloud-pull-streaming |
| version | 1 |
| description | Teaches the pull-buffer streaming API of the flutter_soloud audio plugin — setPullBufferStream with its onMoreDataIsNeeded callback, addPullBufferDataStream with byte offsets, seek via engine re-requests, and bounded-memory playback of huge seekable sources (HTTP range requests, large files). Use when the user asks to stream a large remote/local audio file with seeking, play multi-GB audio without loading it into memory, or is deciding between push (setBufferStream) and pull streaming. |
flutter_soloud pull-buffer streaming
In flutter_soloud, "pull" streaming means the engine owns the data demand: you create an AudioSource with setPullBufferStream(...) declaring the total encoded size, and the engine calls your onMoreDataIsNeeded(offset) callback whenever it wants the next chunk of encoded bytes at a specific byte offset. You fetch the bytes (HTTP Range request, file read, decryptor, custom protocol) and hand them back via addPullBufferDataStream. Decoded audio lives in a fixed-size circular buffer, so memory stays bounded regardless of source size — a 10 GB file can play with a 5 MB buffer. Seeking works: after SoLoud.instance.seek(handle, pos), the engine re-issues onMoreDataIsNeeded at the byte offset for the new position. One pull stream = one playback voice.
Minimal example
import 'package:flutter/foundation.dart';
import 'package:flutter_soloud/flutter_soloud.dart';
Future<void> playHugeFile(
Uint8List Function(int offset, int length) fetchRange,
int totalBytes,
) async {
await SoLoud.instance.init(); // must complete before any other call
// Declare first: the callback closure must reference the source, and a
// local can't be referenced inside its own initializer.
late final AudioSource source;
source = SoLoud.instance.setPullBufferStream(
audioSizeBytes: totalBytes, // REQUIRED, non-zero, known upfront
bufferSizeBytes: 5 * 1024 * 1024, // decoded circular buffer, ~14 s stereo f32
bufferTriggerPosition: 0.8, // default; ask for more when 20% ahead remains
format: BufferType.auto, // default; detects MP3/OGG Opus/OGG Vorbis/FLAC/WAV
onAudioDuration: (seconds) {/* total duration is now known */},
onMetadata: (metadata) {/* detected format, sample rate, channels */},
onMoreDataIsNeeded: (offset) {
const chunkSize = 64 * 1024;
final end = (offset + chunkSize).clamp(0, totalBytes);
if (offset < 0 || offset >= totalBytes) return;
SoLoud.instance.addPullBufferDataStream(
source,
fetchRange(offset, end - offset),
offset: offset,
);
},
);
final handle = SoLoud.instance.play(source);
// Seeking is free: the engine re-requests data at the new offset.
SoLoud.instance.seek(handle, const Duration(minutes: 2));
// No end-of-stream call exists: when sequential data reaches
// audioSizeBytes the engine ends the stream itself.
// Dispose on teardown: SoLoud.instance.deinit();
}