forked from Foxyz/sync_replay_project
A fresh player for every media change (the frozen frame after a swap needed Ctrl+R); promotion and fresh players share one hand-over
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c3fe8b682d
commit
e52a7633a0
4 files changed
+163
-43
No files matched your search
@@ -290,6 +290,10 @@ class SessionCoordinator {
|
||||
// Unlike [_mediaId] it survives a lost connection, so a reconnect to the
|
||||
// same media keeps the player, and a swap stops the previous media.
|
||||
int _playerMediaId = -1;
|
||||
// [_playerMediaId] at the last open: the same media again (a reconnect,
|
||||
// joining back) keeps the player, any other gets a fresh one (see
|
||||
// [_openMedia]).
|
||||
int _openedFor = -1;
|
||||
String? _openUrl;
|
||||
String _wsHost = '';
|
||||
int _wsPort = 0;
|
||||
@@ -361,8 +365,9 @@ class SessionCoordinator {
|
||||
jellyfin = jellyfin ?? JellyfinAccounts.instance,
|
||||
trackPrefs = trackPrefs ?? TrackPrefs();
|
||||
|
||||
/// Player lifetime = one session: created here on connect, disposed by
|
||||
/// [leave]. Never reused across sessions (a GPU-side video freeze sticks
|
||||
/// The session's first player: created here on connect, disposed by
|
||||
/// [leave]; each new media gets its own ([PlaybackController.openUrl]).
|
||||
/// Never reused across sessions or media (a GPU-side video freeze sticks
|
||||
/// to the player).
|
||||
Future<void> initPlayer() async {
|
||||
if (_playerReady) return;
|
||||
@@ -465,6 +470,7 @@ class SessionCoordinator {
|
||||
diff.reset();
|
||||
_mediaId = -1;
|
||||
_playerMediaId = -1;
|
||||
_openedFor = -1;
|
||||
settledMediaId.value = -1;
|
||||
_openUrl = null;
|
||||
playerError.value = '';
|
||||
@@ -552,9 +558,13 @@ class SessionCoordinator {
|
||||
});
|
||||
}
|
||||
|
||||
/// Opens [url] (with [headers] on every request); false on failure.
|
||||
/// Opens [url] (with [headers] on every request); false on failure. A
|
||||
/// new media gets a fresh player (or the preload holding it); the media
|
||||
/// the player held before (a reconnect) keeps it.
|
||||
Future<bool> _openMedia(String url, {Map<String, String>? headers}) async {
|
||||
if (url == _openUrl) return true;
|
||||
final keepPlayer = _playerMediaId == _openedFor;
|
||||
_openedFor = _playerMediaId;
|
||||
_openUrl = url;
|
||||
_openHeaders = headers;
|
||||
diff.reset();
|
||||
@@ -564,7 +574,10 @@ class SessionCoordinator {
|
||||
try {
|
||||
await _prepareYtDlp(url);
|
||||
switchTrace.mark(mediaId, SwitchTrace.open);
|
||||
final promoted = await playback.openUrl(url, headers: headers);
|
||||
final promoted = await playback.openUrl(url,
|
||||
headers: headers,
|
||||
keepPlayer: keepPlayer,
|
||||
onFreshPlayer: () => switchTrace.mark(mediaId, SwitchTrace.player));
|
||||
switchTrace.mark(mediaId, promoted ? SwitchTrace.preloaded : SwitchTrace.opened);
|
||||
health.value =
|
||||
const HealthStatus(HealthSeverity.ok, 'connected');
|
||||
@@ -938,6 +951,8 @@ class SessionCoordinator {
|
||||
Future<void> _leavePreviousMedia(int mediaId) async {
|
||||
final held = _playerMediaId;
|
||||
_playerMediaId = mediaId;
|
||||
// Opened from the welcome, before any state: that was this media.
|
||||
if (held == -1 && _openedFor == -1 && _openUrl != null) _openedFor = mediaId;
|
||||
if (held == -1 || held == mediaId) return;
|
||||
_openUrl = null;
|
||||
_openHeaders = null;
|
||||
|
||||
@@ -11,6 +11,8 @@ class SwitchTrace {
|
||||
static const state = 'state';
|
||||
static const resolved = 'resolved';
|
||||
static const open = 'open';
|
||||
/// A fresh player is up for it (no preload held it).
|
||||
static const player = 'player';
|
||||
static const opened = 'opened';
|
||||
static const preloaded = 'preloaded';
|
||||
static const buffered = 'buffered';
|
||||
|
||||
Reference in new issue
Block a user