badaix / snapcast

Synchronous multiroom audio player
GNU General Public License v3.0
6.15k stars 457 forks source link

New input plugin: TCP stream #511

Closed badaix closed 4 years ago

badaix commented 4 years ago

I'm currently using MPD as input for snapcast (connected via pipe) and now I started playing with Mopidy, which seems to be more actively developed and more feature rich. I've observed some strange audio loops during my Mopidy tests, using this setup GStreamer setup:

[audio]
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! filesink location=/tmp/snapfifo

I was wondering if there are GStreamer sinks that are more reliable and implemented a TCP stream that can be configured to act as client or as server, allowing the following setups:

Snapcast running in TCP server mode

snapcast.conf:

[stream]
stream = tcp://127.0.0.1?name=mopidy_tcp

the general pattern is: tcp://<IP of the listen interface>:<port>?name=<name>&mode=[client|server] default for port (if omitted) is 4953, default for mode is server

mopidy.conf (running GStreamer in client mode)

[audio]
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! tcpclientsink

Snapcast running in TCP client mode

snapcast.conf:

[stream]
stream = tcp://127.0.0.1?name=mopidy_tcp&mode=client

in client mode the IP and port are the server's IP, port to connect to (default for port is again 4953)

mopidy.conf (running GStreamer in server mode)

[audio]
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! tcpserversink

If you want to give it a try: it's available in the current develop branch, any feedback is appreciated! This would also solve #486 (well, at least it would work around it)

uSpike commented 4 years ago

Awesome! I think this would be very useful for streaming pulseaudio from a different machine on the network.

slowphil commented 4 years ago

I'd love to test that on my Raspberry 4 running Raspbian Buster. I hope it could solve frequent drop-out of music when I interact with the desktop (for instance browsing internet).

Could you please update the building instructions for Raspbian? (in particular, Boost provided with Raspbian Buster seems too old...)

badaix commented 4 years ago

I will do so tonight. You will just need header only boost libs, i.e. it's enough to download and unzip the latest boost and let make/cmake point to the directory. I think you can pass the boost path to cmake like this cmake -DBOOST_ROOT=<path to your unzipped boost root> (no guarantee, I have to cross check on my dev machine tonight).

miLORD1337 commented 4 years ago

Interesting. I'm using Mopidy since I first found out about Snapcast. I did not experience audible looping issues... How are you testing for that? Our GStreamer setup is the same.

gerroon commented 4 years ago

I had terrible issues with Mopidy and Gstreamer, changing songs or radio channels meant delays, glitches, looping feedbacks etc then I moved to Mpd and it works great with SC. However I am interested in this imporvement as well.

JayGatsby7 commented 4 years ago

I'm currently using MPD as input for snapcast (connected via pipe) and now I started playing with Mopidy, which seems to be more actively developed and more feature rich. I've observed some strange audio loops during my Mopidy tests, using this setup GStreamer setup:

[audio]
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! filesink location=/tmp/snapfifo

I was wondering if there are GStreamer sinks that are more reliable and implemented a TCP stream that can be configured to act as client or as server, allowing the following setups:

Snapcast running in TCP server mode

snapcast.conf:

[stream]
stream = tcp://127.0.0.1?name=mopidy_tcp

the general pattern is: tcp://<IP of the listen interface>:<port>?name=<name>&mode=[client|server] default for port (if omitted) is 4953, default for mode is server

mopidy.conf (running GStreamer in client mode)

[audio]
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! tcpclientsink

Snapcast running in TCP client mode

snapcast.conf:

[stream]
stream = tcp://127.0.0.1?name=mopidy_tcp&mode=client

in client mode the IP and port are the server's IP, port to connect to (default for port is again 4953)

mopidy.conf (running GStreamer in server mode)

[audio]
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! tcpserversink

If you want to give it a try: it's available in the current develop branch, any feedback is appreciated! This would also solve #486 (well, at least it would work around it)

