fix(player): surface a persistent HTTP 503 at open instead of retrying forever

ffmpeg's reconnect loop deliberately retries 503 without bound (#1520), so a
server that keeps refusing the stream at open time left a silent black screen:
ExoPlayer fell back to MPV, MPV reconnected forever, and no error ever reached
the screen. A new open-phase watchdog arms on the first 503 seen before any
frame renders and, after 20s without one, synthesizes a server-http-503 error
that shows an actionable dialog. Mid-stream 503s and live TV keep their
existing ride-out paths.

close #1830
This commit is contained in:
edde746
2026-08-08 12:06:32 +02:00
parent f0debe2c32
commit e6be5f9fef
38 changed files with 321 additions and 12 deletions
+7
View File
@@ -91,6 +91,7 @@ import 'video_player/live_stream_retry.dart';
import 'video_player/live_timeline_report.dart';
import 'video_player/wakelock_controller.dart';
import 'video_player/playback_failure_action.dart';
import 'video_player/open_http_503_watchdog.dart';
import 'video_player/live_tv_session_args.dart';
import 'video_player/live_tv_session_state.dart';
import 'video_player/tv_background_suspend_policy.dart';
@@ -1765,6 +1766,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
_autoPlayTimer?.cancel();
_tvBackgroundPlayerSuspendTimer?.cancel();
_http503Watchdog.disarm();
_stillWatchingTimer?.cancel();
@@ -1977,6 +1979,11 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
/// transient status must never mask the fatal one that follows.
final Set<int> _fatalHttpStatuses = <int>{};
/// Bounds an open the server keeps answering with HTTP 503 — that loop
/// otherwise never raises an error (#1830). Armed from [_onPlayerLog],
/// disarmed on first frame, on every new-open reset, and in [dispose].
late final OpenHttp503Watchdog _http503Watchdog = OpenHttp503Watchdog(onPersistent: _onOpenHttp503Persistent);
// OS Media Controls Integration
/// Navigate to a specific queue item (called from QueueSheet)