jakemoroni / audio_async_loopback

Real-time S/PDIF PCM/AC3 capture and playback
GNU General Public License v3.0
25 stars 7 forks source link

audio_async_loopback

Real-time S/PDIF PCM/AC3 capture and playback

A simple program to play audio from an S/PDIF input, in real-time.

Requires Pulseaudio, libavcodec, and libsamplerate.

It supports uncompressed PCM as well as IEC 61937-3 (AC3) bitstreams.

When an IEC 61937 AC3 bitstream is detected, it automatically begins decoding it into 5.1 channel audio. If there are no IEC 61937 data bursts found within a given time window, it switches back to PCM mode.

Why not just use pacat and pipe it into ffplay/mpv/vlc/whatever? Or Pulseaudio's module_loopback?

To address this clock domain issue, the audio samples are passed through a resampler with a ratio that is dynamically adjusted to attempt to maintain a constant amount of data in the intermediate buffer at any given time. This compensates for any slight differences in sampling rate between the input and output.

One of the goals was to maintain as low of a latency as possible, so a lot of the parameters are fairly aggressive, resulting in high CPU usage. These parameters can be tweaked (see config.h), and will probably need to be adjusted depending on your system.

In my system, I typically see about ~15 milliseconds of latency with PCM audio, and ~45 with AC3 bitstreams. The reason AC3 bitstreams have more latency is because it's decoded on a per-frame basis, and each AC3 frame typically represents 1536 PCM samples (33 milliseconds at 48 kHz).

In order for this program to work for AC3, it requires an S/PDIF input that is capable of capturing bit-perfect audio. Many S/PDIF inputs will do things like internal resampling, mixing, volume control, etc., which will break any compressed bitstream format. Other inputs will automatically mute the audio if the non-PCM IEC 60958 channel status bit is set, which is also a problem.

I was able to get this working using the miniDSP USBStreamer B with the stereo firmware loaded. Just make sure Pulseaudio is configured for 48 kHz and that the volume is set to 100%.

NOTE: There are a lot of loose ends in this program. I made it for my own personal use. I'm sure there are bugs, but it works fine for me.