Spotifyd / spotifyd

A spotify daemon
https://spotifyd.rs
GNU General Public License v3.0
9.79k stars 447 forks source link

dbus mpris PlayPause command does not work #890

Closed Icelk closed 2 years ago

Icelk commented 3 years ago

Description When trying to play-pause via dbus mpris, spotifyd resumes, but seems unavailable to pause.

To Reproduce

  1. Compile with the features pulseaudio_backend,dbus_mpris
  2. Use dbus to send a mpris command (e.g. playerctl play-pause)
  3. Music starts, but does not stop.

Expected behavior

Should pause and resume.

Logs First one, when using the PlayPause command

Click to show logs ``` handle_msgs: (MethodCall, Some("/org/mpris/MediaPlayer2"), Some("org.mpris.MediaPlayer2.Player"), Some("PlayPause")) loop poll - 3.209350078s loop time - Instant { tv_sec: 1665, tv_nsec: 985905862 } loop process, 7.944µs Polling message stream msgstream found Ok(Ready(Some((MethodCall, Some("/org/mpris/MediaPlayer2"), Some("org.mpris.MediaPlayer2.Player"), Some("PlayPause"))))) Polling message stream msgstream found Ok(NotReady) D-Bus i/o poll ready: 47 is Ready(Readable) D-Bus i/o unix ready: 47 is Readable | Aio scheduling Read for: 4 scheduling Read for: 5 flushing framed transport writing; remaining=342 framed transport flushed loop poll - 49.473µs loop time - Instant { tv_sec: 1665, tv_nsec: 986038801 } loop process, 4.428µs Polling message stream msgstream found Ok(NotReady) event Readable | Writable Token(20971525) loop process - 1 events, 0.000s attempting to decode a frame frame decoded from buffer attempting to decode a frame scheduling Read for: 5 flushing framed transport framed transport flushed loop poll - 54.747185ms loop time - Instant { tv_sec: 1666, tv_nsec: 40800483 } loop process, 5.33µs Polling message stream msgstream found Ok(NotReady) loop poll - 1.252µs loop time - Instant { tv_sec: 1666, tv_nsec: 40822233 } loop process, 4.769µs ```

Second one, when using the Pause command

Click to show logs ``` handle_msgs: (MethodCall, Some("/org/mpris/MediaPlayer2"), Some("org.mpris.MediaPlayer2.Player"), Some("Pause")) loop poll - 11.221291429s loop time - Instant { tv_sec: 1786, tv_nsec: 380255459 } loop process, 4.609µs Polling message stream msgstream found Ok(Ready(Some((MethodCall, Some("/org/mpris/MediaPlayer2"), Some("org.mpris.MediaPlayer2.Player"), Some("Pause"))))) Polling message stream msgstream found Ok(NotReady) Sending status to server: [kPlayStatusPause] D-Bus i/o poll ready: 47 is Ready(Readable) D-Bus i/o unix ready: 47 is Readable | Aio scheduling Read for: 4 scheduling Read for: 5 flushing framed transport writing; remaining=2114 framed transport flushed loop poll - 55.935µs loop time - Instant { tv_sec: 1786, tv_nsec: 380387346 } loop process, 5.791µs Polling message stream msgstream found Ok(NotReady) command=Pause == Stopping sink == loop poll - 5.149706ms loop time - Instant { tv_sec: 1786, tv_nsec: 385554375 } loop process, 9.938µs Polling message stream msgstream found Ok(NotReady) Sending status to server: [kPlayStatusPause] ==> kPlayStatusPause scheduling Read for: 5 flushing framed transport writing; remaining=2114 framed transport flushed loop poll - 48.411µs loop time - Instant { tv_sec: 1786, tv_nsec: 385672105 } loop process, 4.699µs event Readable | Writable Token(20971525) loop process - 1 events, 0.000s attempting to decode a frame frame decoded from buffer attempting to decode a frame scheduling Read for: 5 flushing framed transport framed transport flushed loop poll - 46.990391ms loop time - Instant { tv_sec: 1786, tv_nsec: 432669760 } loop process, 7.935µs Polling message stream msgstream found Ok(NotReady) loop poll - 1.032µs loop time - Instant { tv_sec: 1786, tv_nsec: 432697492 } loop process, 4.548µs event Readable | Writable Token(20971525) loop process - 1 events, 0.000s attempting to decode a frame frame decoded from buffer attempting to decode a frame scheduling Read for: 5 flushing framed transport framed transport flushed loop poll - 57.11597ms loop time - Instant { tv_sec: 1786, tv_nsec: 489819743 } loop process, 6.492µs Polling message stream msgstream found Ok(NotReady) loop poll - 902ns loop time - Instant { tv_sec: 1786, tv_nsec: 489841083 } loop process, 3.035µs ```

Compilation flags

Versions (please complete the following information):

Icelk commented 3 years ago

If anyone else encounters this, I've made a fast script which resolves this and adds further functionality (such as pausing all before playing again). https://github.com/Iselk/dotfiles/blob/main/scripts/playerctl-custom.sh

flaktack commented 3 years ago

I've opened a PR for librespot which fixes the handling of the play/pause toggling and should solve this: https://github.com/librespot-org/librespot/pull/605

