-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpd: extend coverage of MPD protocol #3200
Conversation
Although crossfade is not implemented in bpd, we can store the setting and repeat is back to clients. Also log a warning that the operation is not implemented. The real MPD doesn't show the crossfade in status if it's zero since that means no crossfade, so now we don't either.
If an MPC client is expecting a command to take an argument that bpd isn't expecting (e.g. because of a difference in protocol versions) then bpd currently crashes completely. Instead, do what the real MPD does and return an error message over the protocol.
These are a more sophisticated version of crossfade so we're free to ignore them, at least for now. We now track the values of the two settings, and show them in the status output. Like MPD, we suppress the mixrampdb value if it's set to nan, which is how it signals that the feature should be turned off.
MPD supports a deprecated command 'volume' which was used to change the volume by a relative amount unlike its replacement 'setvol' which uses an absolute amount. As far as I can tell 'volume' always responds with a system error message "No mixer".
There's a special status command for checking the replay gain mode, which can be set to one of a short list of possible values. For now at least we can ignore this feature, but track the setting anyway.
The real MPD offers persistent playlist manipulation, storing the playlists in a directory set in the config file. If that directory is not available then the feature is disabled and the relevant commands all respond with errors. Based on this, the initial support in bpd just returns errors matching the MPD server in the disabled mode. For playlistadd, extend the _bpd_add helper to work with playlists other than the queue in order to support testing the real implementations of these commands in the future.
This command instructs bpd to stop playing when the current song finishes. In the MPD 0.20 protocol this flag gains a value 'oneshot' but for now we just support its older version with a boolean value.
The repeat flag indicates that the entire playlist should be repeated. If both the repeat and single flags are set then this triggers the old behaviour of looping over a single track.
The songs are indexed starting from zero for the play command, however the bound check was off by one. An index matching the length of the playlist would crash the server instead of responding with an error message over the protocol.
Previously issuing the 'previous' command when at position 0 on the playlist would cause bpd to stop playing. MPD instead just restarts the currently playing song instead, so we now match this behaviour.
These flags are all relevant to the 'previous' command as well as the 'next' command.
Ok I think this might be enough for the first batch of bpd changes before this PR gets too long. The main feature in this PR that benefits current users right now is that bpd will crash less often. After merging this bpd will be in a sort of hybrid state in terms of protocol support since since e.g. The stored playlist features could be implemented for real easily enough, but since they're optional in MPD anyway I'm starting off with placeholders. Advanced playback features like crossfade and replaygain could potentially have real implementations instead of the current placeholders if we pick up an optional dependency on a more sophisticated audio player backend library. We can think about that after catching up with MPD though, if there's even a demand for it. I've been testing locally with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks awesome! I agree that it is totally fine to start with partial support for the new features—this seems really unlikely to confuse any clients. We can increment the version number, as you say, once we cover all the major features for that version.
I have just a few minor comments inline.
Check function signature instead of using TypeError to crudely guess that the wrong number of arguments were provided. Prevent bpd from crashing when trying to log a traceback. The `traceback.format_exc` function takes an optional argument which is supposed to be an integer restricting the length of the backtrace to show. Instead we were passing the exception object to this function and causing a new exception to be raised.
I've run into an issue with In Python 2 the wrapper is using: Python 2.7.16 (default, Mar 4 2019, 15:29:09)
[GCC 8.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import inspect
>>> class A:
... def cmd_a(self, a, b, c): pass
...
>>> an_a = A()
>>> inspect.getargspec(an_a.cmd_a)
ArgSpec(args=['self', 'a', 'b', 'c'], varargs=None, keywords=None, defaults=None) Whereas in Python 3 it's using: Python 3.7.3 (default, Mar 26 2019, 07:25:18)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import inspect
>>> class A:
... def cmd_a(self, a, b, c): pass
...
>>> an_a = A(); inspect.signature(an_a.cmd_a)
<Signature (a, b, c)>
>>> sig = inspect.signature(an_a.cmd_a)
>>> sig.parameters
mappingproxy(OrderedDict([('a', <Parameter "a">), ('b', <Parameter "b">), ('c', <Parameter "c">)]))
>>> inspect.getfullargspec(an_a.cmd_a)
FullArgSpec(args=['self', 'a', 'b', 'c'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) That is, in the shim the Edit: |
Under the original compatibility shim we weren't correctly inclusing `self` in the argument list for bound methods.
Thank you for looking into the inspect deprecation! I'm really happy the stdlib authors un-deprecated that call. I like this so much better without the wrapper than with it. 🎉 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks fantastic! Would you mind adding a short changelog about the new protocol features that BPD supports so far?
Wonderful! Thanks again for your attentiveness here! ✨ |
Adds support for some of the "easy" MPD protocol features bpd is missing, as part of #800. I'll do more complicated features like the
idle
command separately, and unfortunately we needidle
to be able to increment the protocol version string.The MPD protocol specification document is not very precise and is intended to be read together with the MPD source code and an actual MPD server. Some of the clients I've seen tend to ignore the MPD version in the client hello message (or maybe at most issue a warning if it looks too old) and attempt to use the commands they want to use anyway, whereas others abort on an old version. For those reasons I think incremental updating of the protocol support should be OK, as long as we don't bump the protocol version string past a version of the protocol that we can actually support.
This adds/changes:
consume
mode, which erases songs from the playlist as they are played,single
mode, which stops playback when the current song finishes,repeat
mode now repeats the entire playlist rather than a single track unless used in conjunction withsingle
mode,previous
when on track 0 now restarts track 0 instead of stopping bpd,status
gained some new fields, like the higher-precision timeselapsed:
andduration:
,crossfade
,mixramp*
,replay_gain_*
,volume
, and stored playlist commands (listplaylists
,save
, etc.).