hrkfdn / ncspot

Cross-platform ncurses Spotify client written in Rust, inspired by ncmpc and the likes.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Changing volume internally does not change MPRIS volume

aubergino opened this issue · comments

Describe the bug

When I change the volume inside the ncspot application, whether by commands, scroll wheel, or keybinds, this does not update MPRIS' idea of ncspot's internal volume. As a matter of fact, the exact same one-sided communication happens with repeat and shuffle. For example...

To Reproduce

Steps to reproduce the behavior:

  1. Have a song playing so you can tell what's going on.
  2. Use MPRIS (I use the Media Player Plasmoid from KDE Plasma) to set ncspot's volume to 100%.
  3. Inside ncspot, set the volume (using any method you like) to 50%. The music gets quieter.
  4. Use MPRIS to decrement the volume by 5%. It sets ncspot's volume to 95%.

Expected behavior

In the above example, I expected ncspot's volume to be set to 45% after the final step.

System

  • OS: Arch Linux
  • Terminal: Konsole
  • Version: 0.13.2-3
  • Installed from: Arch official repositories

Screenshots


Changed from inside ncspot, they don't match

Debug log

This log was massive, so for clarity I only included the part of the log that actually, y'know, relate to this bug report. I didn't exclude anything from where the log starts to where it ends, however; I only trimmed out the start and end.
ncspot-debug-1.log

Additional context

Status is passed on during startup

It seems that whenever you start ncspot, the state is loaded into MPRIS. For example, if I set repeat=R1, shuffle=on, volume=70% inside ncspot, MPRIS will have no idea. But if I quit ncspot then restart it, MPRIS is suddenly aware of all those things.

playerctl works, so it might be partially KDE's fault...

I conducted some testing with playerctl, and it seems to me like half the fault here is with KDE.
If I repeat the above methodology but replace the last step with running playerctl volume -0.05, everything works fine.
Same goes for playerctl shuffle toggle.
playerctl doesn't have an absolute command for repeating, so I can't compare there.
My hypothesis, therefore, is that their Plasmoid does not pass on relative commands but appears to store an internal value for volume/repeat/shuffle and then use absolute commands like playerctl volume 0.95. Or playerctl shuffle off instead of playerctl shuffle toggle, depending on the internally stored value.

...but not completely

When I use the official Spotify client to do the same tests, I don't get this issue. When I change shuffle, repeat, or volume in Spotify, the status in the Plasmoid changes to match. So even if the Plasmoid does keep track of the volume/repeat/shuffle internally, it updates them when Spotify changes something. Look, I even took a screenshot:

@aubergino Is this fixed with the changes from #1343 or is that unrelated? I don't use KDE so can't reproduce it, unfortunately.

@hrkfdn Unfortunately no--Arch hasn't updated their ncspot repo package past 0.13.2 yet, but when I compiled v1.0.0 via the AUR package ncspot-git, the problem is still there.

EDIT: I also tried tweaking Arch's official PKGBUILD for ncspot to compile v1.0.0, as well as cloning this repository and compiling with cargo build --release --features cover,mpris, with the same result :/

I think the plasmoid caches the value for volume while playerctl might not do that. I tested with busctl sending the raw MPRIS commands and when using MPRIS, ncspot sends the PropertyChanged signals. When changing the volume inside ncspot, those signals are never sent, so the plasmoid probably uses the cached value. There is no relative volume adjustments in the MPRIS standard so the tools mimick this, and when they do it with the cached value, you would get this incorrect behavior.

TLDR: It's a problem with ncspot because it doesn't send PropertyChanged when the volume is changed inside ncspot, only when using MPRIS.

@hrkfdn I've been looking into this and my first thought was to add an extra event to PlayerEvent which would then be used to call update() on the MprisManager inside the event loop, but I don't fully understand what that enum is used for. I assumed it was for real events generated by the player, but it is also used as a status for playback, which means something like VolumeChanged doesn't really belong there? I don't fully understand what Spotify is for either.

@ThomasFrans Sounds appropriate to me. Spotify is responsible for updating the volume in the Librespot player (which is hosted by the Worker). So if things in the player change (including volume), it could emit a PlayerEvent.