Stream audio to Snapcast server

Hi,

I have a main server running mopidy and snapcast server, on the same network I have a couple of RPI with snapcast clients.
These RPI have also rhasspy running, but the thing it’s that I don’t know how to simultaneously listen to music and audio output from rhasspy.

I though about piping audio from rhasspy to the snapcast server, so that it can be heard in all snapcast clients, which is what I’m actually doing with mopidy. Which sends output to snapcast server.

I defined a snapcast stream using a TCP server:

# /etc/snapserver.conf
stream = tcp://127.0.0.1:3333?name=mopidy_tcp 

Mopidy configuration have the following:

# /etc/mopidy/mopidy.conf
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! tcpclientsink host=127.0.0.1 port=3333

Then in the RPI satellites I tried the following custom command for audio output for rhasspy:

  • To use netcat to pipe the stdin audio to the snapcast server:
nc 192.168.IP.SERVER 3333 -
  • Use gstreamer (as used in mopidy) to pipe the audio:
gst-launch-1.0 -v fdsrc ! audio/x-raw,format=S16BE,channels=1,rate=8000 ! audioconvert ! audio/x-raw,format=S16LE,channels=1,rate=8000 ! wavenc ! tcpclientsink host=192.168.IP.SERVER port=3333

But both of them have unsuccessful results. I hear a noise sound in the snapcast clients. I think that it might be related with encoding of the audio. It’s difficult to debug gstreamer.

I saw that this have been discussed here Stream music or radio

But still there is no concrete answer.

If you hear noise, than the piping works.
So I think the key here is to find if the input is actually audio/x-raw,format=S16BE,channels=1,rate=8000

If you set the TTS to GoogleWavenet, you can set the rate to 22050.
The output will be S16LE mono with 22050 sample rate.

You could also try and save the audio to a file and inspect it with VLC or some other software

Thanks for you answer. I used gstream to dump the audio with the custom command:

gst-launch-1.0 -v fdsrc ! filesink location=captureRaw.wav

Then I can see the properties:

Playing /captureRaw.wav.
libavformat version 58.45.100 (external)
Audio only file format detected.
Load subtitles in /home/arch/
==========================================================================
Opening audio decoder: [pcm] Uncompressed PCM audio decoder
AUDIO: 16000 Hz, 1 ch, s16le, 256.0 kbit/100.00% (ratio: 32000->32000)
Selected audio codec: [pcm] afm: pcm (Uncompressed PCM)
==========================================================================

I uploaded the audio here, just in case: https://ufile.io/517tidlt

When I try just piping the raw input file to snapcast server I only hear noise and I receive the following message in the snapcast server:

(AsioStream) Error reading message: End of file, length: 2092

I think this might be related with the format. I think snapcast expects audio/x-raw,rate=48000,channels=2,format=S16LE. I’m trying to build the conversion pipeline but it’s not easy with gstreamer.

I just found the good pipeline:

gst-launch-1.0 -v fdsrc ! wavparse ! audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc !  tcpclientsink host=192.168.IP.SERVER port=3333

Great! gstreamer is indeed very hard to do.
Good work.
I tried it as well in the settings but I got errors, can you share a screenshot of your Audio Playing setting? Maybe I am entering the wrong parameters…

Thanks for the pipline. I have adapted it to use it with pulseaudio including ducking module in order to lower the volume of music when announcement is played. The rest of the setup seems similar, I also use snapcast to distribute the stream to several satellites.

Pipeline

gst-launch-1.0 -v fdsrc ! wavparse ! audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! pulsesink server=192.168.x.xx device=xx stream-properties=“props,media.role=announcement”

Since I did not manage to enter this via the Rhasspy web interface I decided to put this into a script and just put the script name as program in the audio playing section. (I just linked the script into the docker container: $PWD/pulse_tts.sh:/bin/pulse_tts.sh)

/edit
In order to make pulsesink work I had to install gstreamer pulse plugin (docker exec -u 0 -it Rhasspy apt install gstreamer1.0-pulseaudio)