mirror of
https://github.com/R0m1k3/xtremobile.git
synced 2026-10-11 17:29:26 +02:00
feat: implement native IPTV player screen using media_kit with optimized playback profiles
This commit is contained in:
1 parent
a1628a6b13
commit
4c78210c5c
2 files changed
+41
-21
No files matched your search
@@ -162,22 +162,25 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
|
||||
(_player.platform as dynamic)?.setProperty('cache', 'yes');
|
||||
|
||||
if (widget.streamType == model.StreamType.live) {
|
||||
// LIVE PROFILE: Increased stability, no longer low-latency (prevents cuts)
|
||||
// LIVE PROFILE: TiviMate-Power Profile (Ultra Stability)
|
||||
// Uses larger buffers and ignoring broken timestamps to prevent "rollbacks"
|
||||
final deviceInfo = DeviceInfo();
|
||||
final liveBufferSecs = deviceInfo.getRecommendedLiveBufferSeconds();
|
||||
// Estimate bytes based on 2MB/s (16Mbps) which is high for most IPTV
|
||||
final liveBufferBytes = liveBufferSecs * 2 * 1024 * 1024;
|
||||
|
||||
debugPrint(
|
||||
'MediaKitPlayer: Applying LIVE optimization profile (STABILITY)',
|
||||
'MediaKitPlayer: Applying TIVIMATE-POWER profile - buffer=${liveBufferSecs}s cache=${liveBufferBytes ~/ (1024 * 1024)}MB',
|
||||
);
|
||||
(_player.platform as dynamic)?.setProperty(
|
||||
'cache-secs',
|
||||
'10',
|
||||
); // Reduced to 10s for faster startup
|
||||
(_player.platform as dynamic)?.setProperty(
|
||||
'demuxer-max-bytes',
|
||||
'32000000',
|
||||
); // 32MB (approx 20-30s @ 10Mbps) for stability
|
||||
(_player.platform as dynamic)
|
||||
?.setProperty('demuxer-readahead-secs', '15');
|
||||
(_player.platform as dynamic)
|
||||
?.setProperty('demuxer-max-back-bytes', '0');
|
||||
|
||||
(_player.platform as dynamic)?.setProperty('cache-secs', liveBufferSecs.toString());
|
||||
(_player.platform as dynamic)?.setProperty('demuxer-max-bytes', liveBufferBytes.toString());
|
||||
(_player.platform as dynamic)?.setProperty('demuxer-readahead-secs', liveBufferSecs.toString());
|
||||
(_player.platform as dynamic)?.setProperty('demuxer-max-back-bytes', '0');
|
||||
|
||||
// Fix rollbacks: Ignore broken/discontinuous timestamps in some TS streams
|
||||
(_player.platform as dynamic)?.setProperty('correct-pts', 'no');
|
||||
|
||||
// Ensure temp files are cleaned up
|
||||
(_player.platform as dynamic)?.setProperty('cache-unlink-files', 'yes');
|
||||
|
||||
@@ -215,11 +218,13 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
|
||||
// Audio/Video Sync - critical for smooth playback
|
||||
// Changed to 'audio' (default) instead of 'display-resample' to prevent resource exhaustion/drift over time
|
||||
(_player.platform as dynamic)
|
||||
?.setProperty('video-sync', 'audio'); // More stable for long streams
|
||||
?.setProperty('video-sync', 'audio'); // Audio-master sync
|
||||
(_player.platform as dynamic)
|
||||
?.setProperty('interpolation', 'no'); // Keep off for safety
|
||||
(_player.platform as dynamic)
|
||||
?.setProperty('audio-buffer', '1.0'); // Larger audio buffer (1 second)
|
||||
?.setProperty('audio-buffer', '3.0'); // [FIX] 3s buffer to prevent 30-min drift/crash
|
||||
(_player.platform as dynamic)
|
||||
?.setProperty('audio-pitch-correction', 'yes'); // Smooth sync adjustments
|
||||
(_player.platform as dynamic)
|
||||
?.setProperty('audio-samplerate', '48000'); // Standard high quality
|
||||
|
||||
@@ -660,17 +665,23 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
|
||||
_watchdogStallCount = 0;
|
||||
if (widget.streamType != model.StreamType.live) return;
|
||||
|
||||
// Check every 60 seconds — only reconnect after 2 consecutive stalls (2 min total)
|
||||
_liveWatchdog = Timer.periodic(const Duration(seconds: 60), (_) {
|
||||
// [FIX] TiviMate-like Watchdog: Check every 30 seconds for faster recovery
|
||||
_liveWatchdog = Timer.periodic(const Duration(seconds: 30), (_) {
|
||||
if (!mounted) return;
|
||||
|
||||
if (!_isPlaying && !_isLoading && _errorMessage == null) {
|
||||
// If intentionally paused by user, don't trigger watchdog
|
||||
if (!_isPlaying && _player.state.playing == false && _errorMessage == null && !_isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If buffering or not playing for 60s total, reconnect
|
||||
if (!_isPlaying || _isLoading) {
|
||||
_watchdogStallCount++;
|
||||
debugPrint(
|
||||
'MediaKitPlayer: Watchdog stall count: $_watchdogStallCount/2',
|
||||
'MediaKitPlayer: Watchdog health check: $_watchdogStallCount/2',
|
||||
);
|
||||
if (_watchdogStallCount >= 2) {
|
||||
debugPrint('MediaKitPlayer: Watchdog — stream stalled for 2min, reconnecting...');
|
||||
debugPrint('MediaKitPlayer: Watchdog — Stream unstable or stalled, triggering auto-reconnect...');
|
||||
_watchdogStallCount = 0;
|
||||
_attemptReconnect();
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'features/iptv/screens/mobile_dashboard_screen.dart';
|
||||
import 'core/models/playlist_config.dart';
|
||||
import 'core/database/hive_service.dart';
|
||||
import 'core/utils/startup_profiler.dart';
|
||||
import 'core/utils/device_info.dart';
|
||||
|
||||
/// Android-optimized entry point for XtremFlow IPTV
|
||||
/// No authentication - direct access to playlist selection
|
||||
@@ -25,6 +26,14 @@ void main() async {
|
||||
await HiveService.init();
|
||||
StartupProfiler.mark('hive_init');
|
||||
|
||||
// Initialize DeviceInfo for player buffering optimizations
|
||||
try {
|
||||
await DeviceInfo().init();
|
||||
StartupProfiler.mark('device_info_init');
|
||||
} catch (e) {
|
||||
debugPrint('XtremFlow: DeviceInfo init failed: $e');
|
||||
}
|
||||
|
||||
// [P0-2 FIX] Implement TTL-based cache instead of destructive clearing
|
||||
// Cache is now persistent with TTL:
|
||||
// - Channel/category lists: 6 hours
|
||||
|
||||
Reference in new issue
Block a user