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

Problems Changing Between Streams? #569

Closed
mjvotaw opened this issue Mar 24, 2020 · 6 comments
Closed

Problems Changing Between Streams? #569

mjvotaw opened this issue Mar 24, 2020 · 6 comments
Labels
next release fixed in develop branch and will be part of the next release

Comments

@mjvotaw
Copy link

mjvotaw commented Mar 24, 2020

The short version of this issue I'm running into:

Snapcast seems to have trouble with changing the streams being sent to a client/clients. I have a slightly complicated setup, with multiple groups, one of which is meant to control all of the snapclients in my house. Changing between this group and any of the single-client groups seems particularly problematic.

The much-longer-than-I-intended version:

To start, I'll describe my snapcast setup:
I have 3 rpi's attached to speakers throughout my home, each running snapclient. One also runs the snapserver. This "main" device runs snapserver v0.18.1, and four instances of raspotify (controlled by systemd services). As you'd expect, there are four streams (and four groups) setup to read from the raspotify instances: one for each client, and a forth that's meant to be a "whole house" client.

The three single-client streams generally work fine, but I haven't been able to find a good solution to the forth. It seems that the snapserver is failing to switch the clients' streams if I change between a single-client Spotify Connect device and the "whole house" device.

My current workaround is to utilize librespot's onevent option, which fires a script that sends jsonrpc commands to explicitly re-set the associated group's clients. This is still a pretty fragile setup, though. From what I've gathered, occasionally the onevent script fails to find the expected stream. Right now my assumption is that the script is getting called while snapserver is still handling the streams changing state.

I'm pretty interested in fixing this issue, and ideally eliminating the need for the onevent script. I'm trying to familiarize myself with the snapcast codebase right now. If you have any thoughts on the matter, or suggestions of where I should focus, I would much appreciate it.

Also, I just want to say: I've been running this setup, with minor tweaks, for at least a year and a half now, and despite this issue, it's been pretty great. I really appreciate the time you've taken to put this project together.

@badaix
Copy link
Owner

badaix commented Mar 24, 2020

What does this mean?

It seems that the snapserver is failing to switch the clients' streams if I change between a single-client Spotify Connect device and the "whole house" device.

Do the clients continue playing the other stream? But the clients don't hang, as in #564? I assum that otherwise another stream reassignment with the script wouldn't help.
How do you change the streams? With Snapdroid?
Can you send server logs from this situation?
Is there a speacial reason to use Raspotify (which seems to be some dockerized package, right?) and not Librespot directly? Snapserver used to kill all running instances of Librespot, maybe this is the issue. In version 0.19 (of course I highly recommend to update), there is the "kill=false" argument for librespot streams to not kill all other instances.

@mjvotaw
Copy link
Author

mjvotaw commented Mar 25, 2020

I'm changing between different Spotify Connect devices from within the Spotify app. This changes what stream Spotify is sending audio to, but I'm not directly controlling the streams. I guess I'm trying to rely on Snapserver to detect that one stream has gone idle, and another has started playing.

I don't believe the clients are hanging, but they don't continue playing music, because Spotify is no longer sending audio to the previous stream.

Raspotify is basically just a predefined systemd service for running librespot as a daemon. I can't recall why I ended up using it over librespot directly, though it may have been to work around the issue of Snapserver killing the librespot instances.

I spent some time this morning recreating the situation with debug logging turned on. Attached is log files from Snapserver, a Snapclient instance, and three librespot instances. It also contains the config files used for each, in case that's of any help.
Around the 2020-03-24 14-49-33 is when I start playing audio and changing what stream I'm sending audio to.

Let me know if there's anything I can do to clarify this more.

snapserver_logs.zip

[edit]
I spent some time this morning trying out 0.19, and tried to replicate my setup just using librespot streams setup by Snapserver. It doesn't seem to resolve the issue (I'm actually having trouble getting the 'whole-house' group setup again).

@mjvotaw
Copy link
Author

mjvotaw commented Mar 27, 2020

For what it's worth, I think I figured out how to workaround the problem I was running into. To be totally honest, I'd had this "fixed" once before, but then my main rpi managed to corrupt its sd card, and of course, I had no backups.

I setup a small python script using python-snapcast to watch for changes to the stream status, and then send a command back to Snapserver to tell it to add the stream to the appropriate group. Snapserver then updates the associated clients' stream sessions.

import os
import asyncio
import snapcast.control
import sys
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
server = loop.run_until_complete(snapcast.control.create_server(loop, 'localhost', 1705))

def on_stream_update(group):
    if group.stream_status == 'playing':
        asyncio.run_coroutine_threadsafe(group.set_stream(group.stream), loop)

try:
    for group in server.groups:
            group.set_callback(on_stream_update)

    loop.run_forever()
except KeyboardInterrupt:
    pass
finally:
        loop.close()

@badaix
Copy link
Owner

badaix commented Mar 30, 2020

Sorry for the delay: Now I understand. This is not a Snapcast issue, the clients will continue playing the configured stream, when switching to another librespot instance, the current stream will of course stop playing. What you need is either your script or some "Meta stream", like in issue #402
Edit: but nice to see that a workaround with your script is possible

@mjvotaw
Copy link
Author

mjvotaw commented Apr 1, 2020

A meta stream is a really interesting way to look at this. I've spent a little time the last couple nights getting a handle on the Snapserver architecture, and I don't see an immediate way to implement something like that.

One thought that I had was to have StreamManager implement PcmListener and act as a middle man between the streams and the StreamServer. It could then optionally pass events and data from one stream to a meta stream. Or possibly, the StreamServer could manage the meta streams itself. But, even as I'm typing all this out, this seems like it's probably not a good way to handle it.

In my opinion, I think a less complicated route would be to have this managed at the group level--if a group could be subscribed to multiple streams, then whenever StreamServer receives an onStateChanged call, it could update the relevant groups. It could essentially do the same as making a Group.SetStream api call.

I get the sense that you're somewhat averse to making many changes to how groups are structured and function, and I understand. If you have any thoughts on the matter, let me know.

cz8s added a commit to cz8s/snapcast that referenced this issue Jun 22, 2020
@cz8s cz8s mentioned this issue Jun 22, 2020
@badaix
Copy link
Owner

badaix commented Sep 26, 2020

Meta stream will be supported in v0.22, see #666

@badaix badaix closed this as completed Sep 26, 2020
@badaix badaix reopened this Sep 26, 2020
@badaix badaix added the next release fixed in develop branch and will be part of the next release label Sep 26, 2020
@badaix badaix closed this as completed Oct 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
next release fixed in develop branch and will be part of the next release
Projects
None yet
Development

No branches or pull requests

2 participants