Has anyone tried this? I run several clients and a server on raspberry pi's and have some issues with mopidy that don't seem to exist when using librespot - appreciate your good work on this software.

uSpike commented 4 years ago

I'm running with the latest dev commit, and the following configs:

stream = tcp://0.0.0.0:4953?name=Spotify_1
stream = tcp://0.0.0.0:4954?name=Spotify_2
stream = tcp://0.0.0.0:4955?name=Mopidy

Librespot is running on two separate docker containers and is forwarding FIFO to network via netcat:

nc ${TARGET_HOST} ${TARGET_PORT} </tmp/snapfifo &
librespot ... --backend pipe --device /tmp/snapfifo

and mopidy:

[audio]
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! tcpclientsink host=snapcast port=4955

It seems to work well :) I'll do more stress testing this week.

fatg3erman commented 4 years ago

Ooh this looks good, just been discussing th issues Gstreamer has with fifos with the mopidy devs and one of them pointed me at this. I need to give this a try.

One thing is slightly confusing me though, is the nomenclature around client mode/server mode. I'd assume snapserver would always need to be in 'server mode' and snapclient in 'client mode' - but I'm not sure if that makes sense - and then mopidy in... what mode?

fatg3erman commented 4 years ago

OK I managed to get it to build natively on a RaspberryPi 3B+ and the good news is it's working!

For anybody interested in trying, here's what I did. I'm no expert at editing MakeFiles so I just blundered around making edits until it built, so here's the full list of what I changed.

Download the latest libboost and unzip it somewhere. This will give you a directory we'll call \<boost dir>

I only rebuilt the Snapcast server. So, in \<snapcast dir>/server:

Edit CMakeLists.txt and find the SERVER_INCLUDE section and change it to

set(SERVER_INCLUDE
    ${CMAKE_SOURCE_DIR}/server
    ${CMAKE_SOURCE_DIR}/common)

list(APPEND SERVER_INCLUDE "<boost dir>")

Then edit Makefile:

Find the long line beginning CXXFLAGS += and change it to

CXXFLAGS += $(ADD_CFLAGS) -std=c++14 -Wall -Wextra -Wpedantic -Wno-unused-function -DBOOST_ROOT=<boost dir> -DBOOST_ERROR_CODE_HEADER_ONLY -DHAS_FLAC -DHAS_OGG -DHAS_VORBIS -DHAS_VORBIS_ENC -DHAS_OPUS -DVERSION=\"$(VERSION)\" -I. -I.. -I../common  -I<boost dir> 

and change the LDFLAGS line below it to

LDFLAGS  += $(ADD_LDFLAGS) -lvorbis -lvorbisenc -logg -lFLAC -lopus -latomic

Now do

make
sudo make install

In my /etc/snapserver.conf I have

stream = tcp://127.0.0.1?name=mopidy_tcp&port=4953

And in /etc/mopidy/mopidy.conf I have

output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! tcpclientsink host=127.0.0.1 port=4953

Note that using 'localhost' in the mopidy.conf didn't work, I got errors saying GStreamer could not open the source, but using 127.0.0.1 fixed that. Wierd.

The only minor issue I now have is that the playback position reported by mopidy is about 5 seconds ahead of what's coming out of my speakers. I assume this is some buffer size thing in the tcp sink, it'd be interesting to know how to change that.

gerroon commented 4 years ago

Can Snapcast run multiple modes at the same time? I still would like to be able to use fifo together with tcp

uSpike commented 4 years ago

@gerroon you can define multiple streams that have different sources (fifo, tcp)

KraigoMpls commented 4 years ago

FWIW, the Mopidy team just dropped version 3.0.1 eleven days ago. I haven't had a chance to play with it yet. It requires Python 3.7 I've read and it uses a much more recent version of GStreamer, 1.14.0. This might be enough to resolve your issue. I'm planning on playing with it tonight. I got all of my backups in line this morning so I can step back if necessary, but I'm really excited about it.

