/audiostreamer

Stream audio from a PulseAudio source to HTTP (MP3)

Primary LanguageCGNU General Public License v3.0GPL-3.0

This is a daemon and companion website to stream audio. I use it to stream from my system's audio to an <audio> element. It outputs MP3 audio.

I thought it would be fun to be able to share what I am playing on my local media player on a simple website. I wanted to take the audio directly from PulseAudio and make it available in an <audio> element.

To do this, I've written a C library to read/decode audio from PulseAudio and then encode/write it out as MP3. I use the library in Go with cgo.

Essentially this gives me a simple daemon I can start that will livestream my system's audio.

Requirements

  • ffmpeg (libavcodec, libavformat, libavdevice, libavutil, libswresample). I developed using 3.2.2. On Debian this is in the package libavutil-dev.
  • C compiler. I developed using gcc 6.2.1.
  • Go. I developed using 1.7.3.
  • The track display feature depends on accessing a song_tracker API. This is optional however.

Installation

  • go get github.com/horgh/audiostreamer
  • go build
  • Place index.html somewhere accessible. Update the song_tracker_url and the <audio> element src attribute. If you don't want to use the song tracker, then set song_tracker_url to a blank string.
  • Run the daemon. Its usage output shows the possible flags. There is no configuration file.

Components

  • audiostreamer: A Go daemon that serves HTTP requests to stream audio as MP3.
  • audiostreamer.h: A library that uses ffmpeg to read/decode from PulseAudio and encode/write to MP3.
  • index.html: A website containing an <audio> element that lets us stream audio from the daemon. It also displays the currently playing track (by polling a song_tracker API). In the case of daemon restart, clients try to reconnect endlessly.
  • transcode_example: A sample C program that uses audiostreamer.h to transcode to a file.

Notes

  • In general MP3 is not a streamable format. To make it possible to slice and start streaming from anywhere (if an encode is already in progress), I disable the MP3 bit reservoir. This means I can have just one encoded stream for any number of streaming clients.
  • In theory output can be any audio format/codec. In a few places I have hardcoded use of MP3. To switch to a different output format/codec, it is likely sufficient to change the outputFormat and outputEncoder in encoder(), and adjust the Content-Type in audioRequest(). You must make sure the format/codec is streamable and that it is valid to send audio frames starting from any point, as that is the current behaviour.
  • In theory input can be from a file. In fact this does work, for a given value of work. Right now the daemon decodes as quickly as it can. When taken from a PulseAudio input the daemon is throttled as the audio is real time. From a file however there is no such limit, and it will consume 100% CPU (one thread). As well, it decodes the same file over and over. As my main use case is to stream from PulseAudio I have chosen to leave this as is as adjusting it introduces complexity.