Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chromecast / Airplay / Sonos / X support #750

Open
Ulrar opened this issue Dec 27, 2020 · 27 comments
Open

Chromecast / Airplay / Sonos / X support #750

Ulrar opened this issue Dec 27, 2020 · 27 comments

Comments

@Ulrar
Copy link

Ulrar commented Dec 27, 2020

Hi,

I've been using forked-daapd to do multi-room audio with the ability to mix and match chromecast and airplay speakers transparently, which works really well.
I do have other issues with it though, like the lack of group support, so I've been looking at snapcast.

It doesn't look like there's any real way to use already smart speakers (or cheap audiocasts, which are much cheaper to buy and run than an rpi) with snapcast.
I've seen some mentions of using pulseaudio-dlna with some extra stuff to emulate this but I can't find any docker images with the client and PA, and I suspect the delay on these would be a nightmare.

Any chance to get chromecast and airplay support either in the server or the client at some point ?
Or any other way to do this I may have missed ?

Thanks

@inickt
Copy link

inickt commented Dec 27, 2020

I have wondered about this as well. Now that snapweb can play streams in the browser I actually am wondering if it wouldn't bee too hard to make a Chromecast wrapper... I have made a couple basic Chromecast apps before so this could be something I look into eventually.

@badaix badaix changed the title Chromecast / Airplay support Chromecast / Airplay / Sonos / X support Dec 29, 2020
@badaix
Copy link
Owner

badaix commented Dec 29, 2020

@rmalchow wrote in #751

hi,

i've been watching OSS multiroom audio solutions, and it used to be quite a mess. at it has been getting into shape more and more. so recently, i have started playing with a combo of jellyfin, mopidy and snapcast - and i have to say, it looks great so far.

now - i have had some sonos speakers for a long time. and when i start doing this migration, i would really love to have some way to keep using them with snapcast. is there any way to do this? basically using them as i would use other snapcast clients?

.rm

@JKleinrath
Copy link

I have a similar setup and would love to be able to use existing (sonos) speakers as sapcast clients!

@duhow
Copy link
Contributor

duhow commented Dec 30, 2020

I'm doing some modifications to Xiaomi XiaoAI Speaker Pro LX06, and managed to install MPD, Snapcast (both client and server) and shairport-sync . With this last one you may be able to play AirPlay, and also Snapcast allows to integrate it directly, instead of having to use MPD.
Unfortunately in my case I'm having issues with forked-daapd :(

@badaix
Copy link
Owner

badaix commented Jan 2, 2021

Related to #744 and #688

@maikvitesse
Copy link

Chromecast support would be awesome!

@JamesDAdams
Copy link

Hi, News ?

Now snapcast support DLNA or AirPlay client ?

Thanks.

@Asuanin
Copy link

Asuanin commented Mar 10, 2022

Please also add Play-Fi support, thank you.

@keesfluitman
Copy link

A way to output snapcast to chromecast would be awesome. I might as well get rid of my chromecast speaker though. Im really not that happy with it.

@BTMorton
Copy link

BTMorton commented Mar 25, 2023

I did some digging into chromecast support for snapclient to see what options there are, as I'd like to integrate snapcast with some chromecast speakers and Home Assistant. After reading the chromecast docs and getting a bit lost digging into streaming protocols, I figured I'd look into some existing solutions.

I looked at DashCast to cast the web client, which didn't really work as the audio was super choppy.

I tried using chrome proper to cast the web client from the browser, which worked really well but after some more digging doesn't seem like it can be run headlessly and would require manually casting every time. Possible with a UX automation tool, maybe, but not great.

I then looked at Mkchromecast which is a python tool for casting desktop audio to a chromecast device. Instead of just running it natively, I dug into how it works and instead of casting the dektop audio hooked it up to the output of snapclient directly and it streamed great, albiet with some delay.

For an audio stream, it does the following:

  • Creates an HTTP endpoint for audio clients
  • Starts the default media player on the selected chromecast, pointing to the created HTTP endpoint
  • When the chromecast opens a connection:
    • Stats snapclient outputting to stdout
    • Pipes stdout through ffmpeg
    • Sends the ffmpeg output to through HTTP connection

The ffmpeg step in the middle is what I think is causing the delay here. It's reading the flac data out of snapclient, doing an audio conversion to flac, and then outputting the resulting flac data. Since it's flac in and flac out, it should be possible to skip the ffmpeg step entirely and just go straight from snapclient to HTTP.