https://mopidy.com/blog/2019/12/22/mopidy-3.0/

KO

fatg3erman commented 4 years ago

I'm already running it. It doesn't solve the issue :) The Mopidy devs say that GStreamer and FIFOs don't play well together. They did try to make a fifo output within Mopidy some time ago but again, GStreamer makes it hard. This new TCP sink is the way forward.

KraigoMpls commented 4 years ago

My biggest concern is that the configuration seems to rely on static IP addresses, which I spent a few days getting rid of in favor of DHCP when I went to OpenWRT a month or two ago . I really want to stay dynamic. My implementation of the static IP addresses was ugly and I'd really prefer to not step back to it.

fatg3erman commented 4 years ago

Well if you're using it in place of a fifo - which you can't use over a network anyway - then the only IP address you need is 127.0.0.1, which is 'local loopback' and requires no configuration.

KraigoMpls commented 4 years ago

TYVM!

uSpike commented 4 years ago

I've been testing this all night, and it's working great with a bunch of streams. I've been able to separate my services (multiple librespot instances, mopidy, etc) and the FIFO mess is gone!

I've also been able to stream the audio from my PC to snapcast from pulseaudio.

Config:

stream = tcp://0.0.0.0:4956?name=PC

On my PC I pipe pulseaudio to netcat:

$ parec --rate=48000 --format=s16le --channels=2 | nc snapserver.home 4956

Does anyone know of a better way to have pulseaudio send raw PCM over a network to a host?

uSpike commented 4 years ago

@badaix I have one suggestion... instead of tcp://...&mode=[client|server] how about tcp-server://... and tcp-client://...? I think it'd be a lot more immediately clear what's going on there.

natumbri commented 4 years ago

Another confirmed working: the develop branch builds just fine on Armbian (ubuntu bionic) after manually installing the ubuntu libboost1.71-dev package (https://launchpad.net/ubuntu/+source/boost1.71).

And the tcp stream works great with mopidy 3.0.

Thanks!

@fatg3erman very early testing suggests something seems to be up with the RompR snapcast volume control when using the TCP stream. Here's the output I get:

Screenshot_20200112-072805

RompR v1.30

Cheers Nik

eoware commented 4 years ago

If I understand this correctly, I could run a stream in server mode, and on another machine netcat a PCM stream to the IP/PORT set in the stream, is that right? This is great timing as I've been looking for a way to easily stream a PCM capture from a remote device.

uSpike commented 4 years ago

@eoware yes, correct.

JayGatsby7 commented 4 years ago

I'm running with the latest dev commit, and the following configs:

stream = tcp://0.0.0.0:4953?name=Spotify_1
stream = tcp://0.0.0.0:4954?name=Spotify_2
stream = tcp://0.0.0.0:4955?name=Mopidy

Librespot is running on two separate docker containers and is forwarding FIFO to network via netcat:

nc ${TARGET_HOST} ${TARGET_PORT} </tmp/snapfifo &
librespot ... --backend pipe --device /tmp/snapfifo

and mopidy:

[audio]
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! tcpclientsink host=snapcast port=4955

It seems to work well :) I'll do more stress testing this week.

can't seem to get this to work with librespot (raspotify) -- could be my lack of understanding about netcat . . . I'm running librespot on the same server as the snapserver.... TCP seems to work ok with mopidy.

uSpike commented 4 years ago

can't seem to get this to work with librespot (raspotify) -- could be my lack of understanding about netcat . . . I'm running librespot on the same server as the snapserver.... TCP seems to work ok with mopidy.

@JayGatsby7 can you provide more information?

JayGatsby7 commented 4 years ago

can't seem to get this to work with librespot (raspotify) -- could be my lack of understanding about netcat . . . I'm running librespot on the same server as the snapserver.... TCP seems to work ok with mopidy.

@JayGatsby7 can you provide more information?

  1. Do you have a pipe open on snapserver.conf for tmp/snapfifo? Or just the setting for TCP?

  2. Netcat configs in your example. Are you putting those parameters in the librespot / raspotify config?

