forked from Foxyz/sync_replay_project
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
@@ -63,6 +63,10 @@ class PlaybackController {
|
||||
/// e.g. a CDN's 403), at most once per [beginOpen].
|
||||
void Function(String error)? onLoadError;
|
||||
|
||||
/// The current media's HTTP stream lost its size (see [mpvStreamLost]):
|
||||
/// at most once per player and media; the coordinator opens it again.
|
||||
void Function()? onStreamLost;
|
||||
|
||||
/// Seeks from the controls (seek bar, the video widget's own) go here
|
||||
/// instead of to mpv.
|
||||
void Function(Duration position)? onUserSeek;
|
||||
@@ -71,6 +75,7 @@ class PlaybackController {
|
||||
// load error was reported.
|
||||
String? _httpError;
|
||||
bool _loadErrorSent = false;
|
||||
bool _streamLostSent = false;
|
||||
|
||||
/// The current player. Only while [alive].
|
||||
HostedPlayer get player => _player!;
|
||||
@@ -144,6 +149,7 @@ class PlaybackController {
|
||||
_chapterJson = '';
|
||||
_httpError = null;
|
||||
_loadErrorSent = false;
|
||||
_streamLostSent = false;
|
||||
_shaders = '';
|
||||
_loaded = loaded && p.state.duration > Duration.zero;
|
||||
_opened = loaded;
|
||||
@@ -196,6 +202,7 @@ class PlaybackController {
|
||||
_chapterJson = '';
|
||||
_httpError = null;
|
||||
_loadErrorSent = false;
|
||||
_streamLostSent = false;
|
||||
_loaded = false;
|
||||
chapters.value = const [];
|
||||
tracks.value = const [];
|
||||
@@ -286,7 +293,14 @@ class PlaybackController {
|
||||
// error while shaders are on is a shader that failed to load or compile
|
||||
// (mpv then renders without it).
|
||||
void _onLog(PlayerLogLine log) {
|
||||
if (log.prefix == 'ffmpeg') return;
|
||||
if (log.prefix == 'ffmpeg') {
|
||||
if (!_streamLostSent && mpvStreamLost(log)) {
|
||||
_streamLostSent = true;
|
||||
_log.warning('the media stream lost its size, every seek fails: [ffmpeg] ${log.text.trim()}');
|
||||
onStreamLost?.call();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!_loadErrorSent && mpvLoadFailed(log, duration.peek())) {
|
||||
_loadErrorSent = true;
|
||||
final http = _httpError;
|
||||
|
||||
Reference in new issue
Block a user