Relay: viewers keep the file size (headers within 4 s, connection: close), retries back off, 412 re-resolves
Two server behaviours left ffmpeg (8.1/9.0) without the file size, after which every seek failed with "size -38" until a reload: - dart:io holds response headers until body bytes exist: a stalled source meant no headers within mpv's 5 s timeout. Relay byte responses are now written on the raw connection, headers with the first bytes or after 4 s, and a swap ends waiting reads with a plain close. - every response closed its socket without saying connection: close, so ffmpeg 8.x reused a dead connection for its next seek (pol's X clips). The server now says it whenever the request asks. A failed pull waits 250 ms doubling to 8 s instead of re-pulling at once (the ~130 ms storm that drew Bilibili's 412/403); 412 counts as an expired URL and re-resolves the page, at most once per 60 s. The app reloads a player once per media when ffmpeg reports the lost size anyway. P37: a read that waits past ffmpeg's retry budget still ends the file early. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5e3834e6ba
commit
e91539d113
17 files changed
+575
-63
No files matched your search
@@ -81,6 +81,7 @@ class PieceBuffer implements TrackBuffer {
|
||||
/// null before a minute of it has arrived.
|
||||
double? get bytesPerSec => _knownSecs >= 60 ? _knownBytes / _knownSecs : null;
|
||||
DateTime? _retryAt;
|
||||
var _failures = 0; // failed pulls in a row (backoff)
|
||||
var _disposed = false;
|
||||
Completer<void> _kick = Completer();
|
||||
final Completer<void> _ready = Completer();
|
||||
@@ -167,6 +168,7 @@ class PieceBuffer implements TrackBuffer {
|
||||
final pl = _pull;
|
||||
if (pl == null || pl.id != id || _disposed) return;
|
||||
_pull = null;
|
||||
_failures = 0;
|
||||
final data = pl.buf.takeBytes();
|
||||
final i = pl.piece;
|
||||
_pieces[i] = data;
|
||||
@@ -182,12 +184,18 @@ class PieceBuffer implements TrackBuffer {
|
||||
_wake();
|
||||
}
|
||||
|
||||
static final _pullFailThrottle = LogThrottle(burst: 3);
|
||||
|
||||
@override
|
||||
void feedFail(int id, String reason) {
|
||||
if (_pull?.id != id) return;
|
||||
_log.warning('relay piece pull $id failed: $reason');
|
||||
_pull = null;
|
||||
_retryAt = DateTime.now().add(const Duration(seconds: 1));
|
||||
final delay = relayRetryDelay(++_failures);
|
||||
_retryAt = DateTime.now().add(delay);
|
||||
final pass = _pullFailThrottle.allow('${identityHashCode(this)}');
|
||||
if (pass != null) {
|
||||
_log.warning('${pass}relay piece pull $id failed ($_failures in a row, next in ${delay.inMilliseconds} ms): $reason');
|
||||
}
|
||||
_wake();
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user