mirror of
https://github.com/R0m1k3/xtremflow.git
synced 2026-10-21 14:08:04 +02:00
fix: stabilize IPTV playback and implement request throttling
- Add playback lock to XtreamService to delay EPG during stream init - Increase MPEG-TS stash buffer to 512KB for better stability - Enable liveBufferLatencyChasing to prevent stream drift - Tune HLS parameters for balanced speed and reliability
This commit is contained in:
1 parent
0ca6f96710
commit
df4bcfd07f
5 files changed
+48
-22
No files matched your search
@@ -140,6 +140,12 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
|||||||
streamUrl = service.getLiveStreamUrlTs(currentStreamId);
|
streamUrl = service.getLiveStreamUrlTs(currentStreamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// STABILIZATION: Lock background requests during stream init
|
||||||
|
service.isPlaybackLoading = true;
|
||||||
|
Future.delayed(const Duration(seconds: 10), () {
|
||||||
|
service.isPlaybackLoading = false;
|
||||||
|
});
|
||||||
|
|
||||||
_currentStreamUrl = streamUrl;
|
_currentStreamUrl = streamUrl;
|
||||||
|
|
||||||
final encodedUrl = Uri.encodeComponent(streamUrl);
|
final encodedUrl = Uri.encodeComponent(streamUrl);
|
||||||
|
|||||||
@@ -15,6 +15,13 @@ class XtreamService {
|
|||||||
|
|
||||||
PlaylistConfig? _currentPlaylist;
|
PlaylistConfig? _currentPlaylist;
|
||||||
|
|
||||||
|
/// Flag to indicate that a playback is currently loading
|
||||||
|
/// Used to throttle background requests (EPG, images)
|
||||||
|
bool isPlaybackLoading = false;
|
||||||
|
|
||||||
|
/// Minimum delay for background requests when playback is loading
|
||||||
|
static const _throttleDelay = Duration(seconds: 8);
|
||||||
|
|
||||||
XtreamService() {
|
XtreamService() {
|
||||||
_dio = Dio(
|
_dio = Dio(
|
||||||
BaseOptions(
|
BaseOptions(
|
||||||
@@ -616,6 +623,11 @@ class XtreamService {
|
|||||||
Future<List<EpgEntry>> getShortEpg(String streamId) async {
|
Future<List<EpgEntry>> getShortEpg(String streamId) async {
|
||||||
if (_currentPlaylist == null) throw Exception('No playlist configured');
|
if (_currentPlaylist == null) throw Exception('No playlist configured');
|
||||||
|
|
||||||
|
if (isPlaybackLoading) {
|
||||||
|
debugPrint('[XtreamService] Throttling short EPG for $streamId');
|
||||||
|
await Future.delayed(_throttleDelay);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await _dio.get(
|
final response = await _dio.get(
|
||||||
_wrapWithProxy(_currentPlaylist!.apiBaseUrl),
|
_wrapWithProxy(_currentPlaylist!.apiBaseUrl),
|
||||||
@@ -653,6 +665,11 @@ class XtreamService {
|
|||||||
Future<xm.ShortEPG> getShortEPG(String streamId) async {
|
Future<xm.ShortEPG> getShortEPG(String streamId) async {
|
||||||
if (_currentPlaylist == null) throw Exception('No playlist configured');
|
if (_currentPlaylist == null) throw Exception('No playlist configured');
|
||||||
|
|
||||||
|
if (isPlaybackLoading) {
|
||||||
|
debugPrint('[XtreamService] Throttling short EPG metadata for $streamId');
|
||||||
|
await Future.delayed(_throttleDelay);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await _dio.get(
|
final response = await _dio.get(
|
||||||
_wrapWithProxy(_currentPlaylist!.apiBaseUrl),
|
_wrapWithProxy(_currentPlaylist!.apiBaseUrl),
|
||||||
|
|||||||
+4
-4
@@ -253,15 +253,15 @@
|
|||||||
const isTurbo = urlParams.get('turbo') === 'true';
|
const isTurbo = urlParams.get('turbo') === 'true';
|
||||||
|
|
||||||
const hls = new Hls({
|
const hls = new Hls({
|
||||||
maxBufferLength: isTurbo ? 30 : 45,
|
maxBufferLength: isTurbo ? 45 : 50,
|
||||||
enableWorker: true,
|
enableWorker: true,
|
||||||
liveSyncDurationCount: isTurbo ? 2 : 4,
|
liveSyncDurationCount: isTurbo ? 3 : 4, // Improved stability
|
||||||
// Turbo-Start specific
|
// Turbo-Start specific
|
||||||
startLevel: isTurbo ? 0 : -1,
|
startLevel: isTurbo ? 0 : -1,
|
||||||
initialLiveManifestSize: 1,
|
initialLiveManifestSize: 1,
|
||||||
abrEwmaDefaultEstimate: 500000,
|
abrEwmaDefaultEstimate: 500000,
|
||||||
manifestLoadingRetryDelay: 500,
|
manifestLoadingRetryDelay: 800,
|
||||||
levelLoadingRetryDelay: 500
|
levelLoadingRetryDelay: 800
|
||||||
});
|
});
|
||||||
window.hlsInstance = hls;
|
window.hlsInstance = hls;
|
||||||
hls.loadSource(url);
|
hls.loadSource(url);
|
||||||
|
|||||||
+14
-11
@@ -245,18 +245,18 @@
|
|||||||
const isTurbo = urlParams.get('turbo') === 'true';
|
const isTurbo = urlParams.get('turbo') === 'true';
|
||||||
|
|
||||||
const hls = new Hls({
|
const hls = new Hls({
|
||||||
maxBufferLength: isTurbo ? 30 : 60,
|
maxBufferLength: isTurbo ? 45 : 60,
|
||||||
maxMaxBufferLength: isTurbo ? 60 : 120,
|
maxMaxBufferLength: isTurbo ? 90 : 120,
|
||||||
enableWorker: true,
|
enableWorker: true,
|
||||||
liveSyncDurationCount: isTurbo ? 2 : 5, // Aggressive sync for Turbo
|
liveSyncDurationCount: isTurbo ? 3 : 5, // Improved stability
|
||||||
liveMaxLatencyDurationCount: isTurbo ? 10 : 15,
|
liveMaxLatencyDurationCount: isTurbo ? 15 : 20,
|
||||||
lowLatencyMode: true,
|
lowLatencyMode: true,
|
||||||
// Turbo-Start specific
|
// Turbo-Start specific
|
||||||
startLevel: isTurbo ? 0 : -1, // Lowest bitrate first
|
startLevel: isTurbo ? 0 : -1,
|
||||||
initialLiveManifestSize: 1,
|
initialLiveManifestSize: 1,
|
||||||
abrEwmaDefaultEstimate: 500000, // Start with conservative estimate
|
abrEwmaDefaultEstimate: 500000,
|
||||||
manifestLoadingRetryDelay: 500,
|
manifestLoadingRetryDelay: 800,
|
||||||
levelLoadingRetryDelay: 500
|
levelLoadingRetryDelay: 800
|
||||||
});
|
});
|
||||||
|
|
||||||
window.hlsInstance = hls;
|
window.hlsInstance = hls;
|
||||||
@@ -292,9 +292,12 @@
|
|||||||
url: url
|
url: url
|
||||||
}, {
|
}, {
|
||||||
enableWorker: true,
|
enableWorker: true,
|
||||||
stashInitialSize: isTurbo ? 128 * 1024 : 512 * 1024, // Tiny stash for Turbo zapping
|
stashInitialSize: isTurbo ? 512 * 1024 : 1024 * 1024, // 512KB for better stability
|
||||||
enableStashBuffer: !isTurbo, // Direct pass-through for Live TV Turbo
|
enableStashBuffer: true, // Re-enable stash buffer for stability
|
||||||
lazyLoad: false
|
liveBufferLatencyChasing: true, // Correct drift
|
||||||
|
liveBufferLatencyChasingOnPaused: true,
|
||||||
|
lazyLoad: false,
|
||||||
|
maxStashSize: 1024 * 1024 // 1MB Max
|
||||||
});
|
});
|
||||||
|
|
||||||
player.attachMediaElement(video);
|
player.attachMediaElement(video);
|
||||||
|
|||||||
@@ -231,18 +231,18 @@
|
|||||||
const isTurbo = urlParams.get('turbo') === 'true';
|
const isTurbo = urlParams.get('turbo') === 'true';
|
||||||
|
|
||||||
const hls = new Hls({
|
const hls = new Hls({
|
||||||
maxBufferLength: isTurbo ? 30 : 60,
|
maxBufferLength: isTurbo ? 45 : 60,
|
||||||
maxMaxBufferLength: isTurbo ? 60 : 120,
|
maxMaxBufferLength: isTurbo ? 90 : 120,
|
||||||
liveSyncDurationCount: isTurbo ? 2 : 5,
|
liveSyncDurationCount: isTurbo ? 3 : 5, // Improved stability
|
||||||
liveMaxLatencyDurationCount: isTurbo ? 10 : 15,
|
liveMaxLatencyDurationCount: isTurbo ? 15 : 20,
|
||||||
enableWorker: true,
|
enableWorker: true,
|
||||||
lowLatencyMode: !isTurbo, // Prioritize stability unless Turbo requested
|
lowLatencyMode: true,
|
||||||
// Turbo-Start specific
|
// Turbo-Start specific
|
||||||
startLevel: isTurbo ? 0 : -1,
|
startLevel: isTurbo ? 0 : -1,
|
||||||
initialLiveManifestSize: 1,
|
initialLiveManifestSize: 1,
|
||||||
abrEwmaDefaultEstimate: 500000,
|
abrEwmaDefaultEstimate: 500000,
|
||||||
manifestLoadingRetryDelay: 500,
|
manifestLoadingRetryDelay: 800,
|
||||||
levelLoadingRetryDelay: 500
|
levelLoadingRetryDelay: 800
|
||||||
});
|
});
|
||||||
hls.loadSource(streamUrl);
|
hls.loadSource(streamUrl);
|
||||||
hls.attachMedia(video);
|
hls.attachMedia(video);
|
||||||
|
|||||||
Reference in new issue
Block a user