mikebrady / shairport-sync

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

Signal to get shairport-sync to re-open ALSA (and re-read .asoundrc or /etc/asound.conf)? #1030

Closed derekatkins closed 3 years ago

derekatkins commented 4 years ago

I've been trying to make my own multi-zone shairport-sync workaround. I have a single Wandboard ARM server running shairport-sync with 16 USB audio devices each plugged into a different zone throughout my house. If I run with iTunes on a Mac I can select multiple zones and play to them, however that doesn't work with e.g. Amazon Music (on any platform). I found node-airplayhub ( https://github.com/noelhibbard/node-airplayhub ) but even after I successfully got it working I was not able to get it to play anything to any shairport-sync zone (apparently this is a known issue with the underlying node-airtunes). So I was looking for another way to combine zones... Which I found I can do by creating a new alsa meta-device that copies the stream to multiple alsa devices at once. This worked quite well with a static configuration. However, I'd like to make the configuration more dynamic. I know that if I stop and restart shairport-sync it will re-read the .asoundrc and/or /etc/asound.conf file. What I DON'T know is if there is a way to get the program (via libalsa) to re-read the config file? And if there is, is there a way to signal shairport-sync to perform that re-read? Alternately, would there be some way to set up shairport-sync to send output to multiple output_devices simultaneously? And then re-read the shairport-sync.conf file?

mikebrady commented 4 years ago

Thanks for the interesting post.

Sadly, there isn't any way to get Shairport Sync to re-read its configuration file, nor can it change output device or output backend after startup.

Built on the premise that the configuration would be static after startup, it would take a major effort to rebuild the application to be capable of responding dynamically to configuration changes.

derekatkins commented 4 years ago

Is it possible to get shairport-sync to output to multiple devices? (I honestly have no idea if Alsa even supports that).

Worst case I build a service to rebuild the .asoundrc config and then systemctl restart the shairport service, but of course that would require re-starting the client playing. However I don't expect that to be a common occurrence (reconfiguring my multi-zone).

Ahh, well. Just waiting for Airplay2 support ;)

mikebrady commented 4 years ago

It is not possible to get Shairport Sync to output to multiple devices, but you can run multiple instances of Shairport Sync on one device.

Yeah, AirPlay 2 is a tough one... 😊

derekatkins commented 4 years ago

I'm currently running 16 instances of shairport-sync on the same device. But that only helps me when running from iTunes on a Mac. When I run on an iDevice or Amazon Music (even on a Mac) I can only set one Airplay target, which means if I want to play to multiple zones I either need:

  1. Airplay 2
  2. Shairport to be able to output to multiple zones
  3. Something like the AirplayHub to actually work, or
  4. I need to build an Alsa MultiZone zone

I chose option 4, (as option 3 didn't work once I got it installed on a 3-year-old Fedora platform because it wouldn't install on a modern Fedora platform). Of course this does not really allow for easy, dynamic modification of the zones.

I'm curious, now that Airplay2 has been reverse-engineered and there are, e.g. Java implementations of an Airplay2 server, what's so tough about it (rather than the fact that it requires re-coding in C?)

mikebrady commented 4 years ago

To the best of my knowledge, AirPlay 2 has not been successfully reverse engineered in any form – that's the problem.

derekatkins commented 4 years ago

So I guess https://github.com/serezhka/java-airplay-server and https://www.programmersought.com/article/2084789418/ are not a sufficient starting point? (I saw these posted in Issue #535). The former certainly seems to imply a screen-share capability?

mikebrady commented 4 years ago

Don't know anything about the first one. Pretty sure the second one relied on a loophole that has since been closed.

derekatkins commented 4 years ago

The first one, combined with https://github.com/serezhka/java-airplay-lib -- CLAIMS to be an Airplay2 implementation in Java. I haven't explored it deeply, but latest code changes were ~4 months ago.

derekatkins commented 4 years ago

FWIW, here is the .asoundrc I came up with. Each underlying device has a shariport-sync in front it, and this file creates a multioutput device that sits behind a shairport "Multi Out" target. (I don't know if there is a way to streamline the bindings like I did with the route_policy):

pcm.multioutput {
     type plug
     slave.pcm {
         type multi
         slaves {
             a { pcm "hw:USBsound01" channels 2 } # Basement Play
             b { pcm "hw:USBsound10" channels 2 } # Kitchen
             c { pcm "hw:USBsound02" channels 2 } # Driveway
             d { pcm "hw:USBsound15" channels 2 } # Pool
             e { pcm "hw:USBsound16" channels 2 } # Deck
         }
         bindings [
             { slave a channel 0 }
             { slave a channel 1 }
             { slave b channel 0 }
             { slave b channel 1 }
             { slave c channel 0 }
             { slave c channel 1 }
             { slave d channel 0 }
             { slave d channel 1 }
             { slave e channel 0 }
             { slave e channel 1 }
         ]
     }
     route_policy duplicate
}
noelhibbard commented 4 years ago

@derekatkins , I have been on the same quest as you for many many years. I have also asked Mike for a way to dynamically change output devices and got the same response you did. My current solution (as of the past week) is Snapcast. Snapcast is a distributed audio server which takes audio from a pipe and then sends it to any Snapcast clients that are connected to the server. It uses FLAC so there is no drop in quality from the original source. So like you I have several instances of shairport-sync running for playing to single zones but then I have another instance named [Multiroom] that pipes to Snapcast server. Then I have several instances of Snapcast client running for each zone. Then to make it easy to enable/disable multiple zones I made a Homebridge plugin that creates a bunch of dimmable lightbulbs which will show up in control center. So to play in multiple zones I simply AirPlay to [Multiroom] and then swipe open the control center and then click the Speakers I want to turn on or long press to adjust the volume of that zone.

Snapcast also has a websockets interface for changing the way zones are grouped and what their source is (because Snapserver can read multiple pipes and swap pipes dynamically). The websocket interface also fires events when things happen so you could use it to proxy volume changes over to an AVR for example. I've been fairly impressed with Snapcast so far. Snapcast can also work as a Spotify Connect device which gives a more AirPlay 2 like expreience where you run Spotify on your phone, tell it to output to Snapcast and then use my homebridge plugin to enable multiple zones. Then you can totally turn off your phone if you wanted because snapcast is the one pulling the stream from Spotify. The latest release of snapcast will build on windows too.

Here are some links: Snapcast Homebridge homebridge-snapcast

cby016 commented 4 years ago

@noelhibbard Thanks for sharing. After reading your post I started to look into Snapcast. It really simplified the multi-room audio setup I have been working on. In addition to multi-room audio I also wanted the ability to pause / mute the music and broadcast TTS and other announcements. I was trying to get something working with Shairport-Sync and MPD. I'm using Home Assistant and Node Red for the automations and broadcasting announcements. It was working ok for one zone but when I tested with multiple zones, things weren't in sync and pausing multiple airplay streams was problematic (especially for multi-room play).

Now with Snapcast things have improved drastically. On each client I only have to install snap client and bringing up another airplay stream is trivial - just add one line in the /etc/snapserver.conf file. In addition to that TTS announcements are in sync across multiple zones and multi-room play no longer requires iTunes Remote. I too created a MultiRoom Airplay stream and adding / removing clients to it can be done by toggling some input booleans in Home Assistant which then drive an automation in Node Red that interfaces with the Snapcast web socket server. So far I'm very pleased with the setup.

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.