Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

mpris

MPRIS: media players with metadata, controls, TrackList and Playlists.

local player = mantle.mpris:map(function(mpris)
    return mpris.players[1]
end)

rect {
    on_click = function()
        local current = player:get()
        if current then
            mantle.mpris:control(current.id, "play_pause")
        end
    end,
    children = {
        text {
            max_width = 240,
            elide = "end",
            content = player:map(function(current)
                return current and (current.play_state .. ": " .. current.title) or ""
            end, ""),
        },
    },
}

State

mantle.mpris:get() returns MprisState, nil before the first push. A field marked ? may be absent.

FieldTypeDescription
playersPlayerState[]Every controllable MPRIS player except playerctld, longest-running first, so players[1] stays put; empty when none runs.

LoopStatus

MPRIS LoopStatus, also the set_loop_status argument.

ValueDescription
"none"Plays through once.
"track"Repeats the current track.
"playlist"Repeats the playlist.

PlayState

MPRIS PlaybackStatus.

One of "playing", "paused", "stopped".

PlayerState

FieldTypeDescription
albumstringAlbum title; empty when unset.
album_art_pathstringCover art as an existing local path, or empty when unavailable.
album_artiststringAlbum artists joined with ", "; empty when unset.
art_urlstringmpris:artUrl as sent, e.g. an https:// image to fetch and cache; empty when unset.
artiststringArtists joined with ", "; empty when unset.
can_go_nextbooleanMPRIS CanGoNext.
can_go_previousbooleanMPRIS CanGoPrevious.
can_pausebooleanMPRIS CanPause.
can_playbooleanMPRIS CanPlay.
can_quitbooleanMPRIS CanQuit on the root interface.
can_raisebooleanMPRIS CanRaise on the root interface.
can_seekbooleanMPRIS CanSeek.
desktop_entrystringThe player’s .desktop basename, e.g. "firefox", for app matching; empty when unset.
genrestringGenres joined with ", "; empty when unset.
idstringBus-name suffix after org.mpris.MediaPlayer2., e.g. "spotify"; every action takes it.
identitystringDisplay name, e.g. "Spotify"; empty if unanswered.
length?integerTrack length in microseconds, or nil when unknown, as for a live stream.
loop_status?LoopStatusMPRIS loop mode; nil when the player does not report one.
maximum_ratenumberMPRIS maximum playback rate, or 0 when unavailable.
minimum_ratenumberMPRIS minimum playback rate, or 0 when unavailable.
pid?integerProcess id of the bus name’s owner, which mantle.audio.apps[].pid matches exactly; nil when the bus refuses. A sandboxed app’s streams may report a pid from inside its sandbox.
play_statePlayStateMPRIS PlaybackStatus; keeps the last value when a read fails, "stopped" if none.
playlistsPlaylistsStateOne bounded page from the optional MPRIS Playlists interface.
position?integerPlayback offset in microseconds as of position_updated_at, not polled while playing: add elapsed time. nil when unknown.
position_updated_atintegerCLOCK_MONOTONIC microseconds when position was read: the clock of mantle.clock:now() in seconds, so mantle.clock:now() - position_updated_at / 1e6 is the age.
ratenumberMPRIS playback rate.
shufflebooleanMPRIS shuffle setting.
titlestringTrack title; empty when unset, normal between tracks.
track_listTrackListStateNearby tracks from the optional MPRIS TrackList interface.
urlstringxesam:url as sent, e.g. a file:// path or an https:// page; empty when unset.
volumenumberMPRIS volume in percent, 100 when unreported. The protocol permits amplification above 100.

PlaylistSummary

FieldTypeDescription
iconstringIcon URI, or empty if absent.
idstringStable playlist object path.
namestringUser-facing playlist name.

PlaylistsState

FieldTypeDescription
active?PlaylistSummaryActive playlist, if the player reports one.
countintegerTotal playlists reported by the player.
indexintegerIndex used for the current page.
orderstringOrdering used for the current page.
orderingsstring[]Ordering names accepted by playlists_get.
page_sizeintegerNumber of entries requested for the current page, at most 100.
playlistsPlaylistSummary[]At most 100 playlist entries.
reversebooleanWhether the page is reversed.

TrackListState

FieldTypeDescription
can_editbooleanWhether the player permits add and remove calls.
current_trackstringCurrent TrackList object path, or empty if unknown.
tracksTrackSummary[]At most 100 tracks around the current track; the full playlist remains player-owned.

TrackSummary

FieldTypeDescription
artiststringTrack artists joined with ", ".
idstringTrackList object path, used by track_list_go_to and track_list_remove_track.
length?integerTrack length in microseconds, or nil when unknown.
titlestringTrack title, empty when the player has none.

Actions

Call each as mantle.mpris:<action>(arguments...); ? marks an argument you may omit.

ActionArgumentsDescription
controlid: string, cmd: PlayerCommandSends a playback command to players[].id.
seekid: string, position_us: integerSeeks to an absolute position in microseconds, clamped to [0, length] (only >= 0 when length is nil).
seek_relativeid: string, offset_us: integerSeeks by a signed offset in microseconds, unclamped; past the end may skip to the next track.
raiseid: stringCalls Raise; check players[].can_raise before calling.
quitid: stringCalls Quit; check players[].can_quit before calling.
open_uriid: string, uri: stringOpens an absolute URI in the player.
set_volumeid: string, value: numberSets MPRIS Volume in percent; finite values at or above zero are accepted.
set_loop_statusid: string, value: LoopStatusSets MPRIS LoopStatus.
set_shuffleid: string, value: booleanSets MPRIS Shuffle.
set_rateid: string, value: numberSets a positive finite MPRIS playback rate.
track_list_add_trackid: string, uri: string, after_track: string, set_as_current: booleanInserts a URI after a track id, or after /org/mpris/MediaPlayer2/TrackList/NoTrack to prepend.
track_list_remove_trackid: string, track_id: stringRemoves a track by its TrackList object path.
track_list_go_toid: string, track_id: stringStarts the track identified by its TrackList object path.
playlists_getid: string, index: integer, count: integer, order: string, reverse: booleanReads a bounded playlist page into players[].playlists.
playlists_activateid: string, playlist_id: stringActivates a playlist by its object path.

PlayerCommand

One of "play", "pause", "play_pause", "next", "previous", "stop".

Backend

ContractBehavior
DiscoverySession bus ListNames once, then NameOwnerChanged for org.mpris.MediaPlayer2.*. Skips playerctld and any player reporting CanControl = false
PushesOn playback, metadata, control-property, TrackList or Playlists changes and on Seeked. A status change re-reads Position 100 ms later. Nothing polls
Seekseek calls SetPosition with the cached mpris:trackid. A player without one gets a relative Seek from a live Position read
ControlsRead can_* before calling matching methods. Setters accept a finite nonnegative volume percent, positive finite rate within advertised limits, and "none", "track", or "playlist" loop status
ArtworkUses existing local file:// paths. Remote artwork URLs are unsupported

How do I…

TaskAnswer
Show a live progress barCompare position_updated_at / 1e6 with mantle.clock:now(), or stamp each new report in on_change and add the seconds since: Media player

Gotchas

TrapFix
position stands still while playingIt is the offset at position_updated_at, not polled. Extrapolate, as above
position_updated_at compared with mantle.clock.monotonic is off by a millionSame clock, different unit: microseconds against seconds. Divide by 1e6; use mantle.clock:now() for a live reading

See also: Media player recipe.

Source: supervisor/src/capabilities/mpris/