package ffmpeg import ( "bytes" "context" "os" "os/exec" "strconv" "time" ) type FFmpeg struct { Out *bytes.Buffer Cmd *exec.Cmd Started bool Cancel context.CancelFunc Len time.Duration Title string Channel string err chan error fb chan bool } func NewFFmpeg(uri string, sampleRate int, channels int) (ff *FFmpeg, err error) { ff = new(FFmpeg) ctx, cancel := context.WithCancel(context.Background()) ff.Cancel = cancel ff.Cmd = exec.CommandContext( ctx, "ffmpeg", "-i", uri, "-f", "s16le", "-v", "error", //"-stats", "-ar", strconv.Itoa(sampleRate), "-ac", strconv.Itoa(channels), "-af", "loudnorm=I=-16:LRA=11:TP=-1.5", "pipe:1", ) ff.Cmd.Stderr = os.Stdin // FFmpeg requires a certain buffer size to start writing. This seems to be enough? // This will grow big enough to fit the whole song. ff.Out = bytes.NewBuffer(make([]byte, 128*1024)) ff.Cmd.Stdout = ff.Out return } func (ff *FFmpeg) Start() error { ff.Started = true err := ff.Cmd.Start() go func() { if err != nil { ff.err <- ff.Cmd.Wait() } }() return err } func (ff FFmpeg) Close() error { ff.Cancel() return nil }