What I'm thinking then as a solution here is to have a snapserver sidekick or something that offers an HTTP endpoint that can spin up snapclients when chromecast or whatever devices connect and dump the flac output directly to the audio device. Alternatively, a new HTTP output could be added to the snapclient that will just dump the flac data natively. This is still theoretical and I haven't fully tested it yet.

The downside to this approach, is that all of the timing and sync is done on the device that is running snapclient, rather than on the device that is actually playing the audio. This could potentially mean that the audio eventually drifts out of sync or even has some initial delay if the player caches some of the incoming audio data.

What I've yet to look at is setting up a proper chromecast app, because I'm stingy and don't want to pay the $5 chromecast dev fee 🤣. If the HTTP approach doesn't work out, or is unreasonably laggy or delayed, I'll actually look at native chromecast app support.

If anyone has any feedback or suggestions on the above, or any entirely different ideas on approaches for this, I'm all ears. I'll try and update if I get anywhere 👍

@Ulrar
Copy link
Author

Ulrar commented Mar 26, 2023

Nice ! One note is ffmpeg has an option for that I believe: -tune zerolatency, it's meant for radio streaming I believe but maybe it'll help with this

@kingosticks
Copy link
Contributor

kingosticks commented Mar 26, 2023

So this is:

Music source -> snapserver -> snapclient -> stdout -> httpserver -> Chromecast

There's no synchronisation from stdout onwards, right? I don't mean to be rude, but why bother with Snapcast at all here?

@BTMorton
Copy link

Yeah, it's the main downside to this approach as I said in my post, but for my use case "close enough" sync should be fine. I have a mix of hi-fi and CC speakers each in different rooms, I just want music to follow me as I move between them. Icecast had way too much delay, I didn't like the LMS spotify integration, and I can't manage chromecast multi-room groups from home assistant. Snapcast having a centralilsed music source from which I can automate dynamically adding/removing clients and have them all playing at the same point is what I need, even if it takes some custom integrations - yay open source! If the stdout -> httpserver -> Chromecast has <1s delay, I can work with that. If you have a suggestion for an alternative system that I could try, I'm open to that too 😄

It won't necessarilly be a solution for everyone, but I don't have experience building Chromecast apps and I don't know if the webkitAudioContext is available in that environment to try integrating snapweb. All of the example apps I looked at use the chromecast media element, which from reading their documentation seems to only support higher latency audio streams. I'm still just experimenting with things at the moment and if I can't get this to work nicely, I can look into a native app. Or someone else that has worked with Chromecast apps can beat me to it 😄

@BTMorton
Copy link

Turns out it didn't work anyway. From looking at it again, I think the chromecast is buffering the stream for a bit before playing anyway. When it eventually starts playing it's what was playing in snapweb when the steam request logs message prints. Interesting detour, but unfortunately not a solution :/

@v1-valux
Copy link

v1-valux commented Mar 26, 2023

Not sure if it fits the spot here, or applicable for you, but I solve the latency problem by simply playing on all speakers and only mute, or unmute where I need the "follow-me" feature..

This leads to perfect synchronous sound in all rooms, with the downside that players in abcent rooms cannot be used for other things together with the follow-me feature.

@sploders101
Copy link

sploders101 commented Oct 28, 2023

For what it's worth, I got AirPlay working using the client with pipewire-alsa and the raop-discovery module. It seems pipewire is able to successfully communicate latency information back to snapclient for synchronization. This finally makes snapcast worth it for me! I'm going to set up an Arch VM this weekend to automatically create snapcast devices for AirPlay sinks and write up a script to share.

Update:
Unfortunately, I hit some roadblocks making this available for practical use. It will end up requiring some sort of toggle outside of snapcast because pipewire doesn't disconnect/reconnect when the speaker is actually being used. However, I will be creating an orchestration tool and posting the source code on my Github. This tool will be controlled through MQTT (intended to be used by home assistant), and you can provide it with a list of AirPlay devices that will show up in snapserver when the virtual MQTT switch is turned on.

@jankaifer
Copy link

jankaifer commented Nov 7, 2023

What I've yet to look at is setting up a proper chromecast app, because I'm stingy and don't want to pay the $5 chromecast dev fee 🤣. If the HTTP approach doesn't work out, or is unreasonably laggy or delayed, I'll actually look at native chromecast app support.

@BTMorton I'll happily give you those $5, if you are still interested in digging into it.

