Yeah, nah, aye

Main categories:

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.