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 } 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 ff.Out = bytes.NewBuffer(make([]byte, 4096)) ff.Cmd.Stdout = ff.Out return } func (ff *FFmpeg) Start() error { err := ff.Cmd.Start() // We need to wait till the buffer starts filling up.. for ff.Out.Len() == 4096 { } ff.Started = true go func() { if err != nil { ff.err <- ff.Cmd.Wait() } }() return err } func (ff FFmpeg) Close() error { ff.Cancel() return nil }