I’m using mopidy with tcp for the time being but would like to get librespot working with tcp on a separate port as well.

badaix commented 4 years ago

My biggest concern is that the configuration seems to rely on static IP addresses, which I spent a few days getting rid of in favor of DHCP when I went to OpenWRT a month or two ago . I really want to stay dynamic. My implementation of the static IP addresses was ugly and I'd really prefer to not step back to it.

@KraigoMpls: I will keep this in mind for the next version. I already started to implementing host resolution, but removed it for this first version of the tcp plugin. I think for most users the audio source will run on the same host. You can open a feature request for this, so that I will not forget about it.

badaix commented 4 years ago

@badaix I have one suggestion... instead of tcp://...&mode=[client|server] how about tcp-server://... and tcp-client://...? I think it'd be a lot more immediately clear what's going on there.

@uSpike: valid suggestion, could be done together with the client host resolution feature. Can you also open a feature request for this?

languitar commented 4 years ago

I've now also tested this with mopidy and things work fine apart from one fact: If I stop music on mopidy or switch the song, this sometimes takes ~ 30 seconds to propagate to the snapclient instances. Any ideas on that? Sounds a like the buffer is too large.

badaix commented 4 years ago

@languitar GStreamer's tcpserversink has the option buffers-max, maybe this could help. What happens when you stop/start playing? Will the delay be reset? Does it grow over time? What is your gstreamer config (your [audio] output)?

Remark: that's the inherent problem with TCP: it doesn't drop. I was initially playing with the UDP client/server sinks, but had lots of dropped packets, this would require a dedicated reader thread and packet queue.

languitar commented 4 years ago

@languitar GStreamer's tcpserversink has the option buffers-max, maybe this could help.

I haven't configured anything special here so far.

What happens when you stop/start playing? Will the delay be reset? Does it grow over time?

It starts playing more or less immediately. Seems to accumulate over some time, though.

What is your gstreamer config (your [audio] output)?

The basic config that I have found in the docs / issues:

output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! tcpclientsink host=127.0.0.1 port=3333

Remark: that's the inherent problem with TCP: it doesn't drop. I was initially playing with the UDP client/server sinks, but had lots of dropped packets, this would require a dedicated reader thread and packet queue.

I don't think dropping packages here is needed as long as the buffer size is controlled somehow.

Uatschitchun commented 4 years ago

Does anyone know of a better way to have pulseaudio send raw PCM over a network to a host?

I'd be interested in this, too, as I stream from a local kodi instance (which needs pulseaudio). Or is it possible to create a tcp sink to use this new plugin?

parameter-pollution commented 4 years ago

Does anyone have problems with seeking when using tcpclientsink ?

I have mopidy 3.0.1, snapserver 0.18.1 and tried the tcpclientsink, but when I seek using any mpd/webclient the audio immediately stops, does nothing for ~1min (snapclient is not receiving any samples) and then starts playing at the seeked time.

