latency - fcorthay/RPi-multiroom-audio GitHub Wiki
The important point about a multiroom system is that the receivers playing the same music have to be synchronous. The delay between two sounds in two neighbouring rooms have to be low enough not to be distinguished by the human ear.
Yet if a RPi has to play the sound output of a PC or a media player, a low latency (delay between the audio source and the loudspeaker sound) is of importance.
In order to measure the latency between a sound input to a RPi based system and the loudspeaker output one needs an Ananlog to Digital Converter (ADC) and an amplifier. This can be built with a HiFiBerry DAC and ADC board together with its companion power amplifier.
As a test file, one can use a single tone .wav
file generated with:
$AUDIO_BASE_DIR/LoudspeakerTest/buildSingleFrequency.py -r 0.01
The shortest path is from analog in to analog out.
Check who is driving the soundcard:
$AUDIO_BASE_DIR/Management/showInstallation.bash
Stop this service (adapt):
sudo service camilladsp stop
Now transfer audio in to audio out:
alsaloop -C hw:sndrpihifiberry -P plughw:sndrpihifiberry >/dev/null 2>&1 &
The plughw:
prefix lets the system adapt the samples format from input to output.
Play the sound file to the analog input and measure de delay from input to output, e.g. with an oscilloscope. With a RPi 3, I have had a delay of 12.5 ms.
End the audio transfer:
pkill alsaloop
The path from analog in to the Loopback
device and from there to the analog out
will later allow more flexibility.
Setup the path:
alsaloop -C hw:sndrpihifiberry -P plughw:Loopback,0,7 2>/dev/null & alsaloop -C hw:Loopback,1,7 -P plughw:sndrpihifiberry 2>/dev/null &
Play the sound to the analog input and measure de delay anew. With a RPi 3, I have had a delay of 25.3 ms.
Close the audio path:
pkill alsaloop
CamillaDSP allows to implement some processing on the audio being played.
A processing path from input to output can be established by editing $CAMILLA_CONFIGURATIONS_DIR/passthroughFromRecord.yaml
:
--- devices: samplerate: 48000 chunksize: 256 capture: type: Alsa channels: 2 device: "hw:sndrpihifiberry" format: S32LE playback: type: Alsa channels: 2 device: "dmix:sndrpihifiberry" format: S32LE mixers: passthrough: channels: in: 2 out: 2 mapping: - dest: 0 sources: - channel: 0 gain: 0 inverted: false - dest: 1 sources: - channel: 1 gain: 0 inverted: false pipeline: - type: Mixer name: passthrough
As the DSP sends its output to a dmix
device, one can reestablish the previous full functional path,
but set the snapcast
volume to zero:
sudo service camilladsp restart SNAPCAST_SERVER=`cat /etc/default/snapclient | grep ^SNAPCLIENT_OPTS | sed "s/.*--host\s*//" | sed "s/[ \"].*//"` $AUDIO_BASE_DIR/Snapcast/setVolume.py -s $SNAPCAST_SERVER $(hostname) 0
Run the DSP:
/opt/camilladsp $CAMILLA_CONFIGURATIONS_DIR/passthroughFromRecord.yaml
Playing a sound and measuring the delay gives:
-
12.7 ms with
chunksize: 256
-
45.2 ms with
chunksize: 1024
-
88.1 ms with
chunksize: 2048
chunksize: 256
issues a warning suggesting to use a period of 1024 samples.
Changing the passthrough to an 8th order IIR gives:
-
23.6 ms with
chunksize: 256
-
46.1 ms with
chunksize: 1024
-
89.4 ms with
chunksize: 2048
Changing to a FIR of order 1001 gives:
-
40.0 ms with
chunksize: 256
-
60.3 ms with
chunksize: 1024
-
100.5 ms with
chunksize: 2048
Streaming over Ethernet can induce latency due to the buffering of the samples in order to build packets and to fill gaps in case of the late arrival of some of them.
Sound Exchange SoX allows many different audio manipulations, including low latency (?) streaming. It can interact with ALSA devices.
Install it both on the computer and the RPi:
sudo apt install -y sox
On the RPi, stream a sound to an ALSA device:
amixer -D hw:$AMPLIFIER_SOUNDCARD get Digital amixer -D hw:$AMPLIFIER_SOUNDCARD sset Digital 90% sox /usr/share/sounds/alsa/Front_Center.wav -t alsa dmix:$AMPLIFIER_SOUNDCARD
On the computer, install non-interactive ssh password authentication:
sudo apt install sshpass
Provide RPi ssh password (adapt):
sudo apt install sshpass echo amp > ~/.passwords/audioAmps chmod 600 ~/.passwords/audioAmps
With this, stream sound to the RPi over Ethernet (adapt host and soundcard):
HOST='[email protected]' sshpass -f ~/.passwords/audioAmps ssh $HOST aplay -l | grep ^card AMPLIFIER_SOUNDCARD='sndrpijustboomd' sox /usr/share/sounds/alsa/Front_Center.wav -p | sshpass -f ~/.passwords/audioAmps ssh $HOST sox -p -t alsa dmix:$AMPLIFIER_SOUNDCARD
VideoLAN media player (VLC) allows to play audio and video using the Graphical User Interface (GUI).
As we are going to stream from ALSA on the PC to ALSA on the RPi, make sure to have installed ALSA loopback on the PC:
sudo bash -c 'cat << EOF > /etc/modules-load.d/aloop.conf # alsa loopback snd snd-timer snd-pcm snd-aloop EOF' sudo modprobe snd-aloop
On the PC, launch VLC with its audio output sent to the ALSA loopbcak device:
LOOPBACK_SUBDEVICE='7' vlc -A alsa --alsa-audio-device dmix:Loopback,0,$LOOPBACK_SUBDEVICE >/dev/null 2>&1 &
Choose any music or video and play it.
Stream the audio to the RPi (adapt soundcard and host):
HOST='[email protected]' ssh $HOST aplay -l | grep ^card AMPLIFIER_SOUNDCARD='sndrpijustboomd' sox -t alsa plughw:Loopback,1,$LOOPBACK_SUBDEVICE -p 2>/dev/null | sshpass -f ~/.passwords/audioAmps ssh $HOST sox -p -t alsa dmix:$AMPLIFIER_SOUNDCARD 2>/dev/null &
The audio can show some lagging from the video.
If this is the case, play with the keyboard keys j
and k
to change the audio delay.
It is also possible to add --delay-time -100
in the invocation of VLC
.
Terminate the streaming:
pkill sox
For a room hosting a pair of actively driven loudspeakers, one can have a pair of RPi audio amplifiers, each driving one of the loudspeakers. In this situation, one can stream the audio to one of the RPi's and have it both forward it to the other RPi and split it for the two local loudspeaker drivers.
Streaming audio over Ethernet is not done directly to the loudspeaker outputs but to the RPi's Loopback
device,
as the DSP takes the audio from this device and splits the audio frequencies to the different loudspeaker drivers
[1].
Stream a sound to one of the RPi's (adapt host and loopback device):
HOST='[email protected]' sshpass -f ~/.passwords/audioAmps ssh $HOST /home/amp/RPi-multiroom-audio/Management/showInstallation.bash LOOPBACK='dmix:Loopback,0,0' sox /usr/share/sounds/alsa/Front_Center.wav -p | sshpass -f ~/.passwords/audioAmps ssh $HOST sox -p -t alsa $LOOPBACK
My experience is that I have to either pause mopidy or mute snapclient on the RPi in order to be able to stream audio to the loopback device from sox.
- ^ In fact, several options are available. Instead of streaming to the same loopback entry as the (snapclient) multiroom audio, one could wish to stream to a free loopback entry and start another CamillaDSP instance with a different audio processing, as for example a crossover with a lower latency (IIR vs FIR).