package main import ( "flag" "fmt" "log" "os" "os/signal" "path/filepath" "syscall" "time" "github.com/Sendspin/sendspin-go/pkg/sendspin" "rpi-sendspin/internal/pipewire" ) func main() { server := flag.String("server", "localhost:8927", "server address") name := flag.String("name", hostname(), "player name") device := flag.String("device", "", "PipeWire sink node name (default: system default)") listDevices := flag.Bool("list-devices", false, "list available PipeWire sinks and exit") volume := flag.Int("volume", 80, "initial volume (0-100)") flag.Parse() if *listDevices { sinks, err := pipewire.ListSinks() if err != nil { log.Fatalf("list sinks: %v", err) } if len(sinks) == 0 { fmt.Println("no PipeWire sinks found") return } fmt.Println("Available PipeWire sinks:") for _, s := range sinks { fmt.Printf(" %s\n", s) } return } idFile := clientIDFile() savedID, _ := os.ReadFile(idFile) clientID, err := sendspin.ResolveClientID("", string(savedID), func(id string) error { if err := os.MkdirAll(filepath.Dir(idFile), 0700); err != nil { return err } return os.WriteFile(idFile, []byte(id), 0600) }) if err != nil { log.Fatalf("resolve client ID: %v", err) } output := pipewire.NewOutput(*device, *name) player, err := sendspin.NewPlayer(sendspin.PlayerConfig{ ServerAddr: *server, PlayerName: *name, ClientID: clientID, Volume: *volume, Output: output, Reconnect: sendspin.ReconnectConfig{ Enabled: true, InitialDelay: 2 * time.Second, MaxDelay: 30 * time.Second, Multiplier: 2.0, }, OnMetadata: func(meta sendspin.Metadata) { if meta.Artist != "" || meta.Title != "" { log.Printf("now playing: %s — %s", meta.Artist, meta.Title) } }, OnError: func(err error) { log.Printf("error: %v", err) }, }) if err != nil { log.Fatalf("create player: %v", err) } defer player.Close() if *device != "" { log.Printf("output: %s", *device) } else { log.Printf("output: PipeWire default sink") } log.Printf("connecting to %s as %q...", *server, *name) if err := player.Connect(); err != nil { log.Fatalf("connect: %v", err) } if err := player.Play(); err != nil { log.Fatalf("play: %v", err) } sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, syscall.SIGTERM) <-sig log.Println("stopping") player.Stop() } func hostname() string { h, _ := os.Hostname() if h == "" { return "sendspin-player" } return h } func clientIDFile() string { dir, err := os.UserConfigDir() if err != nil { dir = os.TempDir() } return filepath.Join(dir, "rpi-sendspin", "client_id") }