Is it possible to "overload" the dbus Get Properties command?

485 Views Asked by At

I am trying to set up bluetooth audio for my car using my raspberry pi. I music streaming from my phone and 2 GPIO buttons set up which use DBus messages to move the tracks forward or back. I would like to have a screen displaying the current song playing but I am hitting a snag.

Using dbus I can issue this command:

dbus-send --system --type=method_call --print-reply --dest=org.bluez /org/bluez/hci0/dev_DC_41_5F_17_4C_79/player0 org.freedesktop.DBus.Properties.Get string:org.bluez.MediaPlayer1 string:Track

Which returns this "variant"

variant       array [
     dict entry(
        string "Item"
        variant                object path "/org/bluez/hci0/dev_DC_41_5F_17_4C_79/player0/NowPlaying/item751498629074736430"
     )
     dict entry(
        string "Album"
        variant                string "Horse Of A Different Color"
     )
     dict entry(
        string "TrackNumber"
        variant                uint32 1
     )
     dict entry(
        string "Genre"
        variant                string "Country"
     )
     dict entry(
        string "Duration"
        variant                uint32 173061
     )
     dict entry(
        string "NumberOfTracks"
        variant                uint32 50
     )
     dict entry(
        string "Title"
        variant                string "Drinkin' 'Bout You"
     )
     dict entry(
        string "Artist"
        variant                string "Big & Rich"
     )
  ]

What I would like to do is have only the title of the song be returned. I have tried entering the word 'Title' instead of 'Track', also adding another operator at the end of the command 'string: Title' in hopes that it would narrow down the information. But I have no luck.

Can anyone shed some light on how I might go about displaying the Title only? Thanks

1

There are 1 best solutions below

0
On

I'm not sure there is a way to read a variant outside a program. If not, you will need to build a little program to achieve what you want to do.

A variant is a container, the information you seek is inside this variant. Your variant is of type a{sv} which means it is a dictionnary {key,value} where the keys are string (s) and the values are variants (v).

The following C code will parse the variant (using the GLib GDBus api):

/* Call the method that will return your variant dictionary */
GVariant *returnValue = MethodCallThatWillReturnTheDictionary();

/* This will be used to iterate through the dict */
GVariantIter *iter_dict; 

/* These two will be used to store the key and value pair in the dict */
const gchar *key;
GVariant value;

/* Init the iterator */
g_variant_get(returnValue, "a{sv}", &iter_dict);

/* Iterate through the dict */
while(g_variant_iter_loop(iter_dict, "{&sv}", &key, &value)){

    /* Each time we iterate, check if the key is "Title" */
    if( ! strcmp(key, "Title")){

        /* You now know that the Title is inside the "value" variant
           We still have to extract it */

        int title_length /* This will receive the Title length */
        const gchar *yourTitle = g_variant_get_string(value, &title_length);

    }
}
g_variant_iter_free(iter_dict); /* We don't need it anymore */

You can get more information about Variants here :

https://developer.gnome.org/glib/stable/glib-GVariant.html

and here :

https://developer.gnome.org/glib/stable/gvariant-format-strings.html

If you're unsure about DBus and GDBus (the GLib bindings for DBus), you can read more in the link below, look for the low-level and high-level D-Bus support. In your case you would need GDBusConnection and GDBusProxy :

Create a connection to the bus, then build a proxy using the name, path and interface name that you used in dbus-send. Then use the code example I gave you to extract the Title.

https://developer.gnome.org/gio/stable/