Icelk commented 3 years ago

@flaktack Thanks a lot! Hope it gets merges fast.

Icelk commented 3 years ago

I’ll test this in a few, librespot-org/librespot#605 supposedly solved it. Thanks again @flaktack !

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

georgefst commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

I'd say this is still worth keeping open until the relevant version of librespot gets merged (I really don't see the point of this bot...).

Icelk commented 3 years ago

👍

I’ll also check up on this again later today, to see how it behaves now.

Icelk commented 3 years ago

I can't test that this is fixed with Librespot v0.2.0, the newest. A upgrade to Librespot requires major changes. in Spotifyd.

When I upgraded to v0.1.6, a version published the same day as the pull request was merged, this bug persists.

shadowninja55 commented 3 years ago

Any updates on this? I'm having the same issue with play-pause, and I don't reallly understand the script that @Icelk provided.

Icelk commented 3 years ago

I don't reallly understand the script that @Icelk provided.

It’s a Fish script which sends raw dbus-send requests to clients listed by playerctl -l. It bypasses the PlayPause issue by getting the status and sending the opposite to play/pause.

It also prioritises spotifyd over all other audio sources.

I can comment the script if you’d like.

shadowninja55 commented 3 years ago

I don't reallly understand the script that @Icelk provided.

It’s a Fish script which sends raw dbus-send requests to clients listed by playerctl -l. It bypasses the PlayPause issue by getting the status and sending the opposite to play/pause.

It also prioritises spotifyd over all other audio sources.

I can comment the script if you’d like.

So you just run the script with fish as an alternative to playerctl play-pause?

EDIT: Yes, some comments would be wonderful, thanks.

Icelk commented 3 years ago

So you just run the script with fish as an alternative to playerctl play-pause?

Yes!

I’ll comment the script today and ping you here when it’s done.

Icelk commented 3 years ago

@shadowninja55 I've commented the script now in this commit.

jacksongoode commented 3 years ago

Having the same issue, I guess just waiting until spotifyd has an overhaul :( @Icelk would you have any interest in converting your script into Bash? Nice little script for the job though!

MikaelElkiaer commented 3 years ago

If anyone is interested in a simple bash script for mimicking play-pause:

playerctl -l | grep spotifyd &> 0 && (playerctl -p spotifyd status | grep Playing &> 0 && playerctl -p spotifyd pause) || (playerctl -p spotifyd status | grep Paused &> 0 && playerctl -p spotifyd play)
Icelk commented 3 years ago

@jacksongoode Sure! I’ll ping you here when it’s done, probably tomorrow.

Icelk commented 3 years ago

@jacksongoode I rewrote the script in Bash in this commit. It seems to work exactly like the Fish version.

If you found it helpful and don't mind, I'd appreciate a star 😊

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

georgefst commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Stale bots are a truly terrible idea.

JojiiOfficial commented 2 years ago

It is indeed handy when it comes to managing big repositories but I agree on lesser active repositories its sometimes annoying. If you have a better approach, we're open for recommendations.

georgefst commented 2 years ago

Well, my preferred approach is just not using them.

I can maybe just about see the purpose for very large projects that receive vast numbers of low-quality issues (VScode, npm, ...). But elsewhere all it seems to do is provide an illusion of progress: the issue count goes down but only because unresolved issues get closed and contributors are disincentivised from even opening issues because they haven't got time to battle against the bot.

Maybe there's some value you find that I'm missing?

AlejandroMinaya commented 2 years ago

Hello! In case someone was not able to get it to work and is willing to use a Python-based workaround, I whipped up this script:

#!/usr/bin/env python
import dbus
from argparse import ArgumentParser

CTL_INTERFACE = "org.mpris.MediaPlayer2.Player"
INFO_INTERFACE = "org.freedesktop.DBus.Properties"

if __name__ == "__main__":
    parser = ArgumentParser()
    parser.add_argument(
        "command",
        choices=["play", "pause", "toggle", "next", "prev"],
    )

    args = parser.parse_args()

    bus = dbus.SessionBus()
    spotifyd = bus.get_object(
        "org.mpris.MediaPlayer2.spotifyd",
        "/org/mpris/MediaPlayer2"
    )
    spotctl = dbus.Interface(spotifyd, dbus_interface=CTL_INTERFACE)
    spotinfo = dbus.Interface(
        spotifyd, dbus_interface=INFO_INTERFACE
    )

    if args.command == "play":
        spotctl.Play()
    elif args.command == "pause":
        spotctl.Pause()
    elif args.command == "toggle":
        status = spotinfo.Get(CTL_INTERFACE, "PlaybackStatus")
        if status == "Playing":
            spotctl.Pause()
        else:
            spotctl.Play()
    elif args.command == "next":
        spotctl.Next()
    elif args.command == "prev":
        spotctl.Previous()

It is dependent on dbus-python (v1.2.16).

Example

./script toggle # Plays/Pause spotifyd depending on its PlaybackStatus
Icelk commented 2 years ago

@AlejandroMinaya Does my script not work for you?

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Icelk commented 2 years ago

Seems to work now, with the update of Librespot.