seek method
Seeks to targetUs.
The audio thread is suspended across the whole operation. That is not politeness: the worker clears the ring as part of seeking, and clearing it under a live consumer would let one buffer of already-committed samples be overwritten mid-read — a click at exactly the moment a seek is supposed to be clean.
Implementation
Future<void> seek(int targetUs) async {
if (_closed) return;
final before = await _seekGeneration();
await _sink.suspend();
try {
await _worker.request<Object?>(<Object?>['seek', targetUs]);
// Wait for the pump to actually reach the seek: it may have been mid
// decode, and resuming before it has cleared would play the old
// position's tail.
for (var i = 0; i < 100; i++) {
if (await _seekGeneration() != before) break;
await Future<void>.delayed(const Duration(milliseconds: 10));
}
// Position now advances from the seek target, against the ring's
// monotonic cursor.
_baselinePtsUs = targetUs;
_baselineFrames = _sink.ring.framesConsumed;
} on Object {
// A failed seek leaves the stream where it was; the caller sees the
// position not move rather than an exception out of a transport control.
} finally {
// Back to whatever the caller had, NOT unconditionally running: seeking
// a paused player must leave it paused, or a scrub starts playback.
if (!_paused) await _sink.resume();
}
}