mikebrady / shairport-sync

AirPlay and AirPlay 2 audio player
Other
7.24k stars 573 forks source link

Shairport>Darkice>Icecast2 > Sonos or Squeezebox #701

Closed choppedfish closed 3 years ago

choppedfish commented 6 years ago

Hi, I've got a RPi3 running Raspbian lite - latest build from 3 days ago.

I compiled shairport-sync, darkice and icecast2 and had instance success airplaying from my IOS devices to my squeezeboxes (as a radio station).

The next step is to have multiple shairport-sync process running for multiple airplay targets. I did follow post #37 but it took a while before I discovered it was a little out of date in a few things and I could never get the second process running.

That all said I think part of the issue is with the alsa devices. The config file for shairport-sync is very basic and contains the items below. general = { name = "ByronAirplay"; interpolation = "soxr"; };

alsa = { output_device = "hw:1,0"; };

darkice.cfg contains the following relevant info: [input] device = hw:Loopback,1,0

Running as above their is no sound via icecast.

Running with the alsa output_device commented out works fine, therefore the default device is being chosen (whatever that is)..

I've tried variations such as hw:1,0 hw:0,1 hw:1 etc. and nothing seems to work.

I assume the syntax or somesuch for the alsa device is incorrect but i've tried many variations with no avail. I assume shairport-sync and darkice have to match.

The alsa devices are listed below. pi@ByronAirplay:/etc $ aplay -l List of PLAYBACK Hardware Devices card 0: Loopback [Loopback], device 0: Loopback PCM [Loopback PCM] Subdevices: 8/8 Subdevice #0: subdevice #0 Subdevice #1: subdevice #1 Subdevice #2: subdevice #2 Subdevice #3: subdevice #3 Subdevice #4: subdevice #4 Subdevice #5: subdevice #5 Subdevice #6: subdevice #6 Subdevice #7: subdevice #7 card 0: Loopback [Loopback], device 1: Loopback PCM [Loopback PCM] Subdevices: 8/8 Subdevice #0: subdevice #0 Subdevice #1: subdevice #1 Subdevice #2: subdevice #2 Subdevice #3: subdevice #3 Subdevice #4: subdevice #4 Subdevice #5: subdevice #5 Subdevice #6: subdevice #6 Subdevice #7: subdevice #7 card 1: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA] Subdevices: 7/7 Subdevice #0: subdevice #0 Subdevice #1: subdevice #1 Subdevice #2: subdevice #2 Subdevice #3: subdevice #3 Subdevice #4: subdevice #4 Subdevice #5: subdevice #5 Subdevice #6: subdevice #6 card 1: ALSA [bcm2835 ALSA], device 1: bcm2835 ALSA [bcm2835 IEC958/HDMI] Subdevices: 1/1 Subdevice #0: subdevice #0

Obviously I need to have different devices if i'm to run multiple shairport-sync processes so this is a major stumbling block.

Thanks

Byron

mikebrady commented 6 years ago

Thanks for the post. I haven’t tried this kind of thing before, and to be honest, Shairport Sync was designed for output to a real sound card that returns status and delay information. I am not sure if the loopback device returns that kind of information.

That said, I suppose the way to move forward is to get the loopback stuff working with something like aplay rather than using Shairport Sync. If you could get a 44.1k 16-bit stereo sound file, can you play it using aplay into the loopback?

Another possibility is to use alsamixer to see what output devices are there. Once you have found and selected the device, if you then then use the F6 function key, you’ll see the address of the selected device under the cursor.

Maybe someone else has other suggestions...

choppedfish commented 6 years ago

Thanks Mike, let me follow your ideas and see what happens. Using the default device does work for sure. I'm trying to avoid buying multiple pi's if I can.

I got the idea from a few places, but the main one being this write up. https://gist.github.com/bmweiner/f80e7aaeca5bcee1db46e56914b415fa

I will play some more and post back.

Thanks

Byron

choppedfish commented 6 years ago

Hi,

I've made some progress and understand alsa loopback somewhat.

Basically the device in shairport-sync.conf needs to be something like: device = "hw:Loopback,0,0" - this is the default device

In darkice it needs to be hw::Loopback,1,0

So card 0 is where shairport sends audio and card 1 is where darkice receives it. This makes a loopback pair.

I then went further and made a 2nd instance of darkice and shairport-sync with different ports and devices hw:Loopback,0,1 (shairport) and hw:Loopback,1,1 (darkice) respectively.

Both were running fine but in a simple test the first shairport would crash. I tried messing with subdevices (ie. hw:Loopback,0,0,0" but despite what the doco says that is not valid.

Unfortunately now even the first shairport-sync crashes with a segmentation fault.

I will test with soxr off as I gather even a pi3b may not be powerful enough.

Byron

choppedfish commented 6 years ago

I upgraded to the latest version of shairport-sync and magically it works and it seems stable with some basic testing. I've turned of soxr interpolation which may not have helped, but sounds fine and I can airplay from 2 IOS devices to the airplay receivers and then tune into them on the squeezeboxes as planned.

Volume changes work and the lag is no worse than with a radio station. I may look at reducing lag but it works which is important.

Byron

mikebrady commented 6 years ago

Thanks Byron. The have been quite a few fixes in the last few weeks, and for this kind of work, you're probably better off on the development branch because it's always got the most recent fixes in it and would be easer to modify for further testing. You're right about the soxr interpolation; to interpolate one 8 millisecond packet takes around 20 milliseconds on an RPi, so the CPU can be swamped if too much interpolation is needed. For normal audio, it's hard to distinguish anyway.

choppedfish commented 6 years ago

I've now added 2 more Airplay targets for a total of 4. These are showing up in the squeezebox as radio stations which means I can avoid buying a whole new setup just to get airplay to the end devices (which work fine). There is a tiny bit of lag induced by the squeezebox server as it caches (3 seconds), but it's acceptable.

So effectively I have: 1) 4 x shairport-sync each with their own service (i.e. shairport-sync1.service) and config file. Each config has a different name, different port (5000,5001, 5002 and 5003), and udp_base_port (6101.6201.6301 and 6401) with ranges of 100 each. I could probably narrow that but it works as i'm not using metadata (no way to use it).

