Setting up media keys with mpv
I mostly use mpv
for playing music, video, podcasts, and other media from my computers, and recently found myself needing to make use of the media keys on some Bluetooth headphones. If you're capable of continuing to listen to media while you're pushing a brown puck on the john, then why not have some control over playing/pausing and navigating tracks to soothe your soul. I digress, the actual reason is that the headset sends a "play" or "pause" key event when they are donned or removed by the wearer. A feature that is too spicy to pass up.
Pressing the buttons on the headset revealed that not only had I previously crudely re-mapped my keyboard's prev+next buttons to perform min and max backlight brightness, but that mpv
doesn't respond to these sorts of media key presses, even when it has focus. My first task was to find out commands that could later be added to my xbindkeysrc
to remotely control an mpv session.
Enter playerctl
A web search revealed that I was after the MPRIS protocol. A pacman -Ss mpris
revealed that I wanted playerctl
, a piece of software claiming to be able to control mpv
, among other media players. For most media players, it is zero-setup; you install it and can immediately playerctl --list-all
, as well as commanding actions such as playerctl next
. However, mpv didn't work out of the box; it doesn't show up when listing all players from playerctl
.
Enter mpv-mpris
It turns out mpv
doesn't support MPRIS out of the box, hence playerctl
can't see it. A plugin, mpv-mpris
, exists for solving this problem. At the time of writing, it is available from the AUR, and gives post-install print-out in pacman explaining how to use it. You can either pass the plugin's shared object in like:
mpv /path/to/media --script /usr/lib/mpv/mpris.s
or you can symlink the shared object into your mpv scripts directory to have it loaded automatically on bootup:
ln -s /usr/lib/mpv/mpris.so $HOME/.config/mpv/scripts/mpris.so
xbindkeys
There is plenty of information on the internet for using xbindkeys
to map special keys to run commands etc. In my case, I had some simplified entries that resembled:
# Play/pause media
"playerctl play-pause"
XF86AudioPlay
For most users, this should suffice, but I still had lingering issues with these bindings. Pausing from the headset would work, but resuming play would not. I pinned the issue down to there being a collision in the key name between a media key on my keyboard and the keypress that the headphones were sending. Using xbindkeys --key
gave showed the issue up, as well as providing the extra information needed to remove the ambiguity in the rc:
# headphones play key
"(Scheme function)"
m:0x0 + c:208
XF86AudioPlay
# keyboard play key
"(Scheme function)"
m:0x0 + c:172
XF86AudioPlay
With the entries for the overlapping keys duplicated, and one of the lines m:0x0 + c:172
and m:0x0 + c:208
put into each of the bind entries for XF86AudioPlay
, there is no longer a collision. Restarting xbindkeys
on this updated rc file leaves both buttons working correctly and independently. For example:
# Play/pause on keyboard
"playerctl play-pause"
m:0x0 + c:172
XF86AudioPlay
# Play from Headphones
"playerctl play"
m:0x0 + c:208
XF86AudioPlay
# Pause from Headphones
"playerctl pause"
m:0x0 + c:209
XF86AudioPause
# Next track
"playerctl next"
...
Don't simply copy-paste this configuration, since your system may well have different m
and c
values. Always generate these parts of the config with xbindkeys --key
and stick the desired command on the top of the generated output.