Files
tuner/backend/api/ts.go
Scott Register 03296e7572 v2: tune playback for bursty upstream + clean overflow handling
- Player: match webplayer.online's proven mpegts.js live-sync config
  (deep 30-90s buffer, 45s target latency, 1.1x catch-up). The upstream
  delivers in bursts with multi-second gaps (measured up to ~6s); the
  deep buffer rides over them so 4K HEVC plays smoothly.
- Hub: on subscriber buffer overflow, cleanly disconnect the client so
  it reconnects and resyncs from a TS packet boundary instead of
  dropping bytes mid-stream (which corrupted alignment / sync_byte).
- Enlarge per-client buffer (256 -> 2048 chunks).
- Refresh real1.m3u from upstream.
2026-06-12 19:48:33 -07:00

49 lines
1.1 KiB
Go

package api
import (
"net/http"
)
// HandleTS streams the shared channel's raw MPEG-TS bytes to a viewer.
// Every connected browser subscribes to the same upstream via the hub, so the
// server holds only one connection to the IPTV source regardless of how many
// clients are watching.
// GET /ts
func (a *App) HandleTS(w http.ResponseWriter, r *http.Request) {
flusher, ok := w.(http.Flusher)
if !ok {
http.Error(w, "streaming unsupported", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "video/mp2t")
w.Header().Set("Cache-Control", "no-cache, no-store")
w.Header().Set("Connection", "keep-alive")
w.WriteHeader(http.StatusOK)
flusher.Flush()
sub, unsub := a.Hub.Subscribe()
defer unsub()
ctx := r.Context()
for {
select {
case <-ctx.Done():
return
case <-sub.Done():
return
case <-sub.Overflow():
// Client fell too far behind; close so it reconnects and resyncs.
return
case chunk, ok := <-sub.Chan():
if !ok {
return
}
if _, err := w.Write(chunk); err != nil {
return
}
flusher.Flush()
}
}
}