librespot-org / librespot

Open Source Spotify client library
MIT License
4.75k stars 584 forks source link

Add support for playing to ALSA multi #525

Closed carlyd95 closed 3 years ago

carlyd95 commented 3 years ago

I don’t know if this is something that can be achieved but I figured I’d ask...

I’m currently just using snapcast, one of the devices in the multi is latent as well and I don’t know if there is a way to configure latency in asound.conf

Error produced by setting --device to a multi defined in /etc/asound.conf:

2020-09-20T19:13:16Z INFO librespot] librespot bf44c8c (2020-07-29). Built on 2020-08-24. Build ID: h5fuo7pg [2020-09-20T19:13:19Z INFO librespot_core::session] Connecting to AP "guc3-accesspoint-b-261t.ap.spotify.com:4070" [2020-09-20T19:13:19Z INFO librespot_core::session] Authenticated as "carly-d95" ! [2020-09-20T19:13:19Z INFO librespot_playback::audio_backend::alsa] Using alsa sink [2020-09-20T19:13:19Z INFO librespot_core::session] Country: "US" [2020-09-20T19:13:19Z INFO librespot_playback::player] Loading with Spotify URI [2020-09-20T19:13:21Z INFO librespot_playback::player] (238595 ms) loaded ALSA lib pcm.c:8424:(snd_pcm_recover) underrun occurred ALSA lib pcm.c:8424:(snd_pcm_recover) underrun occurred ALSA lib pcm.c:8424:(snd_pcm_recover) underrun occurred ...

If anyone has ideas let me know if not, snapcast it is.

JasonLG1979 commented 3 years ago

This isn't a librespot problem it's a configuration issue.

It would help though if you explained you're setup and desired audio flow. Like are you trying to do librespot > snapcast server > x number of clients on different machines? Are you trying to play audio on the server too but you can't keep it sync'd with the other clients not on the same machine? In any event I would think that you'd want to output to the pipe file the snapcast server is listening to directly. If you want to listen to audio on the same machine as the server run a client on that machine and let snapcast do it's job and handle keeping everything in sync including the host device. You'll never be able to keep it sync'd if you split the audio before snapcast.

It should look like this:

Librespot > snapcast pipe file > snapcast server x number of clients one of which may be on the same device.

JasonLG1979 commented 3 years ago

If that still doesn't work and everything is more or less in sync but you're still getting underruns on that one device you can raise the buffer on all devices (to keep them in sync) until the underruns stop on the crap device. The only way I know how to do that is with dmix.

Something like this should work. This will get you a 1 sec buffer which should be plenty. This ofc means that all devices will have 1 sec of latency but they should more or less be in sync.

defaults.pcm.card 1 # replace with whatever your device is.
defaults.ctl.card 1 # replace with whatever your device is.

pcm.dmixer {
    type dmix
    ipc_key 1024
    ipc_perm 0666
    slave {
        pcm "hw:1" # replace with whatever your device is.
        rate 44100
        format S16_LE
        period_time 125000
        buffer_time 1000000
    }
    bindings {
        0 0
        1 1
    }
}

ctl.dmixer {
    type hw
    card "hw:1" # replace with whatever your device is.
}

pcm.!default {
    type plug
    slave.pcm dmixer
}

You would also want to set snapcast to 16 bit 44.1 Khz, it defaults to 48 Khz I believe. There's no real point of upsampling to 48 Khz unless your devices don't support 44.1 Khz.

carlyd95 commented 3 years ago

The whole reason I was trying to do this was to eradicate the need of snapcast. I will try your suggestion this afternoon. Basically I want librespot to send audio to my jbl Bluetooth speaker and to loopin (for use with MLSC)

Here is my asound.conf:

pcm.multi { type route; slave.pcm { type multi; slaves.a.pcm "jbl"; slaves.b.pcm "loopin"; slaves.a.channels 2; slaves.b.channels 2; bindings.0.slave a; bindings.0.channel 0; bindings.1.slave a; bindings.1.channel 1; bindings.2.slave b; bindings.2.channel 0; bindings.3.slave b; bindings.3.channel 1; }

ttable.0.0 1;
ttable.1.1 1;
ttable.0.2 1;
ttable.1.3 1;

} pcm.both { type plug slave.pcm "multi" }

carlyd95

pcm.loopin { type plug slave.pcm "hw:Loopback,0,0" } pcm.loopout { type plug slave.pcm "plughw:Loopback,1,0" } pcm.jbl { type plug slave { pcm { type bluealsa device 98:52:3D:BB:82:F3 profile "a2dp" } } hint { show on description "JBL Charge 4" } }

pcm.sony { type plug slave { pcm { type bluealsa device 74:45:CE:27:E3:08 profile "a2dp" } } hint { show on description "JBL Charge 4" } }

JasonLG1979 commented 3 years ago

I don't think you'll ever be able to match the latency of your bluetooth speaker. Even if you could get close it would probably drift up and down which would cause sort of a weird phasing effect like a guitar effects pedal. I don't think Bluetooth has any sort of latency guarante.

carlyd95 commented 3 years ago

Thanks man, that’s what I needed to know. I’ll continue to use snapcast.

Here’s the project btw.