package snapcast import ( "context" "io" "log" "os" "os/exec" "strconv" "sync" "github.com/gopxl/beep" ) type Stream struct { sync.Mutex Out io.ReadCloser Cancel context.CancelFunc Cmd *exec.Cmd f beep.Format buf []byte } func New(host string, port int) (ff beep.Streamer, err error) { st := new(Stream) ctx, cancel := context.WithCancel(context.Background()) st.Cancel = cancel st.Cmd = exec.CommandContext( ctx, "/usr/bin/snapclient", "-h", host, "-p", strconv.Itoa(port), "--player", "file:filename=stderr", "--logfilter", "*:error", ) st.Cmd.Stdout = os.Stdin st.Out, err = st.Cmd.StderrPipe() if err != nil { return nil, err } err = st.Cmd.Start() if err != nil { return nil, err } st.buf = make([]byte, 4) st.f = beep.Format{ SampleRate: beep.SampleRate(48000), NumChannels: 2, Precision: 2, } return st, nil } func (d *Stream) Stream(samples [][2]float64) (n int, ok bool) { for i := range samples { _, err := d.Out.Read(d.buf) if err != nil { log.Println(err) ok = false break } samples[i], _ = d.f.DecodeSigned(d.buf) ok = true } return len(samples), ok } func (d *Stream) Err() error { return nil }