Unable to Parse Dictionary Response in sd_bus_message_read() After Successful String Retrieval

31 Views Asked by At

I'm trying to retrieve track details from a connected Bluetooth device using the org.bluez.MediaPlayer1 interface in the object "/org/bluez/hci0/dev_3C_19_5E_F9_26_60/player0" of org.bluez.

Firstly, I successfully retrieved the status of the currently playing track using the property "Status". Below is the working code snippet:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <systemd/sd-bus.h>

int main(int argc, char *argv[]) {
    sd_bus_error error = SD_BUS_ERROR_NULL;
    sd_bus_message *m = NULL;
    sd_bus *bus = NULL;
    int r;
    const char *path = NULL;

    /* Connect to the system bus */
    r = sd_bus_open_system(&bus);
    if (r < 0) {
        fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));
        goto finish;
    }
    printf("Connected to system bus\n");

    /* Get the property value */
    r = sd_bus_get_property(bus,
                            "org.bluez",        /* service to contact */
                            "/org/bluez/hci0/dev_3C_19_5E_F9_26_60/player0",  /* object path */
                            "org.bluez.MediaPlayer1",/* interface name */
                            "Status",          /* property name */
                            &error,             /* object to return error in */
                            &m,                 /* return message on success */
                            "s"                 /* type */
                           );
    if (r < 0) {
        fprintf(stderr, "Failed to get property: %s\n", error.message);
        goto finish;
    }
    printf("Successfully got property\n");

    /* Parse the response message */
    r = sd_bus_message_read(m, "s", &path);
    if (r < 0) {
        fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));
        goto finish;
    }
    printf("Successfully parsed response message\n");

    if (path != NULL)
        printf("Track status is: %s\n", path);
    else
        printf("Track status not found\n");

finish:
    sd_bus_error_free(&error);
    sd_bus_message_unref(m);
    sd_bus_unref(bus);

    return 0;
}

Then, I extended the code to retrieve properties like track name, duration, artist name, etc., using the property name "Track". Here's the relevant code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <systemd/sd-bus.h>

int main(int argc, char *argv[]) {
    sd_bus_error error = SD_BUS_ERROR_NULL;
    sd_bus_message *m = NULL;
    sd_bus *bus = NULL;
    int r;
    const char *title = NULL;
    uint32_t track_number = 0;
    uint32_t num_tracks = 0;
    uint32_t duration = 0;
    const char *album = NULL;
    const char *artist = NULL;
    const char *genre = NULL;

    /* Connect to the system bus */
    r = sd_bus_open_system(&bus);
    if (r < 0) {
        fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));
        goto finish;
    }
    printf("Connected to system bus\n");

    /* Get the property value */
    r = sd_bus_get_property(bus,
                            "org.bluez",        /* service to contact */
                            "/org/bluez/hci0/dev_3C_19_5E_F9_26_60/player0",  /* object path */
                            "org.bluez.MediaPlayer1",/* interface name */
                            "Track",          /* property name */
                            &error,             /* object to return error in */
                            &m,                 /* return message on success */
                            "a{sv}"             /* type */
                           );
    if (r < 0) {
        fprintf(stderr, "Failed to get property: %s\n", error.message);
        goto finish;
    }
    printf("Successfully got property\n");

    /* Parse the response message */
    const char *s1, *s2, *s3, *s4, *s5, *s6, *s7;

    r = sd_bus_message_read(m, "a{sv}", 7, &s1, &title, &s2, &track_number, &s3, &num_tracks, &s4, &duration, &s5, &album, &s6, &artist, &s7, &genre);
    if (r < 0) {
        fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));
        goto finish;
    }
    printf("Successfully parsed response message\n");

    printf("Title: %s\n", title);
    printf("Track Number: %u\n", track_number);
    printf("Number of Tracks: %u\n", num_tracks);
    printf("Duration: %u milliseconds\n", duration);
    printf("Album: %s\n", album);
    printf("Artist: %s\n", artist);
    printf("Genre: %s\n", genre);

finish:
    sd_bus_error_free(&error);
    sd_bus_message_unref(m);
    sd_bus_unref(bus);

    return 0;
}

According to the output from the busctl command,

busctl get-property org.bluez /org/bluez/hci0/dev_3C_19_5E_F9_26_60/player0 org.bluez.MediaPlayer1 Track

the dictionary response contains 7 pairs of type {variant=>string}. Here's the output from command line:

a{sv} 7 "Title" s "Tere Naina" "TrackNumber" u 1 "NumberOfTracks" u 1 "Duration" u 278546 "Album" s "My Name Is Khan (Original Motion Picture Soundtrack)" "Artist" s "From Smart Shuffle \342\200\242 Shankar-Ehsaan-Loy, Shafqat Amanat Ali" "Genre" s ""

I referred to the documentation on sd_bus_message_read() and the example provided there, but couldn't find a solution. What am I doing wrong here? Any assistance would be greatly appreciated.

0

There are 0 best solutions below