Document the two ports TeleportFling needs (TCP 9756 stream, UDP 9999
multicast discovery) and how to open them on NixOS and other firewalls,
based on the two-machine test.
- contrib/teleportfling.service: per-user unit running the headless CLI
with its own config (~/.config/teleportfling/daemon.json)
- contrib/install-daemon.sh: builds the binary, installs the unit and a
starter daemon config
- contrib/README.md: install and management instructions
- todo.md: mark --config and daemon items complete
Add config.LoadFrom/SaveTo for arbitrary paths and thread a --config
flag through both entry points:
- CLI: --config loads a file first; explicit flags override file values
- GUI: --config selects the settings file used for load and save
- tests for LoadFrom/SaveTo and default fallback
- tray icon and tooltip now reflect engine state: grey when stopped,
green + live frame/drop counters in the tooltip while streaming
- generate a proper app icon (assets/, via cmd/teleportfling-icon) and
embed it so the window and tray carry the icon without runtime files
- add a .desktop entry template for launching from an app menu
- run Fyne UI updates (status label, tray icon/tooltip) on the main
thread via fyne.Do to satisfy the threading model
- 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
- internal/gui: settings form (name, port, source, quality, fps, audio)
wired to the flinger engine, config save/load, start/stop toggle
- system tray via Fyne's StatusNotifierItem: Show (raises window),
Start/Stop, Quit; left-click shows the settings window
- cmd/teleportfling-gui entry point
Verified on Hyprland: tray icon registers, start/stop streaming works,
window shows and focuses from the tray.
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
Add libGL, mesa, wayland, libxkbcommon and the X client libraries the
Fyne cgo toolchain links against, plus LIBRARY_PATH so Go's linker finds
them (it does not read NIX_LDFLAGS).
Capture the Wayland desktop via xdg-desktop-portal + PipeWire using
go2tv.app/screencast (MIT), and stream it to OBS:
- internal/capture: Capture/FrameSource/AudioSource interfaces and the
PipeWire backend (BGRA frames at monitor resolution, S16 48 kHz stereo
system audio)
- protocol: EncodeBGRA fast path producing 4:2:0 YCbCr JPEGs
- cmd: --source screen|pattern, --audio, --stream-index flags; real
capture feeds the existing sender
- share one wall-clock reference between the audio and video loops so
OBS receives aligned A/V timestamps (avoids multi-second latency)
Verified end-to-end: real desktop at 30 fps renders in OBS with
sub-second latency.
Stream a synthetic test pattern and silent PCM audio over the OBS
Teleport protocol:
- protocol: wire format (Header/ImageHeader/WaveHeader), BT.709 full
range colour matrix, JPEG encode via turbojpeg cgo, WAVE packet builder
- output: TCP sender with per-connection buffered channels and drop-on-overflow
- discovery: multicast announce via peerdiscovery
- cmd: teleportfling CLI with flags, test-pattern frame generator
Verified end-to-end: OBS discovers and renders the stream with correct
colours and motion.