Expand description

Crates.io Docs CI

DISCLAIMER: the project is still in an early state. All parts may be subject to change.


A cross-platform library for handling OS media controls and metadata. One abstraction for Linux, MacOS and Windows.

Supported platforms

  • Linux (via MPRIS)
  • MacOS
  • Windows


  • Update metadata:
  • Play and pause polling.





$ cd souvlaki 
$ cargo run --example example

$ playerctl metadata
my_player xesam:artist              Slowdive
my_player xesam:album               Souvlaki
my_player mpris:artUrl              https://c.pxhere.com/photos/34/c1/souvlaki_authentic_greek_greek_food_mezes-497780.jpg!d
my_player mpris:trackid             '/'
my_player mpris:length              290000000
my_player xesam:title               When The Sun Hits


Screenshots coming soon.


The main struct is MediaControls. In order to create this struct you need a PlatformConfig. This struct contains all of the platform-specific requirements for spawning media controls. Here are the differences between the platforms:

  • MacOS: No config needed.
  • Linux:
    • dbus_name: The way your player will appear on D-Bus. It should follow the D-Bus specification.
    • display_name: This could be however you want. It’s the name that will be shown to the users.
  • Windows:
    • hwnd: In this platform, a window needs to be opened to create media controls. The argument required is an HWND, a value of type *mut c_void. This value can be extracted when you open a window in your program, for example using the raw_window_handle in winit.

A full cross-platform app would look like this:

use souvlaki::{MediaControlEvent, MediaControls, MediaMetadata, PlatformConfig};

fn main() {
    #[cfg(not(target_os = "windows"))]
    let hwnd = None;

    #[cfg(target_os = "windows")]
    let hwnd = {
        use raw_window_handle::windows::WindowsHandle;

        let handle: WindowsHandle = unimplemented!();

    let config = PlatformConfig {
        dbus_name: "my_player",
        display_name: "My Player",

    let mut controls = MediaControls::new(config);

    // The closure must be Send and have a static lifetime.
        .attach(|event: MediaControlEvent| println!("Event received: {:?}", event))

    // Update the media metadata.
        .set_metadata(MediaMetadata {
            title: Some("Souvlaki Space Station"),
            artist: Some("Slowdive"),
            album: Some("Souvlaki"),

    // Your actual logic goes here.
    loop {

    // The controls automatically detach on drop.

Check out this example here.

Thanks 💗

  • To jpochyla for being a contributor to library architecture and the sole developer of MacOS support.


A platform-specific error.

A handle to OS media controls.

The metadata of a media item.

An instant in a media item.

OS-specific configuration needed to create media controls.


Events sent by the OS media controls.

The status of media playback.

The direction to seek in.