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 xdg-desktop-portal ScreenCast fallback to monitor enumeration so
the GUI picker works on compositors without hyprctl (GNOME/KDE etc.).
ListMonitors now tries hyprctl first, then creates a portal session,
selects monitor sources, starts capture and parses the stream list.
Verified on Hyprland: the portal path returns the 1920x1200 monitor,
confirming the compositor-agnostic mechanism works.
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.
Enumerate monitors via hyprctl (Hyprland) and present them as a
dropdown in the settings window instead of a raw index. The picker is
enabled only for the screen source and persists the selected monitor as
stream_index. Falls back to a single indexed option when enumeration is
unavailable (non-Hyprland).
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.
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
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.