Skip to content

ovos-media MPRIS Integration

In a nutshell

ovos-media can register on the D-Bus session bus as an MPRIS player (so tools like playerctl and desktop media widgets can control it) and, opt-in, can also reflect and take over other MPRIS players already running on the machine. For the core ovos-media service this extends, see ovos-media.

The legacy stack has MPRIS too, but it ships disabled

This page documents ovos-media's implementation. The default legacy stack (ovos-ocp-audio-plugin inside ovos-audio) also registers an MPRIS player, but the shipped mycroft.conf sets Audio.backends.OCP.disable_mpris: true, so it is off until you turn it on. You do not have to migrate to ovos-media to get MPRIS — see OCP Audio Plugin.

Note the two stacks spell the setting differently and with opposite polarity: legacy disable_mpris (shipped true) versus ovos-media's media.enable_mpris (default false).


MPRIS Integration

OCP integrates with MPRIS, allowing OCP to control and be controlled by external players. Via MPRIS (and KDEConnect), OCP can display data from external players and control playback in connected devices.

{
  "media": {
    "enable_mpris": true,
    "dbus_type": "session"
  }
}

Confirm OCP is registered with dbus:

dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply \
  /org/freedesktop/DBus org.freedesktop.DBus.ListNames

# Should show: "org.mpris.MediaPlayer2.OCP"

Position units differ between the OCP bus and MPRIS

Every position/length value on the OCP bus and in the media-backend contract (seekValue, set_track_position, get_track_position, get_track_length, and the GUI's position/duration fields) is milliseconds. MPRIS itself uses microseconds for its Position property, so ovos-media converts when exporting it (multiplying the millisecond value by 1000). This conversion is internal to the MPRIS exporter; nothing else in ovos-media deals in microseconds.


External Player Reflection & Takeover

OcpMprisExporter (ovos_media/mpris/__init__.py) has two roles, referred to as Role A and Role B. Role A is registering OCP itself on the D-Bus session bus (above), always active once enable_mpris is set, and it is what lets an MPRIS client like playerctl control OCP:

playerctl --player=org.mpris.MediaPlayer2.OCP play-pause
playerctl --player=org.mpris.MediaPlayer2.OCP next
playerctl --player=org.mpris.MediaPlayer2.OCP metadata

Role B is the opt-in second role, and lets OCP reflect and take over other MPRIS players already running on the same machine (Spotify, VLC, Firefox, and so on):

{
  "media": {
    "enable_mpris": true,
    "manage_external_players": true
  }
}

With manage_external_players enabled, OCP periodically scans D-Bus for other org.mpris.MediaPlayer2.* players and mirrors their metadata and playback state onto its own OCP bus messages, so an external player's now-playing info shows up the same way native OCP media does. When an external player starts playing, OCP automatically pauses itself, and vice versa when the external player stops, so only one thing is audibly playing at a time. OCP's own transport controls (skip/pause/shuffle/repeat) are proxied through to whichever external player is currently active, letting one set of controls (voice, GUI, or a remote MPRIS client) drive both native OCP media and third-party players interchangeably.

Not every external player reports an xesam:url in its metadata. When one does not, OCP synthesizes a mpris://<player-name> URI so the reflected now-playing entry can still be built.


Read next: ovos-media Configuration Related: ovos-media · ovos-media Legacy Compatibility · Audio Service