I use the same executable for each so each /lib/systemd/system/shairport-syncUNIQUENAME.service has; ExecStart=/usr/local/bin/shairport-sync -c /etc/shairport-syncUNIQUE NAME.conf

i.e. service file [Unit] Description=ShairportSync AirTunes receiver Niamh After=sound.target Requires=avahi-daemon.service After=avahi-daemon.service Wants=network-online.target After=network.target network-online.target [Service] ExecStart=/usr/local/bin/shairport-sync -c /etc/shairport-syncUNIQUENAME.conf [Install] WantedBy=multi-user.target

i.e. conf file. general = { name = "UNIQUENAMEAirplay"; port = 5102; udp_port_base = 6301; udp_port_range = 100; };

alsa = { output_device = "hw:Loopback,0,2"; };

NOTE: I use basic interpolation as soxr kills the CPU.

On the output device pairs they are as follows; shairport-sync1 - output device = hw:Loopback,0,0 shairport-sync2 - output device = hw:Loopback,0,1 shairport-sync3 - output device = hw:Loopback,0,2 shairport-sync4 - output device = hw:Loopback,0,3

This is selecting card 0, subdevice 0 through 4.

The corresponding ones in darkice are: darkice1 - device = hw:Loopback,1,0 darkice2 - device = hw:Loopback,1,1 darkice3 - device = hw:Loopback,1,2 darkice4 - device = hw:Loopback,1,3

Don't forget to do the following to ensure it all starts on reboot; sudo systemctl daemon-reload sudo systemctl start shairport-syncUNIQUENAME.service sudo systemctl enable darkiceUNIQUENAME.service

2) 4 x darkice each with their own service (i.e. darkiceUNIQUENAME.service) and config file. Each config file has the same airplay name as corresponding shairport-syncUNIQUE NAME. The device is as above. The port is incremented from 8000 to 8003 so each stream is unique when its sent to icecast2.

i.e. service file Create and edit /etc/systemd/system/darkiceNiamh.service: [Unit] Description=DarkIce Live audio stream After=icecast2.service [Service] execStart=/usr/bin/darkice -c /etc/darkiceUNIQUENAME.cfg [Install] WantedBy=multi-user.target

i.e. conf file [general] duration = 0 bufferSecs = 1 reconnect = yes realtime = yes rtprio = 3 [input] device = hw:Loopback,1,2 sampleRate = 44100 bitsPerSample = 16 channel = 2 [icecast2-0] bitrateMode = vbr format = mp3 quality = 1.0 server = localhost port = 8002 password = password mountPoint = UNIQUENAMEAirplay name = UNIQUENAMEAirplay

NOTE: the name of the airplay target must be the same in shairport-sync and darkice or it won't work. NOTE2: VBR uses a lot less CPU than CBR.

don't forget the following for each; sudo systemctl daemon-reload sudo systemctl start darkiceUNIQUENAME.service sudo systemctl enable darkiceUNIQUENAME.service

3) icecast2 - the only thing here really is to edit icecast.xml in /etc/icecast2 and add ports to match darkice, set up the client and sources to match and make sure the passwords match in darkice and icecast2 under the authentication section.

20 4 AirPi
<listen-socket>
    <port>8000</port>
</listen-socket>

<listen-socket>
    <port>8001</port>
</listen-socket>

<listen-socket>
    <port>8002</port>
</listen-socket>

<listen-socket>
    <port>8003</port>
</listen-socket>

4) setup the radio stations in squeezebox - I make them as favourites and the URL is http://192.168.1.71:8000/NiamhUNIQUENAME.m3u

NOTE The port above is always 8000 as that's what icecast broadcasts on. The ports 8000,8001, 8002, 8003 are between darkice and icecast2.

5) I have tested 4 devices airplaying at the same time to 4 squeezeboxes and all seems fine. No drop outs or lag. Running top shows each darkice process is using 15-20% CPU. and each shairport 3-4%. This is on a RPIB+.

Thanks to Mike for his hard work and of course the developers for darkice and icecast2.

Byron

mikebrady commented 6 years ago

Many thanks for this, Byron!

tekdoc commented 6 years ago

@choppedfish, I have been running a similar setup with an OrangePi PC and a Roku Soundbridge for a couple years. To reduce your CPU usage you might want to try ffmpeg (compiled with libshine) instead of darkice. My command line looks something like this:

/usr/bin/ffmpeg -loglevel fatal -f alsa -ac 2 -ar 44100 -i hw:Loopback,1,0 -c:a libshine -b:a 320k -content_type audio/mpeg -ice_name "AirPlay" -f mp3 icecast://source:hackme@localhost:8000/stream
github-actions[bot] commented 3 years ago

This issue has been inactive for 60 days so will be closed 7 days from now. To prevent this, please remove the "stale" label or post a comment.