Shoestring & bubblegum sound server

Thursday, 1 Mar 2012 [Monday, 19 Mar 2012]

In which I beat MacGyver.I recently had need to play sound on a headless Linux machine. I started looking into sound servers, but everything I found seemed a significant amount of work to set up. I tried to reduce the problem to the fundamental parts involved, and by a trail of hints winding through a narrow mountain pass arrived at a rather… minimalist solution to fit my minimalist needs. I did not require anything else than to be able to hear sound at all and the solution did not require anything else of me than ALSA – and it’s hard to install a Linux machine without ALSA these days.

The entirety of the charade amounts to this:

  1. On the speakerless machine, load the loopback ALSA driver:

    modprobe snd-aloop index=0 pcm_substreams=1

    The driver provides a card with two sound devices, and when sound is output onto a stream on one device then the driver mirrors that as an input available on the same stream on the other device.

  2. Configure sound with an .asoundrc like this:

    pcm.!default {
      type dmix
      slave.pcm "hw:Loopback,0,0"
    }
    pcm.loop {
      type plug
      slave.pcm "hw:Loopback,1,0"
    }

    This has programs default to outputting sound to stream 0 of device 0 of the loopback (pseudo-)card, and has ALSA mixing their outputs together (type dmix). The loopback driver will make the resulting sound available for sampling via stream 0 of device 1, for which the configuration sets up another source called loop as a simple alias (type plug).

  3. On the machine with speakers you can then you can do this:

    ssh -C speakerless sox -q -t alsa loop -t wav -b 24 -r 48k - | play -q -

    The bolded portion configures sox’s input to use the ALSA type, and the underlined part (which is where normally a filename is given) gives name of the source – the loop alias from the configuration above. The rest of the switches tell sox to output 24-bit, 48 kHz WAV to standard output, to be picked up by ssh.

  4. Now play something on the speakerless machine.

This will push a constant stream of sample data down the wire, even during silence; with SSH compression enabled as it is here, that will come to something like 4 KB/sec and will very slightly busy the CPU on both machines. Both resource drains stop if you break the SSH connection. You can do so at all times without sound-playing programs on the speakerless machine ever noticing.

The one and only real drawback is a playback latency of a few fractions of a second – enough to be noticably not in real time.

But as I said, I had minimal needs of it.

[Update: added explanations.]