Streaming audio over network

A project log for Onion Omega Media Center

Onion Omega-based Home Media Center with Remote control and WiFi/Ethernet connectivity

andriymalyshenkoandriy.malyshenko 01/28/2021 at 22:160 Comments

Below are the steps that I took to configure Onion Omega Hi-Fi as network streaming node.

As I've mentioned before I use mopidy as music server. It runs in docker actually on one of the SBCs within my network. As I did describe before I use pulseaudio on raspberry or orange pi connected to DAC and them to amp. Therefore it looks like this

[Music Server with Mopidy] => [pulsesink] -> [ethernet] -> [pulse-daemon] => [Raspberry with DAC] -> [Power Amp].

Now here with Omega this setup is failing unfortunately. Pulse (or rather alsa) is somehow broken on Omega,  and as long as you install it Omega will go into boot loop with kernel panic message as soon as pulseaudio starts.

Therefore I was looking for alternative solution. Luckly mopidy uses GStreamer, which is extremely flexible in possibilities. 

First let's prepare Omega to accept network stream with Gstreamer

# you may need to uncomment feeds in /etc/opkg/distfeeds.conf
root@Omega-365D:~# opkg update
root@Omega-365D:~# opkg install gstreamer1 gstreamer1-utils gst1-plugins-base gst1-mod-udp

 Now let's make sure that we already have configured I2S audio that is working fine

root@Omega-365D:~# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: AudioI2S [Audio-I2S], device 0: ralink-i2s-HiFi HiFi-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Test if gstreamer able to speak to alsa

# this should produce tone sound in the speakers
root@Omega-365D:~# gst-launch-1.0 audiotestsrc ! audioconvert ! audio/x-raw,format=S16LE,channels=2,rate=44100 ! alsasink -v

Here we have to do audioconvert to format that kernel module would accept. Unfortunatelt at ths stage this is the only format it would accept actually. Every other will crach gstreamer at best and leads to kernel panic at worst. But for now this will do.,

Now let's start gstreamer listening on udp for data to come

# we start listening on udp port 5000 and expect to have specific format that alsa would accept
# then stream is sent to alsa device, since we have just one, no parameters needed
root@Omega-365D:~# gst-launch-1.0 -v udpsrc port=5000 caps="audio/x-raw, rate=(int)44100, format=(string)S16LE, channels=(int)2, layout=(string)interleaved" ! audioconvert ! alsasink -v

If it wouldn't crash it is a good sign, now it is ready to accept the data.

Now let's start test audio on any node within network where Onion is sitting. My Onion has ip therefore this is the commend i run on my laptop

# this should produce the same sine tone, but this time it is generated on laptop and rendered on Onion
dronische@dronische-desktop:~$ gst-launch-1.0 -v audiotestsrc ! audioconvert ! audio/x-raw,format=S16LE,channels=2,rate=44100 ! udpsink host= auto-multicast=true port=5000

If you hear tone again than it works,

Now back to Omega. Below lines I add to /etc/rc.local

omega2-ctrl gpiomux set i2s i2s

gst-launch-1.0 udpsrc port=5000 buffer-size=102400 caps="audio/x-raw, rate=(int)44100, format=(string)S16LE, channels=(int)2, layout=(string)interleaved" ! audioconvert ! alsasink &

exit 0

 Additinal property added here is buffer-size that makes streaming over wifi a bit smoother

And last configuration for mopidy should have this line on the audio output section

    output="audioconvert ! audio/x-raw,format=S16LE,channels=2,rate=44100 ! audioconvert ! rtpL24pay ! udpsink host= auto-multicast=true port=5000"

Once again  buffer is added. And also we need to convert audio to format that is accepted by Onion. Conversion is possible on the Omega side, but it takes half CPU time, therefore leave it for big machines


- Instead of rc.local we should use service script in /etc/init.d

- I need to figure out how to feed 24 or 32 bit format, since PCM5102 happily supports it. It is not that I'm not happy with 16 bits (Audio CD quality), but it is a shame not to use DAC fully

- I need to stream audio via rtpL24pay and rtpL24depay converters, but for now didn't figure out how to ensure raw audio format 

- Since udp is fire-and-forget format it is okay to stream offline devices as well. Therefore I want to add multiple usp destinations in the future to have simultaneous syncronized  stream to few Onions at the same time.

- I need to be able to detect id audio is present on Omega to enbale amp auto on/off capability