I plan to take a look myself and I already have google dev account. After reading this thread it looks like implementing proper snapcast client for chromecast-enabled devices is the best approach. Is there anything interesting that you found that could help me doing this?

@jankaifer
Copy link

I dug into the chromecast documentation and custom apps work like this:

  • You register your app and specify the url which should be used
  • When someone tries to play stuff on chromecast using your app it just fires up browser, and runs the URL that is tied to the application

It fires the browser even on audio-only devices, that means we could just use an existing snapcast web client.

The only trouble is that Google provides official APIs for casting only for chrome, android and a ios. So there is no supported way to initiate chrome-cast from custom script.

But there are few python projects that seem to be able to trigger these chromecast apps (as some of you mentioned in this thread already):

These python apps use the generic media player, so I'll try to figure out if I can cast to my custom app from some script. If yes, then I can basically open a custom webpage on chromecast device when I want, which should be sufficient to allow us to stream there properly.

@jankaifer
Copy link

jankaifer commented Nov 8, 2023

Cool pychromecast allows you to:

  1. get all chromecasts on the network:
chromecasts, browser = pychromecast.get_chromecasts()
  1. start your custom receiver on a particular Chromecast:
chromecast.start_app(APP_ID)

I tested this with my custom app and it works well. That means that I will just need to make a small Python script that will just launch my custom receiver and send it the URL which it should load and it will load the snapcast web client in an iframe.

@BTMorton
Copy link

BTMorton commented Nov 8, 2023

IIRC, I got a custom app loading on the chromecast without issue. The problem I had was getting playback to work nicely. From reading the chromecast documentation, they want you to use their specific media player object rather than native audio/video elements. As far as I could tell, those elements don't support the same audio buffer playback that snapweb uses.

When I ran a tweaked version of snapweb pointed to my snapcast URL, it would play but was incredibly choppy. I tried tweaking the packet sizes and buffer windows on the snapcast server, but never got seamless playback. I'm not sure if it was a performance issue with decoding the audio packets, an issue with the way snapweb does audio buffering, or just being slow to receive packets over the websocket, but that was as far as I got before figuring out I can use OwnTone with AirPlay to achieve what I wanted.

@jankaifer
Copy link

jankaifer commented Nov 8, 2023

Thanks, that's helpful context. So far I was playing via <audio/> and <video/> and that worked fine. I'll see about snapcast webclient. Do you have a repo somewhere with things you tried?

Also which device have you used? I'm using Google Nest Audio which is one of the newer devices so maybe it will be able to handle it better 🤞

@jankaifer
Copy link

jankaifer commented Nov 8, 2023

It works 🚀🚀. It stops playing after a minute, but while it plays, it plays well.

What I did in my receiver was just to redirect to local snapcast webclient with autoplay and it started playing without any issues.

@literalsands
Copy link

For anyone looking to "cast" to your Snapcast setup, you can "support" Chromecast via a hardware setup. I have a Chromecast to HDMI audio splitter to ground loop noise isolator to mic-in, and I can play whatever is cast to the Chromecast via ALSA source. You can sync that Chromecast to a TV with Chromecast via "Groups" in Google Home, but YMMV. I've noticed the total latency on this system can get pretty high.

This helped me build a system the non-technical users in my life are comfortable using. It also adds support for Google Home features like announcements, doorbell notifications, reminders, etc. via meta sources and a tuned idle threshold.

@gxgani
Copy link

gxgani commented Mar 5, 2024

It works 🚀🚀. It stops playing after a minute, but while it plays, it plays well.

What I did in my receiver was just to redirect to local snapcast webclient with autoplay and it started playing without any issues.

nice work! Were you able to make any progress? IIRC this has been an issue for a long time where stream only plays for a minute and stops, the app needs to relay chromecast to keep the stream alive but correct me If I am wrong.

@jankaifer
Copy link

jankaifer commented Mar 5, 2024

I figured out that the receiver needs to periodically call some API to tell google that it's alive and working as intended (otherwise it gets killed after a minute).

My plan was to fork webclient and add this API call into the webclient source. But I haven't spent time on it yet.

Is that what you meant by relay to Chromecast?

@coxtor
Copy link

coxtor commented May 6, 2024

This thread is quite old by now. So I am wondering: is there any chance that we can stream to / control existing sonos speakers as snapclient?

@jankaifer
Copy link

Fyi I created a new issue #1234 where I will write down things only related to chromecast support so that I do not spam this general issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests