librespot-org / librespot

Open Source Spotify client library
MIT License
4.86k stars 616 forks source link

Spotify does not detect Librespot as a device #876

Closed itwasonlyabug closed 2 years ago

itwasonlyabug commented 3 years ago

Hi, I have been using Librespot for a few months now without any issues. Starting this month (October) though, none of my Librespot instances show up in Spotify.

I am running Librespot in Docker containers on a Raspberry Pi 4, but I also tried a direct cargo install librespot on my laptop with no success.

I have made no changes to my home network and I have tried with various combinations of Wi-Fi 2,ghz, Wi-Fi 5ghz and just everything wired together via Ethernet cable. I see no errors in Librespot's logs (besides ones about the Avahi demon when running inside a container).

Versions tried: 0.1.6 (this one was previously working) 0.2.0 (ditto) 0.3.1

Any tips on how to debug this?

JasonLG1979 commented 3 years ago

I have basically zero experience with containers. Strange that it worked for months and now it stopped? Nothing else in your system has changed has it?

I would start by disabling avahi-daemon if you're not using it for anything else. Librespot doesn't need avahi-daemon unless you compile it with with-dns-sd. And in fact they may interfere with each other.

If that doesn't work you can try disabling discovery with --disable-discovery and providing a --username and --password to see if it's even a mDNS problem.

I would also run with the --verbose flag to see if anything shows up in the logs.

roderickvd commented 3 years ago

Additionally:

I know you said you made no changes to your network, but please double-check multicast is working OK and not firewall in any way. Do other services like shairplay-sync (AirPlay) show up?

itwasonlyabug commented 3 years ago

Thanks for the swift responses.

@JasonLG1979

Container-wise it's effectively running in Ubuntu 20.04 (focal) while the network is directly connected so no extra NAT or other networking hoops.

As I was unsure if this could be some random Docker / Container / RPI issue, I tried installing librespot directly on my laptop (Linux / Manjaro running 5.10 kernel).

In both cases, I'm installing Librespot through cargo and not compilling / building it myself. It's running in verbose mode on both places and I see nothing wrong:

from my laptop: librespot -n "HelloWorld" -b 160 -v [2021-11-01T08:16:02Z INFO librespot] librespot 0.3.1 5049cd7 (Built on 2021-10-29, Build ID: vqN3o9BV, Profile: release) [2021-11-01T08:16:02Z DEBUG librespot_playback::mixer::mappings] Volume control is now Log(60.0) [2021-11-01T08:16:02Z DEBUG librespot_discovery::server] Zeroconf server listening on 0.0.0.0:40631

from the container: librespot -n "HELLO" -b 160 -v [2021-11-01T08:27:04Z INFO librespot] librespot 0.2.0 UNKNOWN (Built on 2021-09-20, Build ID: JrtOukg9) [2021-11-01T08:27:04Z DEBUG librespot_connect::discovery] Zeroconf server listening on 0.0.0.0:35093

I'll try disabling avahi and username + pass + no-discovery.

@roderickvd I said it as in "I didn't explicitly make changes" but as we know - computers are magic :) I will check multicast operation. I have removed all firewalls on the RPI. I have not tried shairplay-sync. Do you mean shairport-sync? I can try that one too.

roderickvd commented 3 years ago

Yes that's what I meant. Or any other zeroconf service.

itwasonlyabug commented 3 years ago

I just tired shairport-sync running in a docker container (https://hub.docker.com/r/mikebrady/shairport-sync) on the same RPI4 and I can see it in Spotify via AirPlay.

roderickvd commented 3 years ago

That puzzles me. I have no idea why one Zeroconf service is discoverable, and the other isn't. Not sure if you've now also tried manually specifying a username and password, and disabling discovery?

kingosticks commented 3 years ago

Maybe you guys already know this but that shairport-sync container also runs avahi. Maybe that's a piece of this puzzle. It's not clear to me which mDNS lib is used by the librespot binary from Cargo. Presumably it is using libmdns ? Did you disable avahi on the host?

itwasonlyabug commented 3 years ago

I ran some tests on the laptop and here's the results:

  1. Just running librespot with verbose and a name does not show up in spotify.
  2. Running the same as above but with added --disable-discovery does not show up in spotify.
  3. Running with --username, --password and --disable-discovery works and is visible in spotify!
  4. Running inside the container with username + pass + disable-discovery works and is visible in spotify!

Here's some logs from the success (non-container):

librespot -n "HelloWorld" -b 160 -v --disable-discovery --username OMITTED --password OMITTED [2021-11-02T09:08:29Z INFO librespot] librespot 0.3.1 5049cd7 (Built on 2021-10-29, Build ID: vqN3o9BV, Profile: release) [2021-11-02T09:08:29Z DEBUG librespot_playback::mixer::mappings] Volume control is now Log(60.0) [2021-11-02T09:08:29Z INFO librespot_core::session] Connecting to AP "gew1-accesspoint-a-7qw9.ap.spotify.com:4070" [2021-11-02T09:08:29Z INFO librespot_core::session] Authenticated as OMITTED ! [2021-11-02T09:08:29Z DEBUG librespot_core::session] new Session[0] [2021-11-02T09:08:29Z INFO librespot_playback::mixer::softmixer] Mixing with softvol and volume control: Log(60.0) [2021-11-02T09:08:29Z DEBUG librespot_connect::spirc] new Spirc[0] [2021-11-02T09:08:29Z DEBUG librespot_connect::spirc] canonical_username: OMITTED [2021-11-02T09:08:29Z DEBUG librespot_core::mercury] new MercuryManager [2021-11-02T09:08:29Z DEBUG librespot_playback::player] new Player[0] [2021-11-02T09:08:29Z INFO librespot_playback::convert] Converting with ditherer: tpdf [2021-11-02T09:08:29Z INFO librespot_playback::audio_backend::rodio] Using Rodio sink with format S16 and cpal host: ALSA [2021-11-02T09:08:29Z INFO librespot_playback::audio_backend::rodio] Using audio device: default [2021-11-02T09:08:29Z DEBUG librespot_playback::mixer::mappings] Input volume 58958 mapped to: 49.99% [2021-11-02T09:08:29Z DEBUG librespot_core::session] Session[0] strong=3 weak=2 [2021-11-02T09:08:29Z INFO librespot_core::session] Country: "OMITTED" [2021-11-02T09:08:29Z DEBUG librespot_core::mercury] subscribed uri=hm://remote/user/OMITTED/ count=0 [2021-11-02T09:08:29Z DEBUG librespot_playback::audio_backend::rodio] Rodio sink was created [2021-11-02T09:08:29Z DEBUG librespot_playback::player] command=AddEventSender [2021-11-02T09:08:29Z DEBUG librespot_playback::player] command=VolumeSet(58958) [2021-11-02T09:08:29Z DEBUG librespot_connect::spirc] kMessageTypeNotify "manjaro" and etc...

@kingosticks AVAHI has always failed for me but this didn't affect anything so far.

roderickvd commented 2 years ago

Well, it must be something with Avahi or otherwise. Have you also tried compiling with --features with-dns-sd?

itwasonlyabug commented 2 years ago

@roderickvd I tried installing with --features-with-dns-sd and got multiple issues while installing / starting. See below:

[2021-11-10T21:19:27Z INFO  librespot] librespot 0.3.1 UNKNOWN (Built on 2021-11-05, Build ID: IUYq1NPe, Profile: release)
[2021-11-10T21:19:27Z DEBUG librespot_playback::mixer::mappings] Volume control is now Log(60.0)
[2021-11-10T21:19:27Z DEBUG librespot_discovery::server] Zeroconf server listening on 0.0.0.0:42661
*** WARNING *** The program 'librespot' uses the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/blog/projects/avahi-compat.html>
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: DNSError(Unknown)', /usr/local/cargo/registry/src/github.com-1285ae84e5963aae/librespot-discovery-0.3.1/src/lib.rs:115:18
stack backtrace:

I heavily modified my Dockerfile to successfully install avahi and I can start it but this does not resolve the issue that LibreSpot is not visible in Spotify. Also, please keep in mind that I have been using the unmodified version for months with no issues.

I also reverted a backup of my router settings to verify there have been no changes and ran some zeroconf tests (avahi-daemon) but saw no issues.

For anyone interested, here's my old and used for a long time Dockerfile:

I want to stress that I have tried just running JUST librespot inside the container, totally separate from Snapserver so consider my testing done with purely Librespot. So this is not a Snapserver issue!

FROM rust:1.45 AS librespot-make

ARG LIBRESPOT_VERSION="0.1.6"
ARG ARCH="armhf"

RUN apt update \
 && apt -y install build-essential libasound2-dev curl unzip \
 && apt clean && rm -fR /var/lib/apt/lists

RUN cargo install librespot --version "${LIBRESPOT_VERSION}"

FROM ubuntu:20.04

ARG SNAPCAST_VERSION="0.24.0"

ARG ARCH="armhf"

RUN apt update -y && apt install curl ca-certificates libasound2 -y && apt install -y -f
RUN curl -L -o /tmp/snapserver.deb "https://github.com/badaix/snapcast/releases/download/v${SNAPCAST_VERSION}/snapserver_${SNAPCAST_VERSION}-1_${ARCH}.deb" \
     && dpkg -i /tmp/snapserver.deb || apt install -f -y --no-install-recommends \
     && apt clean && rm -fR /var/lib/apt/lists

COPY snapserver.conf /etc/snapserver.conf
COPY --from=librespot-make /usr/local/cargo/bin/librespot /usr/local/bin/

CMD ["snapserver"]
EXPOSE 1704/tcp 1705/tcp

The relevant line in Snapserver conf - source = spotify://librespot?name=Spotify&devicename=dockerize&volume=20&normalize=true

And here is my latest & greatest version, with Avahi working:

FROM rust:1.50 AS librespot-make

ARG LIBRESPOT_VERSION="0.3.1"
ARG ARCH="armhf"
ENV DEBIAN_FRONTEND=noninteractive

RUN apt update \
 && apt -y install build-essential libasound2-dev avahi-daemon libavahi-compat-libdnssd-dev curl unzip \
 && apt clean && rm -fR /var/lib/apt/lists

RUN cargo install librespot --version "${LIBRESPOT_VERSION}" --features with-dns-sd

FROM ubuntu:20.04

ARG SNAPCAST_VERSION="0.25.0"
ARG ARCH="armhf"
ENV DEBIAN_FRONTEND=noninteractive

RUN apt update -y && apt install curl ca-certificates libasound2 avahi-daemon libavahi-compat-libdnssd-dev avahi-utils libflac8 libogg0 libopus0 libsoxr0 libvorbis0a libvorbisenc2 -y

RUN curl -L -o /tmp/snapserver.deb "https://github.com/badaix/snapcast/releases/download/v${SNAPCAST_VERSION}/snapserver_${SNAPCAST_VERSION}-1_${ARCH}.deb" \
     && dpkg -i /tmp/snapserver.deb || apt install -f -y --no-install-recommends \
     && apt clean && rm -fR /var/lib/apt/lists

RUN printf "[server]\nenable-dbus=no\n" >> /etc/avahi/avahi-daemon.conf \
    && chmod 777 /etc/avahi/avahi-daemon.conf \
    && mkdir -p /var/run/avahi-daemon \
    && chown avahi:avahi /var/run/avahi-daemon \
    && chmod 777 /var/run/avahi-daemon

COPY snapserver.conf /etc/snapserver.conf
COPY --from=librespot-make /usr/local/cargo/bin/librespot /usr/local/bin/

CMD avahi-daemon --daemonize --no-drop-root; snapserver
EXPOSE 1704/tcp 1705/tcp 1780

EDIT: Installing with --features with-dns-sd works on my laptop (manjaro) but there are no errors in the log and no devices shown in Spotify.

JasonLG1979 commented 2 years ago

Nothing in librespot has changed as far as discovery in a very long time, 6 months or so from the looks of things. (https://github.com/librespot-org/librespot/tree/dev/discovery)

If it worked forever but than stopped working clearly something has changed on your side that you have not found yet. Other devices can interfere with mdns. What new devices have you added to your network?

itwasonlyabug commented 2 years ago

Can you give me some idea how to get some more logs out of Librespot or some breadcrumbs what the path fro Device A to Device B is so I can try to unwrap this?

All I can see is librespot starting and Zeroconf listening but no idea where the connection breaks. I can hit Zeroconf/Librespot on the port it picks, but this isn't logged in Librespot.

I am aware that this is almost entirely an issue with my setup, I just need some help with how to debug it :)

JasonLG1979 commented 2 years ago

Can you give me some idea how to get some more logs out of Librespot ... All I can see is librespot starting and Zeroconf listening but no idea where the connection breaks. I can hit Zeroconf/Librespot on the port it picks, but this isn't logged in Librespot.

There would be no logs from librespot as far as it's concerned it's advertised itself as a service. If there are no logs than no connection is being made.

breadcrumbs what the path fro Device A to Device B is so I can try to unwrap this?

I believe that avahi has a GUI app. I have never used it but maybe that will help.

JasonLG1979 commented 2 years ago

Eventually it would be nice to be able to use avahi's DBus interface for zeroconf on Linux.

itwasonlyabug commented 2 years ago

Eventually it would be nice to be able to use avahi's DBus interface for zeroconf on Linux.

This got me thinking - In all scenarios I have either A) No avahi working or B) Avahi working without DBus. Is DBus 100% required or is dbuss-less avahi fine?

JasonLG1979 commented 2 years ago

I'm not sure? DBus is pretty much a requirement for a modern Linux system as just about everything uses it. I didn't even think you could run a DBus-less system? I've never thought about it or tried?

dubo-dubon-duponey commented 2 years ago

@itwasonlyabug

I've been (and still am) running librespot in containers successfully (currently running 0.3.1).

  1. can you copy the exact command you use to start your container? specifically, what networking mode you are using

  2. also, personal opinion: just avoid avahi - it's messy in containers and definitely a source of issues when multiple instances share the same ip - you do not need avahi to use librespot

itwasonlyabug commented 2 years ago

@dubo-dubon-duponey

  1. /usr/bin/docker run --rm --name snapserver --network host snapserver:0.24. The host is a Raspberry Pi4 and has no firewall, no IPTABLES rules and can be reached freely from the network. It is also directly connected to the same WiFi as the devices running spotify (so no NAT trickery there).

0.24 is the "unmodified" dockerfile I sent in the coment above and 0.25.1 is the modified (with avahi) that I shared above.

  1. I also had the same idea as initially I didn't even install avahi, but after the discussion here decided to try it. It didn't make a difference so I prefer not having it.
dubo-dubon-duponey commented 2 years ago

@itwasonlyabug network host is likely problematic if your host also has avahi installed. Multiple mDNS stacks on the same ip will compete / not play well with each other.

Can you try to use macvlan instead of host? (or make sure your host does not have any mDNS stack running - eg: avahi)

And also make sure you use your version of librespot that does not use avahi (simplifies your problem).

For macvlan, if you are not familiar, see https://docs.docker.com/network/macvlan/ - something in the line of:

docker network create -d macvlan \
  --subnet=192.168.0.0/24 \
  --ip-range=192.168.0.128/25 \
  --gateway=192.168.0.1 \
  -o parent=eth0 my-macvlan
dubo-dubon-duponey commented 2 years ago

Also, you may want to remove snap from the equation and start just librespot (for now).

dubo-dubon-duponey commented 2 years ago

@dubo-dubon-duponey

0.24 is the "unmodified" dockerfile I sent in the coment above

So, 0.24 appears to use librespot 0.1.6 which is quite old. I would just try with 0.3.1.

and 0.25.1 is the modified (with avahi) that I shared above.

This one forces librespot to use avahi, which IIRC does require dbus (which you disabled).

Avahi works fine withOUT dbus if you are interested in resolution only - but (again IIRC) publishing with dnssd-dev does require dbus.

This is one of the reason avahi (in a container) is usually a bad idea. Just to annonce a single service, you have to spin up two different daemons (and the dbus one requires root IIRC).

Summarizing:

Let me know if it still does not work, there are more things we can try.

dubo-dubon-duponey commented 2 years ago

@roderickvd I shared notes / experiences about these topics ^ on the wiki: https://github.com/librespot-org/librespot/wiki/librespot,-mDNS,-networking-and-containers in the hope that could help people who have issues related to containers / mDNS.

I hope this was the appropriate thing to do, but evidently feel free to do whatever you need with that page.

@itwasonlyabug ^

itwasonlyabug commented 2 years ago

Thanks you very much @dubo-dubon-duponey for the support!

Here's my latest attempt:

FROM rust:1.50 AS librespot-make

ARG LIBRESPOT_VERSION="0.3.1"
ARG ARCH="armhf"
ENV DEBIAN_FRONTEND=noninteractive

RUN apt update \
 && apt -y install build-essential libasound2-dev curl unzip \
 && apt clean && rm -fR /var/lib/apt/lists
RUN cargo install librespot --version "${LIBRESPOT_VERSION}"

FROM ubuntu:20.04

ARG SNAPCAST_VERSION="0.25.0"
ARG ARCH="armhf"
ENV DEBIAN_FRONTEND=noninteractive

RUN apt update -y && apt install curl ca-certificates libasound2 libflac8 libogg0 libopus0 libsoxr0 libvorbis0a libvorbisenc2 -y
COPY --from=librespot-make /usr/local/cargo/bin/librespot /usr/local/bin/
CMD librespot -n "HELLO" -b 160 -v
EXPOSE 1704/tcp 1705/tcp 1780

I tried with:

During all of these tests I tried using avahi-browse and avahi-discover but I did not see a single device / entry.

I want to say that it's something on my side that's messing with the network, but I don't understand how Shairport works every time I try it if that is indeed the case.

@roderickvd If you prefer I can close the issue and re-open / open a new one if I manage to track this down, so I don't create noise. For the time being I can't say that it's a librespot issue.

dubo-dubon-duponey commented 2 years ago

@itwasonlyabug

I'm lurking on gitter. Feel free to send me a PM over there if you want to continue this conversation out of band.

Nevertheless, the following should help figuring out what's wrong.

Can you follow these steps below exactly as written?

# ---------------------------------------------------------
# STEP 0
# ---------------------------------------------------------
# ON YOUR RPI
# a. wire up ethernet
# b. shutdown wifi
# c. remove all your test containers, and your existing macvlan network
# d. create your macvlan network (name it `my-macvlan`), attached to the parent *ethernet* interface (eth0 or whatever it's named for you), with the appropriate subnet & gateway config
# e. apt-get install jq

# ON YOUR OTHER LINUX MACHINE (desktop)
# f. apt-get install avahi-utils
# g. Verify avahi-browse works by running:

avahi-browse _workstation._tcp -t

# Confirm *a-g* ^.

# ---------------------------------------------------------
# STEP 1
# ---------------------------------------------------------
# Now:
# On your RPI
docker run -ti --rm --name mypy --net my-macvlan --entrypoint python3 python -m http.server

# In a separate shell, on your RPI:
docker inspect mypy | jq -rc '.[0].NetworkSettings.Networks["dubo-macvlan"].IPAddress'

# On a *different* machine on your network (replace XXXXXXX with the result from that last command above ^)
curl -o /dev/null XXXXXXX:8000 && echo success || echo failure

---------------------------------------------------------
# [1.] If the above ^ does NOT output "success", stop right now, as your macvlan network is not configured correctly.
# If you got "success", continue below:
---------------------------------------------------------

# ---------------------------------------------------------
# STEP 2
# ---------------------------------------------------------
# On your RPI, run
docker run -ti --rm --net my-macvlan --entrypoint shairport-sync dubodubonduponey/airplay --name TEST_shairport

# On a *different* linux machine (your desktop, or any other machine but the one)
avahi-browse _raop._tcp -t | grep TEST_shairport && echo "Success" || echo "Failure"

---------------------------------------------------------
# [2.] If the above ^ does NOT output "success", stop now, as there is something in your LAN that impairs mDNS.
# If you got "success", continue below:
---------------------------------------------------------

# ---------------------------------------------------------
# STEP 3
# ---------------------------------------------------------
# Now, on your RPI
docker run -ti --rm --net my-macvlan --entrypoint goello-server-ng dubodubonduponey/spotify -json '[{"Type": "_spotify-connect._tcp", "Name": "TEST_goello", "Host": "goello", "Port": 10042, "Text": ["VERSION=1.0", "CPath=/"]}]'

# On a different machine:
avahi-browse _spotify-connect._tcp -t | grep TEST_goello && echo "Success" || echo "Failure"

---------------------------------------------------------
# [3.] Confirm the output is "success"
---------------------------------------------------------

# ---------------------------------------------------------
# STEP 4
# ---------------------------------------------------------
# On your RPI

docker run -ti --rm --net my-macvlan --entrypoint librespot dubodubonduponey/spotify --name TEST_librespot -v

# On a different machine
avahi-browse _spotify-connect._tcp -t | grep TEST_librespot && echo "Success" || echo "Failure"

---------------------------------------------------------
# [4.] Confirm the output is "success"
---------------------------------------------------------

If you get a failure at step 1., you messed-up something with your macvlan config, so, try again until you get it right.


If step 1 is a success, but steps 2-4 fail, you have a network configuration issue. To further diagnose it, you can try to first confirm that your RPI sees its own mDNS traffic.

On the RPI, with all the test containers from above still running:

docker run --rm -ti --net my-macvlan debian bash

# Then, inside the container

mkdir /run/dbus
apt-get update -qq
apt-get install avahi-utils -qq
dbus-daemon --system
avahi-daemon -D

# Now test any / one the browse tests from above:
avahi-browse _spotify-connect._tcp -t | grep TEST_librespot && echo "Success" || echo "Failure"

If you get a success in that case while you get failures from a remote host, your network configuration / equipment is definitely the problem.

If you still get a failure in that case, then something is wrong with your RPI itself.


If step 1 is a success, and steps 2-4 are a mix of success & failures, then it's probably still a problem with your network configuration (though it hinders only certain mDNS implementations) <- I want to hear about it if that's the case.

Hope that helps...

roderickvd commented 2 years ago

Great stuff @dubo-dubon-duponey, your input and documentation is highly appreciated.

@itwasonlyabug I'm fine with keeping this issue open. Although I have no idea what's going on, I do find it interesting that shairplay works and librespot doesn't. So if there's a chance that librespot can be improved in this regard, then that's worth pursuing.

dubo-dubon-duponey commented 2 years ago

@roderickvd

From a cursory look & quick traffic sniffing, it seems to me that librespot uses aggressively short TTL (60 sec), and also does not appropriately set the cache flush bits on records.

For comparison, shairport sync uses a 75 minutes TTL, and does set the cache flush bit on all records but PTR. So does Sonos (and also macOS).

Please take what I say with a grain of salt, as I'm not that familiar with the spec, but to me, very short TTLs like that are much more likely to trip multicast storm control with some gear, and lack of cache flush bit will very likely append multiple conflicting IN records for eg on restart (albeit given the short TTLs...).

I do not know if @itwasonlyabug problem is related to that ^ (we may get an answer when they will have run through my tests above ^, or if they can tcpdump), and again I'm not 100% comfortable with these topics, but I thought I would still point these two facts out.

JasonLG1979 commented 2 years ago

it seems to me that librespot uses aggressively short TTL (60 sec)

I traced that back to our implementation:

https://github.com/librespot-org/libmdns/search?q=DEFAULT_TTL

And walked back though the git blames and it's been 60 since the initial commit with no explanation why?

@dubo-dubon-duponey zeroconf/mDNS is black magic voodoo to me. Apple is the king of zeroconf. I'm pretty sure they literally wrote the book. There are certainly worse things we could do than copy their implementation.

I'm sure PR's are welcome.

dubo-dubon-duponey commented 2 years ago

@JasonLG1979 I usually sacrifice a chicken before touching mDNS...

Just fixing the ttl without also fixing the cache flush will likely cause more issues I think (right now the short TTL make it so these issues are at most taking 60 seconds to resolve AFAIK).

I'll look around into the codebase and issues (on the mdns lib) though I do not know rust, so... 🤪

kingosticks commented 2 years ago

Is this not a problem with advertising on the wrong interface, because the default interface (which is used) is probably something weird in a container?

dubo-dubon-duponey commented 2 years ago

Is this not a problem with advertising on the wrong interface, because the default interface (which is used) is probably something weird in a container?

My guess is "no" (at least in the exact set of examples I gave above (using macvlan) - iface is eth0@if2, which works just fine with librespot for me - I've been using this with many different docker versions).

From a cursory look, it looks like: https://github.com/librespot-org/libmdns/blob/acd405604d2fb589e9848d1292ce9404bd206d91/src/fsm.rs#L187 - this simply enumerates all interfaces without trying anything "smart".

Still an interesting point though. Could check with OP if the tests above still fail for them.

JasonLG1979 commented 2 years ago

@dubo-dubon-duponey I'm fairly new to rust but I enjoy a challenge I'd be willing to give it a shot if you want to help me out?

dubo-dubon-duponey commented 2 years ago

@JasonLG1979 switching conversation to gitter if you want, so we can keep this issue centered on @itwasonlyabug problem.

JasonLG1979 commented 2 years ago

Sure.

itwasonlyabug commented 2 years ago

Just wanted to say I'm not dead - having some difficulties with the cabling, but will be able to test this in the next couple of days.

roderickvd commented 2 years ago

Just wanted to say I'm not dead

Well that's always good to hear 😆 Thanks for the update.

sdetweil commented 2 years ago

I have suddenly had to add user/pw info to my librespot instance to get it recognized as a valid receiver in my smart-mirror app

but I don't understand these words as it affects my app

Rather than relying on the user entering a username and password, devices can use zeroconf based authentication. This is especially useful for headless Spotify Connect devices.

In this case, an already authenticated device, a phone or computer for example, 

discovers Spotify Connect receivers on the local network using Zeroconf. 

>>>> The receiver exposes an HTTP server with service type _spotify-connect._tcp,

I am using the node spotify -web-api library . it calls and gets registered receivers.. https://github.com/thelinmichael/spotify-web-api-node

until the librespot instance gets authenticated, the device it represents is not found.

my app doesn't know anything about what the receiver is and how it works internally.

so , all I have is username/pw, which shows on the commandline (ps -ef too) from starting librespot which is a terrible security exposure. I don't have any 'apps' that use zeroconf to discover anything.

JasonLG1979 commented 2 years ago

I have suddenly had to add user/pw info to my librespot instance to get it recognized as a valid receiver in my smart-mirror app

Something has changed on your side networking wise then. The mDNS code in librespot has not changed in a long time.

so , all I have is username/pw, which shows on the commandline (ps -ef too) from starting librespot which is a terrible security exposure. I don't have any 'apps' that use zeroconf to discover anything.

At least that part could be solved with: https://github.com/librespot-org/librespot/pull/886

It's ready and just waiting to be merged.

I don't have any 'apps' that use zeroconf to discover anything

librespot uses zeroconf by default so do the official Spotify apps and a whole lot of other apps and services. You'd be surprised. It's very widely used. If anything to do with your smart mirror depends on avahi-daemon it's using zeroconf.

itwasonlyabug commented 2 years ago

Alright, so I did some testing and I got it working! This is my Dockerfile that works:

FROM rust:1.50 AS librespot-make

ARG LIBRESPOT_VERSION="0.3.1"
ARG ARCH="armhf"
ENV DEBIAN_FRONTEND=noninteractive

RUN apt update \
 && apt -y install build-essential libasound2-dev \
 && apt clean && rm -fR /var/lib/apt/lists

RUN cargo install librespot --version "${LIBRESPOT_VERSION}"

FROM ubuntu:20.04

ARG SNAPCAST_VERSION="0.25.0"
ARG ARCH="armhf"
ENV DEBIAN_FRONTEND=noninteractive

RUN apt update -y && apt install curl ca-certificates libasound2 libflac8 libogg0 libopus0 libsoxr0 libvorbis0a libvorbisenc2 -y
RUN curl -L -o /tmp/snapserver.deb "https://github.com/badaix/snapcast/releases/download/v${SNAPCAST_VERSION}/snapserver_${SNAPCAST_VERSION}-1_${ARCH}.deb" \
     && dpkg -i /tmp/snapserver.deb || apt install -f -y --no-install-recommends \
     && apt clean && rm -fR /var/lib/apt/lists

COPY snapserver.conf /etc/snapserver.conf
COPY --from=librespot-make /usr/local/cargo/bin/librespot /usr/local/bin/

#CMD ["snapserver"]
CMD librespot  -n "HELLO" -b 160 -v
EXPOSE 1704/tcp 1705/tcp 1780

As you can see, I've removed all the avahi stuff, so it looks like the initial container I had running, but with the newest version of Librespot. There is also no Avahi working anywhere atm (not on the PI, not on the laptop i'm using).

Now onto the steps:

  1. Step 0 - did a-to-g but on g I don't see anything on _workstation._tcp -t but I see on _nvstream_dbd._tcp local
  2. Step 1: docker inspect mypy | jq -rc '.[0].NetworkSettings.Networks["my-macvlan"].IPAddress' -> results in
  3. Step 2: avahi-browse _raop._tcp -t | grep TEST_shairport && echo "Success" || echo "Failure" -> results in + enp0s3 IPv4 9391508A60DC@TEST_shairport AirTunes Remote Audio local Success
  4. Step 3: avahi-browse _spotify-connect._tcp -t | grep TEST_goello && echo "Success" || echo "Failure" results in + enp0s3 IPv4 TEST_goello _spotify-connect._tcp local Success
  5. Step 4: docker run -ti --rm --net my-macvlan --entrypoint librespot dubodubonduponey/spotify --name TEST_librespot -v Logs from the container
    [2021-11-30T19:18:08Z INFO  librespot] librespot 0.3.1 c1ac4cb (Built on 2021-11-16, Build ID: 4PPRzYnl, Profile: release)
    [2021-11-30T19:18:08Z DEBUG librespot_playback::mixer::mappings] Volume control is now Log(60.0)
    [2021-11-30T19:18:08Z DEBUG librespot_discovery::server] Zeroconf server listening on 0.0.0.0:43463
    [2021-11-30T19:18:08Z WARN  libmdns] Failed to register IPv6 receiver: Os { code: 19, kind: Uncategorized, message: "No such device" }

    avahi-browse _spotify-connect._tcp -t | grep TEST_goello && echo "Success" || echo "Failure" Failure

This might be relevant to the IPV6 error https://github.com/librespot-org/librespot/issues/67#issuecomment-848225881 @roderickvd is it possible for librespot to fail if it tries to connect to IPV6?

