Add an audio source picker to the GUI so users can capture a specific
PipeWire device (sink monitor or microphone) instead of only the system
default output.
- vendor go2tv.app/screencast and patch the audio stream to accept a
target PipeWire node serial (PW_KEY_TARGET_OBJECT); the upstream lib
only ever auto-connected to the default
- capture: ListAudioSources enumerates PipeWire sinks/sources via pw-dump;
OpenPipeWire takes the selected node serial
- flinger/config/gui: AudioSource config field, persisted and exposed as
an Audio source dropdown (default output + enumerated devices)
Also fixes two pre-existing bugs surfaced by stop/start testing:
- engine Stop now waits for the video/audio/stats goroutines before
destroying the encoder (was a use-after-free SIGSEGV)
- Start/Stop now pause/resume the engine instead of tearing down and
re-opening the portal session, which the portal cannot reliably do
in-process (2nd CreateSession returned Ended/cancelled). Capture
session stays open across stop/start.
Add a Scale option (1.0 native, 0.5 half, etc.) that downsamples the
captured BGRA frame with bilinear interpolation before JPEG encoding.
Config carries the scale factor; the GUI exposes a Scale dropdown
(100%/75%/50%/25%) that applies live via SetConfig.
Verified: OBS displays the image at the reduced resolution matching the
selected scale, without restarting the stream.
- sender tracks payload bytes; engine measures stream bitrate over a
sliding window and exposes it in Status
- GUI status label and tray tooltip show the live bitrate (e.g. 36 Mbps)
- add a Preset dropdown (Low/Medium/High/Ultra) that sets quality+fps
together and applies live via SetConfig
Verified: 36 Mbps shown for Medium (quality 70 @ 30fps) matches the
wire measurement.
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.
Record the most recent runtime error (capture, encode, packet, audio)
in the engine and expose it via Status.Err. The GUI shows it in the
status label (highlighted as a danger) and in the tray tooltip, so a
denied screen-share or encoder failure is visible without reading logs.
- config: validate port/quality/fps/source/stream-index ranges on load
and before engine start (flinger.Config.Validate)
- discovery: add Announce option to disable multicast (GUI checkbox,
CLI --no-announce); absent JSON key keeps the default true
- backpressure: count dropped frames in the TCP sender, expose via
engine Status and a live counter in the GUI status label
- docs: record M3/M4 decisions and X11 coverage via the portal backend
Move the capture/encode/send pipeline out of cmd/teleportfling into a
GUI-free Engine so the CLI and the desktop app share one implementation:
- flinger: Config/Engine/Status, audio+video+stats loops, pattern source
- config: JSON persistence at ~/.config/teleportfling/config.json
- cmd/teleportfling: thin CLI wrapper around the engine (same flags)
- golangci: extend exclusions to flinger/config