I have a Go application in which I would like to stream live uncompressed audio to the browser. I was hoping to stream over HTTP by just having the browser open a URL corresponding to the stream, and then feeding that connection with the audio data.
I was planning on using WAV to send the data uncompressed, However the WAV file format requires the file size be predefined in the header. Is there a better container format for doing this streaming that I can work with easily in Go?
I know that one approach would be to use a proper streaming server and transcode my audio through that, but if I'm implementing this myself, is there a fairly straightforward way to get off the ground? Perhaps a Go library to make this easier?
Thanks
EDIT I've solved this via ffmpeg as outlined in my answer below
Ok, here's what I ended up doing, my Go code pipes the raw PCM data through an ffmpeg process which converts it to mp3. I assume packets
is a channel that my audio data is appearing over, and response
is an http.ResponseWriter
cmd := exec.Command("ffmpeg", "-v", "verbose", "-f", "u16le", "-ar", "44100", "-ac", "1", "-i", "-", "-f", "mp3", "-")
audioIn, err := cmd.StdinPipe()
if err != nil {
log.Println("Failed to create stdin pipe")
}
audioOut, err := cmd.StdoutPipe()
if err != nil {
log.Println("Failed to create stdout pipe")
}
err = cmd.Start()
if err != nil {
log.Println("Failed to start ffmpeg command, error: ", err)
}
go func() {
for {
packet := <-packets
audioIn.Write(packet.Payload)
}
}
go func() {
amount, err := io.Copy(response, audioOut)
if err != nil {
log.Println("io copy terminated with an error", err)
}
log.Printf("Done copying audio data: %d bytes
", amount)
}()
err = cmd.Wait()
if err != nil {
log.Println("ffmpeg command terminated incorrectly", err)
}
If you are still thinking about uncompressed WAVs for ultimate quality then I think you've got two choices
The first choice is easy to implement, but will mean naive browsers try to download a 2GB file instead of streaming it. I would hope that anything implementing HTML5 wouldn't be that naive, but I think you'd need to try it.
The second choice, adding additional chunks seems to be supported by the RIFF spec of which WAV files are a subset. You could then write a WAV file with multiple shorter chunks of sound data within. This should be supported by WAV players, but may not be as WAV files have never been particularly well standardised, and a lot of players just look for a 44 byte header which is not very RIFF compliant!
If I was you I'd try the first option first and see how that works out.