Due to a regretable headset cable incident, I ended up needing to stream low latency system audio (I.E. everything you’d hear from your PC) over a network to another computer. And when I say low latency, I mean low enough that I can still play a video game or youtube video without there being enough of a difference to be distracting. Turns out this is actually pretty easy and you can just use ffmpeg1.
The key thing here is the “Stereo Mix” audio device on Windows. It is a “virtual” recording device which provides, as an input, the current audio output thats going to your default playback device. It’s not enabled by default, and also seems to be provided by the manufacturers audio drivers - I had to install a driver package from the manufacturer of the audio chipset in my system (as opposed to just using the default windows drivers) to get it to show up.
This done, we can now run ffmpeg on the source machine.
ffmpeg.exe -f dshow -audio_buffer_size 50 -i audio="Stereo Mix (Realtek High Definition Audio)" -f s16le udp://10.0.0.10:1234
to break this down a little:
-f dshow -audio_buffer_size 50 -i audio="Stereo Mix (Realtek High Definition Audio)"This relates to our input.
-f dshowset the dshow (Windows DirectShow) input file format
-audio_buffer_size 50is a dshow parameter - it sets the buffer size to 50ms to reduce latency
-i audio="Stereo Mix (Realtek High Definition Audio)"- This is the audio device to capture from. The name needs to match exactly!
-f s16le udp://10.0.0.10:1234
-f s16le- set our output sample format - signed, 16-bit little endian uncompressed PCM
udp://10.0.0.10:1234- protocol (
udp) and destination (
Then, on the receiving side…
ffplay -i udp://10.0.0.10:1234 -f s16le -ac 2
Again, to break this down:
-i udp://:1234- fairly self explainatory! Our input is
1234. We don’t specify the destination IP but could do if we needed to.
-f s16le- Tell ffmpeg what format the incoming audio data is in. If you don’t set this, ffmpeg doesn’t know how to process the audio packets and at least for me just didn’t play anything. If you get it wrong, and say interpret little endian encoded data as big endian, you are most likely to get something a) quite loud and b) quite unpleasant :-)
-ac 2- interpret the input as having 2 channels - I.E. stereo. Fun note - I didn’t add this initially, and as a result ffmpeg defaulted to interpreting it as mono, meaning the audio I was playing played at 0.5x speed. Still sounded kinda good tho.
So anyway, that’s about it. Nothing very special going on here. I was pleasantly suprised at how usable and low latency this was - there’s a perceivable delay, but it’s not distractingly large. I was also surprised that this works remarkably well over the internet too, so long as your upload bandwidth is sufficient!
Because of course it can ↩︎