Skip to content

Flutter app — DVR/HLS player for iPad tablets, with multi-slot support and real-time WebSocket. Based on VLCKit (MobileVLCKit) with a custom native VLC player (MethodChannel + direct VLCKit).

Video Player ​

FeatureWhat it does
3 streaming slotsMAIN, FEED, ALT — 3 simultaneous HLS video players in a vertical layout
FullscreenTap a video to expand it to full screen
DVRTimeline bar to seek back in time, return to live with a tap
Auto-advance liveAutomatic return to live after N seconds of inactivity on the DVR
LIVE/DVR badgeColored badge: red for live, blue for DVR
Video controlsPlay/pause, seek, volume (headphone-only audio), fullscreen toggle
Headphone audioVolume at 0.0 by default, activates automatically only with headphones connected
BoxFit coverVideos fill the screen while keeping proportions, no side black bars
Live/Go LiveBlue button for DVR, red for live streaming

Connection ​

FeatureWhat it does
Persistent WebSocketContinuous connection to the backend to receive real-time updates
Exponential backoffAutomatic reconnection with progressive delay (1s, 2s, 4s, 8s, max 30s)
ConfigurableBackend URL passed via --dart-define=BACKEND_URL=..., nothing hardcoded
Remote resetReceives the device:reset command to restart all streams without restarting the app
Remote slot controlReceives the device:slot:control command to stop/start/restart a single slot

Stream switching ​

FeatureWhat it does
Automatic switchWhen the Control Room changes a link, all iPads switch to the new stream in real time
Free slotWhen a slot is freed, the video stops and waits for the next stream
Track last URLsOn reset, the app remembers the last valid URLs and restores them after 500ms

Requirements ​

ToolVersion
Flutter3.44.4+
Dart3.12.2+
Xcode16+ (for iOS build)
CocoaPods(for iOS dependencies)

Player Dependencies ​

PackageRole
MobileVLCKit (pod)VLC playback engine (declared in ios/Podfile)
web_socket_channelReal-time WebSocket to the backend (ws_link_service.dart)
audio_sessionAudio session configuration
shared_preferencesSettings persistence

Architecture ​

lib/
├── main.dart                  # Flutter entry point → VlcCustomTestScreen
├── vlc_custom_test_screen.dart # Main custom VLC player screen
├── vlc/
│   ├── vlc_controller.dart    # VLC controller (playback, stall watchdog, retry)
│   ├── vlc_controls.dart      # Video controls overlay
│   ├── vlc_timeline_widget.dart # Interactive DVR timeline
│   ├── dvr_support_probe.dart # Server DVR capability detection
│   └── dvr_url_strategy.dart  # DVR URL strategies (Flussonic/Wowza)
├── vlc_native_player.dart     # Native VLC bridge (MethodChannel)
├── switch_timing.dart         # Slot transition timing
├── dvr_range.dart             # DVR range data model
├── link_service.dart          # REST service (unused)
└── ws_link_service.dart       # WebSocket service (active)

Test ​

bash
# Run all tests
flutter test

# Run only the VLC controller tests
flutter test test/vlc_controller_test.dart test/vlc_controller_state_test.dart

App Store Notes ​

The app is designed as a LAN kiosk: it connects via HTTP to a private IP (e.g. 192.168.1.127:3002). For App Store submission you need the App Review Notes and the privacy policy (see Mac Setup and Complete Guide). ATS allows traffic to private IPs; NSAllowsLocalNetworking is configured in ios/Runner/Info.plist for the local network.

→ See Build Flutter App for setup, running and building.

© 2026 Zerolatency — All Rights Reserved