50 lines
1.9 KiB
Dart
50 lines
1.9 KiB
Dart
import 'dart:async';
|
|
|
|
/// Per-screen state for Android display frame-rate matching: the retry
|
|
/// counter for backends that detect fps only after rendering, whether a
|
|
/// switch was already applied for the current item, and the MediaSession
|
|
/// pause-suppression window armed around HDMI renegotiations.
|
|
///
|
|
/// One instance lives on the player screen; the open/reload pipelines call
|
|
/// [resetForNewItem] before each open and the display-matching paths flip
|
|
/// [applied]/[retries] as they negotiate.
|
|
class FrameRateMatcher {
|
|
/// Retries left for late fps detection (ExoPlayer reports container fps
|
|
/// only after ~8 rendered frames).
|
|
int retries = 0;
|
|
|
|
/// Whether a display switch was already applied for the current item —
|
|
/// the post-first-frame path bails instead of switching twice.
|
|
bool applied = false;
|
|
|
|
Timer? _mediaPauseSuppressionTimer;
|
|
|
|
/// Whether a MediaSession PauseEvent should be ignored right now because
|
|
/// the display is (or may still be) renegotiating HDMI. Fire Stick (and
|
|
/// similar Android TV devices) send onPause() through the MediaSession
|
|
/// callback when the display mode changes for frame rate matching.
|
|
bool get suppressesMediaPause => _mediaPauseSuppressionTimer?.isActive ?? false;
|
|
|
|
/// Arm the pause-suppression window around an HDMI renegotiation. The
|
|
/// window outlasts the switch by a safety margin on top of the user's
|
|
/// configured extra delay.
|
|
void beginSuppressWindow(int delaySec) {
|
|
_mediaPauseSuppressionTimer?.cancel();
|
|
_mediaPauseSuppressionTimer = Timer(Duration(seconds: 2 + delaySec + 1), () {
|
|
_mediaPauseSuppressionTimer = null;
|
|
});
|
|
}
|
|
|
|
/// Reset the per-item negotiation state before opening new media.
|
|
void resetForNewItem() {
|
|
retries = 0;
|
|
applied = false;
|
|
}
|
|
|
|
/// Cancel any active suppression window when the owning screen is disposed.
|
|
void dispose() {
|
|
_mediaPauseSuppressionTimer?.cancel();
|
|
_mediaPauseSuppressionTimer = null;
|
|
}
|
|
}
|