It looks like a problem with gstreamer, but I even upgraded it to gstreamer 1.16.2 and had the same problem ( https://discourse.mopidy.com/t/seeking-takes-a-very-long-time-1min/ )

fatg3erman commented 4 years ago

Does anyone have problems with seeking when using tcpclientsink ?

I have mopidy 3.0.1, snapserver 0.18.1 and tried the tcpclientsink, but when I seek using any mpd/webclient the audio immediately stops, does nothing for ~1min (snapclient is not receiving any samples) and then starts playing at the seeked time.

It looks like a problem with gstreamer, but I even upgraded it to gstreamer 1.16.2 and had the same problem ( https://discourse.mopidy.com/t/seeking-takes-a-very-long-time-1min/ )

Yep same problem here. I was going to look into debugging on the Mopidy end when I get some time.

n0rdik commented 4 years ago

First of all, thanks!! This is the feature I was waiting for! I've found a new way to connect a remote pulseaudio client to the snapserver, just add this to your ~/.config/pulse/default.pa (or /etc/pulse/default.pa):

load-module module-simple-protocol-tcp source=0 record=true port=4953 rate=48000 channels=2 format=s16le (get source number from pactl list sources).

and then create a in the snapserver tcp stream client mode:

stream = tcp://<YOUR PULSEAUDIO REMOTE IP>?name=<YOUR STREAM NAME>&mode=client

Everything works flawlessly. I also want to set the streams:

stream = pipe:///tmp/snapfifo?name=default stream = tcp://127.0.0.1?name=mopidy_tcp

all three together, but this doesn't work. I can only set one stream at a time, when I set more than one only one of them works. What I am doing wrong? How can I set multiple streams at a time working all together?

Thanx in advance.

hawkeye217 commented 4 years ago

I've been testing this for a bit today and have run into the issue of always having the first half a second or so of the TCP stream cut off. I've tried with Mopidy 2 and Mopidy 3 (same Gstreamer backend). I've tried switching each between client and server, also without luck. I'm running Mopidy and Snapcast in separate Docker containers and have been feeding in files from Home Assistant, either dynamically generated TTS mp3s or other mp3s I have hosted locally.

I sometimes see this message in Snapcast's log:

2020-04-24 22-53-32 [Error] (AsioStream) Error reading message: End of file, length: 3528

When I switch back from Mopidy/TCP to MPD/pipe, all sounds good again and I don't lose the first part of the audio or see errors in Snapcast's log.

I suppose this issue is probably with Mopidy/Gstreamer, but I was wondering if anyone else has seen this before and if they managed to work around it.

gerroon commented 4 years ago

@hawkeye217

To be honest I think that Mopidy using Gstreamer as a backend was a bad move and I myself wasted so many hours on the same issue while trying to fix it.

hawkeye217 commented 4 years ago

To be honest I think that Mopidy using Gstreamer as a backend was a bad move and I myself wasted so many hours on the same issue while trying to fix it.

Great, glad to know it's not me. I'll stop wasting more hours then :)

Ironically I've had a little more success with Mopidy by using the alsasink output in mopidy.conf:

[audio]
output = alsasink device=snapcast_fifo

and then creating a custom entry in my /etc/asound.conf file like this:

pcm.snapcast_fifo {
    type plug
    slave {
        pcm {
            type file
            file "/tmp/snapfifo"
            slave.pcm null
            format raw
        }
        rate 48000
        format s16_le
        channels 2
    }
}

But it still is not as reliable as mpd. Off to try something else... Volumio maybe?

lealoureiro commented 4 years ago

Any ideas when this plugin might be on official release?

I'm interested because of remote parec

lealoureiro commented 4 years ago

I've been testing this all night, and it's working great with a bunch of streams. I've been able to separate my services (multiple librespot instances, mopidy, etc) and the FIFO mess is gone!

I've also been able to stream the audio from my PC to snapcast from pulseaudio.

Config:

stream = tcp://0.0.0.0:4956?name=PC

On my PC I pipe pulseaudio to netcat:

$ parec --rate=48000 --format=s16le --channels=2 | nc snapserver.home 4956

Does anyone know of a better way to have pulseaudio send raw PCM over a network to a host?

Did you tried to use --server in parec command?

According to documentation you can specify hostname.

hav0ck commented 4 years ago

Dumb question. I'm having a an issue when I have more than 1 client connected to snapcast. One client plays a digital scream for about 10 seconds and then resumes the stream, the other blanks the audio for about 10 seconds as well. I made the changes to mopidy.conf and snapcast.conf but I am getting errors like "mopidy.audio.actor: Setting GStreamer state to GST_STATE_PLAYING failed" and "mopidy.audio.gst: GStreamer error: gst-resource-error-quark: Could not open resource for reading"

I've read and re-read this issue and it looks like a plugin is needed? I'm running the latest stable which was installed with the .deb file on Ubuntu 18.04.

Thanks

fatg3erman commented 4 years ago

I’ve been running this regularly since it was first released and have at some point encountered all the problems described in the thread. I’ve done a lot of debugging and a lot of research and have come to the conclusion that, if it’s not outputting directly to audio hardware, GStreamer just isn’t very good.

To everybody having issues with mopidy my only advice is either learn to live with them or switch to MPD.

gerroon commented 4 years ago

GStreamer just isn’t very good.

This is why Mopidy is not cutting it. I exactly did what fatg3erman says, switched to MPD.

badaix commented 4 years ago

Are there other output plugins available that could me more reliable? Also one could consider writing another sink for gstreamer, maybe a real pipe sink, instead of a file sink.

hav0ck commented 4 years ago

I did get the TCP stream working after upgrading to Mopidy 3. I need to do more testing but lastnight there were frequent short audio drops and no audio at all for extended periods of time. Last night may have been wi-fi congestion...

william-bohannan commented 4 years ago

Have the following working with TCP between Mopidy and Snapcast, works much better than FIFO:

  1. Mopidy Mobile (Android): select music.local and play song. Plays on both remotes (music-1.local and music-2.local).
  2. Mopidy Mobile (Android): select music-1.local and play song. Plays on music-1.local.

The issue is if i do 1. and 2. at the same time then both songs come out of music-1.local speakers at the the same time. It there a way to have it so the latest action cancels the previous action? Below are the configurations:

Server (Unraid VM/Ubuntu 20.04): music.local

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

/etc/mopidy/mopidy.conf

[file]
media_dirs = /mnt/user/tunes

[http]
hostname = 0.0.0.0
zeroconf = Tunes on $hostname

[mpd]
hostname = 0.0.0.0
zeroconf = Tunes on $hostname

[audio]
output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! tcpclientsink hotost=127.0.0.1 port=3333

Remote/s (RPI/Ubuntu 20.04): music-1.local, music-2.local

/etc/defaults/snapclient SNAPCLIENT_OPTS="--host 192.168.2.5"

/etc/mopidy/mopidy.conf

[file]
media_dirs = /mnt/user/tunes

[http]
hostname = 0.0.0.0
zeroconf = Tunes on $hostname

[mpd]
hostname = 0.0.0.0
zeroconf = Tunes on $hostname

[audio]
output = alsasink
kingosticks commented 4 years ago

Does anyone have problems with seeking when using tcpclientsink ?

Yes, if used with wavenc. But we don't need wavenc since snapcast wants S16LE PCM @ 48K (or whatever you have configured) and that's what audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE provides us with. I've had no seeking problems (so far) using:

output = audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! tcpclientsink host=127.0.0.1

I've tested with GStreamer 1.16.2.0 on Ubuntu 20.04 and GStreamer 1.14.4.0 on Raspbian Buster.

However, I do see the issue with the playback position within Mopidy not corresponding to what snapcast is playing. Mopidy's position is delayed. Need to spend more time looking at that. I also hear a little stutter when playing starts or seeks but I'm not convinced that's a Mopidy/GStreamer issue.

It's maybe worth also mentioning that seeking actually works OK if you substitute wavenc for a different encoder e.g. opusenc. Obviously snapcast can't decode opus (although it does try and it doesn't sound great!) but the seek does actually work and there's no GStreamer error as with wavenc. I don't know what's specifically wrong with wavenc or if it's a combination of it's problem along with the tcp*sinks themselves. Those sinks don't see much usage / love, I'm not sure how great they are (but I do like that they let you run Mopidy and Snapcast on different systems and they would also work for Mopidy on Windows).

I gave this all a try after also trying filesink. I didn't actually hit any problems using filesink myself - gapless worked, seeking worked, the playback position remained accurate. But it's a complicated beast and it's really not designed with FIFOs in mind, it just happens to work with them ...some of the time. There's a stark difference when comparing GStreamer's jack-of-all-trades filesink implementation to MPD's super simple FIFO output. FIFO-specific things like creating the FIFO (and then removing it after) and sensibly handling the full condition are handled by MPD but not by filesink. I'm a little tempted to have another look at a dedicated GStreamer fifosink... Although I'd want to understand better and reproduce what's currently wrong with filesink.

fatg3erman commented 4 years ago

Latest snapcast has an ALSA loopback sink which is working much better than either fifo or tcp for me with mopidy. Still has the playback position being off, but surely that's just buffering in snapserver?

kingosticks commented 4 years ago

but surely that's just buffering in snapserver?

Unsure. Bizarrely the playback position offset seems to be noticeably better (less) when Mopidy is running on a different machine to snapserver. Not sure I expected that.

EDIT: Oh wait. I wasn't thinking, it makes sense. It would take longer for the audio data to travel over the network from the Mopidy machine to the snapserver machine, would arrive at snapserver later, and so would be played later. If there was enough delay then playback would appear more synchronised w.r.t Mopidy's delayed current position (but it's just dumb luck).

But for Mopidy's position to be behind, I think that must be a problem within Mopidy. Maybe tcpclientsink is reporting a much larger latency than it's actually seeing.

christf commented 3 years ago

It's maybe worth also mentioning that seeking actually works OK if you substitute wavenc for a different encoder e.g. opusenc. Obviously snapcast can't decode opus (although it does try and it doesn't sound great!) but the seek does actually work and there's no GStreamer error as with wavenc. I don't know what's specifically wrong with wavenc or if it's a combination of it's problem along with the tcp*sinks themselves. Those sinks don't see much usage / love, I'm not sure how great they are (but I do like that they let you run Mopidy and Snapcast on different systems and they would also work for Mopidy on Windows).

I gave this all a try after also trying filesink. I didn't actually hit any problems using filesink myself - gapless worked, seeking worked, the playback position remained accurate. But it's a complicated beast and it's really not designed with FIFOs in mind, it just happens to work with them ...some of the time. There's a stark difference when comparing GStreamer's jack-of-all-trades filesink implementation to MPD's super simple FIFO output. FIFO-specific things like creating the FIFO (and then removing it after) and sensibly handling the full condition are handled by MPD but not by filesink. I'm a little tempted to have another look at a dedicated GStreamer fifosink... Although I'd want to understand better and reproduce what's currently wrong with filesink.

That would be interesting. I am using filesink as well and I am seeing playback stop in a playlist after every track. I am not using waveenc as that would mess up the data by including wav headers. As you write, PCM should be just fine. I have seen an end of stream but cannot figure out why playback stops.

pcwii commented 3 years ago

I've now also tested this with mopidy and things work fine apart from one fact: If I stop music on mopidy or switch the song, this sometimes takes ~ 30 seconds to propagate to the snapclient instances. Any ideas on that? Sounds a like the buffer is too large.

@languitar I realize this was over a year ago now but did you ever solve this problem? I am not using mopidy but have the same results with the android client.

christf commented 3 years ago

On Wed, May 19, 2021 at 12:34:33PM -0700, pcwii wrote:

I've now also tested this with mopidy and things work fine apart from one fact: If I stop music on mopidy or switch the song, this sometimes takes ~ 30 seconds to propagate to the snapclient instances. Any ideas on that? Sounds a like the buffer is too large.

@.*** I realize this was over a year ago now but did you ever solve this problem? I am not using mopidy but have the same results with the android client.

This is the logic being implemented in snapcast.

In snapcastc (an own rewrite that was created at a time when badaix was busy and I wanted things changed) I did experiment with other mechanics for start/stop and pausing. The program follows the same principle as snapcast but has different behavior in those two aspects:

There might be other things that could be tried. In essence snapcast(c) must be told the users intent. So a side channel is needed besides the audio stream. If mopidy supports calling hooks this could be realized with extending the API of either tool.

-- () ascii ribbon campaign - against html e-mail /\ www.asciiribbon.org - against proprietary attachments