feat: live settings changes mid-stream

Add flinger.SetConfig to update FPS/quality/name/audio/announce without
restarting the stream. Fields that require a restart (source, port,
stream-index) are preserved. The video loop reads the live config each
frame so changes apply immediately, and the GUI Quality/Frame-rate
dropdowns push changes to a running engine.

Verified live: fps 12->33 and JPEG size 210KB->1.3MB on quality change.
This commit is contained in:
2026-09-19 17:37:47 +01:00
parent f25b498fc1
commit 95f47abadb
3 changed files with 128 additions and 6 deletions
+36 -2
View File
@@ -140,11 +140,11 @@ func (g *App) buildUI() {
g.setupMonitorPicker()
// Quality.
g.qualitySel = widget.NewSelect([]string{"50", "60", "70", "80", "90", "100"}, func(string) {})
g.qualitySel = widget.NewSelect([]string{"50", "60", "70", "80", "90", "100"}, g.applyLiveSettings)
g.qualitySel.SetSelected(itoa(g.cfg.Quality))
// FPS.
g.fpsSel = widget.NewSelect([]string{"15", "30", "60"}, func(string) {})
g.fpsSel = widget.NewSelect([]string{"15", "30", "60"}, g.applyLiveSettings)
g.fpsSel.SetSelected(itoa(g.cfg.FPS))
// Audio.
@@ -241,6 +241,40 @@ func (g *App) selectedMonitorIndex() int {
return g.cfg.StreamIndex
}
// applyLiveSettings pushes the current form values (quality, fps, name,
// audio, announce) into a running engine via SetConfig so changes take
// effect without restarting the stream. When the engine is not running it is
// a no-op; the values are still captured on the next Start.
func (g *App) applyLiveSettings(string) {
if g.eng == nil {
return
}
quality, _ := atoi(g.qualitySel.Selected)
fps, _ := atoi(g.fpsSel.Selected)
announce := g.announceChk.Checked
cfg := flinger.Config{
Name: g.nameEnt.Text,
Port: g.cfg.Port,
Quality: quality,
FPS: fps,
Source: g.cfg.Source,
Audio: g.audioChk.Checked,
StreamIndex: g.cfg.StreamIndex,
Announce: announce,
}
if err := g.eng.SetConfig(cfg); err != nil {
log.Printf("gui: live settings: %v", err)
return
}
// Keep the persisted config in sync with what we just applied.
g.cfg.Quality = quality
g.cfg.FPS = fps
g.cfg.Audio = cfg.Audio
g.cfg.Name = cfg.Name
ann := announce
g.cfg.Announce = &ann
}
// toggleStream starts or stops the engine based on current UI state.
func (g *App) toggleStream() {
if g.lock {