Now for the final test with all the containers:

avahi-browse _spotify-connect._tcp -t | grep TEST_librespot && echo "Success" || echo "Failure"
+   eth0 IPv4 TEST_librespot                                _spotify-connect._tcp local
Success
avahi-browse _spotify-connect._tcp -t | grep TEST_librespot && echo "Success" || echo "Failure"
+   eth0 IPv4 TEST_librespot                                _spotify-connect._tcp local
Success
avahi-browse _spotify-connect._tcp -t | grep TEST_goello && echo "Success" || echo "Failure"
+   eth0 IPv4 TEST_goello                                   _spotify-connect._tcp local
Success !! Note that this succeeded from within the container but not from outside. !!
avahi-browse _raop._tcp -t | grep TEST_shairport && echo "Success" || echo "Failure"
+   eth0 IPv4 9391508A60DC@TEST_shairport                   AirTunes Remote Audio local
Success

Caveats: My results are contaminated 😭

Thanks to everyone involved, you've been grand! Especially @dubo-dubon-duponey, thanks for the in-depth support! :) If anyone wants to try something on my environment, please add it here otherwise I'm closing the ticket.

dubo-dubon-duponey commented 2 years ago

@itwasonlyabug glad you got it working!

Step 4, I'm afraid you have typos in there. You are supposed to test for TEST_librespot in step4 (and NOT TEST_goello).

is it possible for librespot to fail if it tries to connect to IPV6?

I think it's a red herring. My hunch is "no".

Take-away:

Thanks for the offer to test in your environment. Though, since it does work now, I don't think it's going to surface useful info.

dubo-dubon-duponey commented 2 years ago

@sdetweil have you tried:

until the librespot instance gets authenticated, the device it represents is not found.

I believe this is true for any Spotify compatible speaker (inc. Sonos for example)... until it does authenticate with your user account, it will not be listed by your node app (the node module you are using clearly relies on https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-users-available-devices which can only list devices that are authenticated - either directly, or through the Spotify app).

Put otherwise, your node app is not able to discover existing speaker/endpoints. It only list the speakers/endpoints that are using your Spotify account.

In the case of librespot, that means you have to either:

Hope that helps.

sdetweil commented 2 years ago

yes, helps a lot.. there still is no spotify connect for raspi OS. SO, thats raspotify (which wraps librespot) .. SO local authentication is the only choice..

makes no sense to force someone to PLAY on THIS device (from some other device) with some OTHER tool, so you can then play on this device..

JasonLG1979 commented 2 years ago

makes no sense to force someone to PLAY on THIS device (from some other device) with some OTHER tool, so you can then play on this device..

I'm not sure how you would expect apps to show up in the node service your using, which only shows devices that are authenticated by your account to show up without credentials?

You're essentially asking "Why do I have to authenticate apps for them to show up in the list of authenticated apps?"

sdetweil commented 2 years ago

I know everyone is protecting their assets, vigorously, now.. sure makes useful solutions harder and harder to implement

anyway, I've put the info in a file, and can read it into env variables for when the support comes in..

JasonLG1979 commented 2 years ago

No, what I mean is what you're asking is nonsensical. It's not a matter of security.

In it's "natural" credential-less state librespot operates in zeroconf mode. In that mode it's visible to any and all other Spotify apps locally as a Spotify Connect endpoint. But since there are no creds it's not "owned" (authenticated) by any account. Only after you connect to it does it get authenticated.

If you want librespot to show up as authenticated or "owned" by your account before you connect you have to provide creds.

JasonLG1979 commented 2 years ago

It has to be authenticated one way or another for it to show up in your node app.

JasonLG1979 commented 2 years ago

anyway, I've put the info in a file, and can read it into env variables for when the support comes in..

Yep I know. I'm the Raspotify maintainer.

sdetweil commented 2 years ago

but it hasn't been required for years to do this. but anyway. times they are a changin

JasonLG1979 commented 2 years ago

but it hasn't been required for years to do this. but anyway. times they are a changin

This has not changed in librespot nor Raspotify. If something has changed in the way that librespot operates something has changed in your network or applications.

JasonLG1979 commented 2 years ago

That aspect of librespot has not changed in a very long time.

sdetweil commented 2 years ago

hm. I have been running librespot on this machine for 3 years, without authentication, and up til last year without Spotify connect ( Ubuntu ) for development and fixes, and never had this issue til this spring. the code I am maintaining is older than that