// Command teleportfling is a standalone sender for the Teleport protocol. // // It captures a Wayland screen (PipeWire via xdg-desktop-portal) plus the // system's default audio output and streams them over TCP as the Teleport // protocol, announcing itself on the LAN multicast group so an OBS instance // with the obs-teleport plugin can discover and decode the stream. // // This is the headless/CLI entry point; the engine lives in // internal/flinger. A desktop GUI with settings and a system tray is in // cmd/teleportfling-gui. // // Usage: // // teleportfling [--name NAME] [--port PORT] [--quality 1..100] // [--fps N] [--source screen|pattern] [--audio] // [--stream-index N] [--duration SECONDS] // // --source pattern selects the M1 synthetic test pattern (colour bars with a // moving box) instead of real screen capture, which is useful for testing // without granting screen-share permission. package main import ( "flag" "log" "os" "os/signal" "syscall" "time" "teleportfling/internal/flinger" ) func main() { var ( name = flag.String("name", "", "announce name (default: hostname)") port = flag.Int("port", 9756, "TCP listening port") quality = flag.Int("quality", 80, "JPEG quality 1..100") fps = flag.Int("fps", 30, "video frames per second") source = flag.String("source", "screen", "capture source: screen or pattern") withAudio = flag.Bool("audio", true, "capture and stream system audio") streamIndex = flag.Int("stream-index", 0, "monitor index to capture (screen source)") duration = flag.Duration("duration", 0, "stream duration (0 = run until interrupted)") ) flag.Parse() cfg := flinger.Config{ Name: *name, Port: *port, Quality: *quality, FPS: *fps, Source: *source, Audio: *withAudio, StreamIndex: *streamIndex, } eng, err := flinger.New(cfg) if err != nil { log.Fatalf("flinger: %v", err) } eng.Start() log.Printf("teleportfling: streaming from source %q", cfg.Source) // Interrupt / SIGTERM handling. sigc := make(chan os.Signal, 1) signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM) select { case <-sigc: log.Printf("teleportfling: stopping…") case <-func() <-chan struct{} { if *duration > 0 { ch := make(chan struct{}) time.AfterFunc(*duration, func() { close(ch) }) return ch } return nil }(): log.Printf("teleportfling: duration reached") } eng.Stop() log.Printf("teleportfling: stopped") }