Skip to content

Commit

Permalink
Add metadata to MPRIS output -- not complete.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikebrady committed Jan 1, 2018
1 parent 0801290 commit aaee366
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 8 deletions.
20 changes: 15 additions & 5 deletions dacp.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,8 @@ void *dacp_monitor_thread_code(void *na) {
break;
case 'cang': // genre
t = sp - item_size;
if ((metadata_store.genre == NULL) || (strncmp(metadata_store.genre, t, item_size) != 0)) {
if ((metadata_store.genre == NULL) ||
(strncmp(metadata_store.genre, t, item_size) != 0)) {
if (metadata_store.genre)
free(metadata_store.genre);
metadata_store.genre = strndup(t, item_size);
Expand All @@ -469,8 +470,10 @@ void *dacp_monitor_thread_code(void *na) {
case 'canp': // nowplaying 4 ids: dbid, plid, playlistItem, itemid (from mellowware --
// see reference above)
t = sp - item_size;
if (memcmp(metadata_store.item_composite_id, t, sizeof(metadata_store.item_composite_id)) != 0) {
memcpy(metadata_store.item_composite_id, t, sizeof(metadata_store.item_composite_id));
if (memcmp(metadata_store.item_composite_id, t,
sizeof(metadata_store.item_composite_id)) != 0) {
memcpy(metadata_store.item_composite_id, t,
sizeof(metadata_store.item_composite_id));

char st[33];
char *pt = st;
Expand All @@ -485,14 +488,19 @@ void *dacp_monitor_thread_code(void *na) {
metadata_store.changed = 1;
}
break;
case 'astm':
t = sp - item_size;
r = ntohl(*(int32_t *)(t));
metadata_store.songtime_in_milliseconds = ntohl(*(uint32_t *)(t));
break;

/*
case 'mstt':
case 'cant':
case 'cast':
case 'cmmk':
case 'caas':
case 'caar':
case 'astm':
t = sp - item_size;
r = ntohl(*(int32_t *)(t));
printf(" %d", r);
Expand Down Expand Up @@ -534,7 +542,9 @@ void *dacp_monitor_thread_code(void *na) {
}
// printf("\n");
}

// now, if the metadata is changed, send a signal
run_metadata_watchers();

} else {
printf("Status Update not found.\n");
Expand Down Expand Up @@ -571,7 +581,7 @@ void *dacp_monitor_thread_code(void *na) {
response = NULL;
}
*/
sleep(2);
sleep(2);
}
debug(1, "DACP monitor thread exiting.");
pthread_exit(NULL);
Expand Down
23 changes: 22 additions & 1 deletion metadata_hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Basically, if you need to store metadata
* (e.g. for use with the dbus interfaces),
* then you need a metadata hub,
* where everything is stored
* where everything is stored
* This file is part of Shairport Sync.
* Copyright (c) Mike Brady 2017
* All rights reserved.
Expand Down Expand Up @@ -38,3 +38,24 @@ void metadata_hub_init(void) {
debug(1, "Metadata bundle initialisation.");
memset(&metadata_store, 0, sizeof(metadata_store));
}

void add_metadata_watcher(metadata_watcher fn, void *userdata) {
int i;
for (i = 0; i < number_of_watchers; i++) {
if (metadata_store.watchers[i] == NULL) {
metadata_store.watchers[i] = fn;
metadata_store.watchers_data[i] = userdata;
debug(1, "Added a metadata watcher into slot %d", i);
break;
}
}
}

void run_metadata_watchers(void) {
int i;
for (i = 0; i < number_of_watchers; i++) {
if (metadata_store.watchers[i]) {
metadata_store.watchers[i](&metadata_store, metadata_store.watchers_data[i]);
}
}
}
14 changes: 14 additions & 0 deletions metadata_hub.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "config.h"
#include <pthread.h>

#define number_of_watchers 2

enum play_status_type {
PS_PLAYING = 0,
PS_PAUSED,
Expand All @@ -20,6 +22,10 @@ enum repeat_status_type {
RS_ALL,
} repeat_status_type;

struct metadata_bundle;

typedef void (*metadata_watcher)(struct metadata_bundle *argc, void *userdata);

typedef struct metadata_bundle {
int changed; // normally 0, nonzero if a field has been changed
int playerstatusupdates_are_received; // false if it's "traditional" metadata
Expand Down Expand Up @@ -48,11 +54,19 @@ typedef struct metadata_bundle {
uint32_t item_id; // seems to be a track ID -- see itemid in DACP.c
int item_id_changed;

uint32_t songtime_in_milliseconds;

unsigned char
item_composite_id[16]; // seems to be nowplaying 4 ids: dbid, plid, playlistItem, itemid

metadata_watcher watchers[number_of_watchers]; // functions to call if the metadata is changed.
void *watchers_data[number_of_watchers]; // their individual data

} metadata_bundle;

struct metadata_bundle metadata_store;

void add_metadata_watcher(metadata_watcher fn, void *userdata);
void run_metadata_watchers(void);

void metadata_hub_init(void);
88 changes: 86 additions & 2 deletions mpris-service.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,90 @@

#include "dacp.h"

#include "metadata_hub.h"
#include "mpris-service.h"

void mpris_metadata_watcher(struct metadata_bundle *argc, void *userdata) {
debug(1, "MPRIS metadata watcher called");
char response[100];
switch (argc->repeat_status) {
case RS_NONE:
strcpy(response, "None");
break;
case RS_SINGLE:
strcpy(response, "Track");
break;
case RS_ALL:
strcpy(response, "Playlist");
break;
}

// debug(1,"Set loop status to \"%s\"",response);
media_player2_player_set_loop_status(mprisPlayerPlayerSkeleton, response);

GVariantBuilder *dict_builder, *aa;
GVariant *trackname, *albumname, *trackid, *tracklength;

// Build the Track ID from the 16-byte item_composite_id in hex prefixed by
// /org/gnome/ShairportSync

char st[33];
char *pt = st;
int it;
for (it = 0; it < 16; it++) {
sprintf(pt, "%02X", argc->item_composite_id[it]);
pt += 2;
}
*pt = 0;
debug(1, "Item composite ID set to 0x%s.", st);

char trackidstring[1024];
sprintf(trackidstring, "/org/gnome/ShairportSync/%s", st);

trackid = g_variant_new("o", trackidstring);

// Make up the track name and album name
trackname = g_variant_new("s", argc->track_name);
albumname = g_variant_new("s", argc->album_name);

// Make up the track length in microseconds as an int64

uint64_t track_length_in_microseconds = argc->songtime_in_milliseconds;

track_length_in_microseconds *= 1000; // to micorseconds in 64-bit precision

// Make up the track name and album name
tracklength = g_variant_new("x", track_length_in_microseconds);

/* Build the artists array */
// debug(1,"Build artists");
aa = g_variant_builder_new(G_VARIANT_TYPE("as"));
g_variant_builder_add(aa, "s", argc->artist_name);
GVariant *artists = g_variant_builder_end(aa);
g_variant_builder_unref(aa);

/* Build the genre array */
// debug(1,"Build genre");
aa = g_variant_builder_new(G_VARIANT_TYPE("as"));
g_variant_builder_add(aa, "s", argc->genre);
GVariant *genres = g_variant_builder_end(aa);
g_variant_builder_unref(aa);

/* Build the metadata array */
// debug(1,"Build metadata");
dict_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
g_variant_builder_add(dict_builder, "{sv}", "xesam:title", trackname);
g_variant_builder_add(dict_builder, "{sv}", "xesam:album", albumname);
g_variant_builder_add(dict_builder, "{sv}", "xesam:artist", artists);
g_variant_builder_add(dict_builder, "{sv}", "xesam:genre", genres);
g_variant_builder_add(dict_builder, "{sv}", "xesam:trackid", trackid);
g_variant_builder_add(dict_builder, "{sv}", "xesam:length", tracklength);
GVariant *dict = g_variant_builder_end(dict_builder);
g_variant_builder_unref(dict_builder);

media_player2_player_set_metadata(mprisPlayerPlayerSkeleton, dict);
}

static gboolean on_handle_next(MediaPlayer2Player *skeleton, GDBusMethodInvocation *invocation,
gpointer user_data) {
send_simple_dacp_command("nextitem");
Expand Down Expand Up @@ -77,8 +159,8 @@ static void on_mpris_name_acquired(GDBusConnection *connection, const gchar *nam
media_player2_set_supported_uri_schemes(mprisPlayerSkeleton, empty_string_array);
media_player2_set_supported_mime_types(mprisPlayerSkeleton, empty_string_array);

media_player2_player_set_playback_status(mprisPlayerPlayerSkeleton, "stop");
media_player2_player_set_loop_status(mprisPlayerPlayerSkeleton, "off");
media_player2_player_set_playback_status(mprisPlayerPlayerSkeleton, "Stopped");
media_player2_player_set_loop_status(mprisPlayerPlayerSkeleton, "None");
media_player2_player_set_volume(mprisPlayerPlayerSkeleton, 0.5);
media_player2_player_set_minimum_rate(mprisPlayerPlayerSkeleton, 1.0);
media_player2_player_set_maximum_rate(mprisPlayerPlayerSkeleton, 1.0);
Expand All @@ -98,6 +180,8 @@ static void on_mpris_name_acquired(GDBusConnection *connection, const gchar *nam
g_signal_connect(mprisPlayerPlayerSkeleton, "handle-previous", G_CALLBACK(on_handle_previous),
NULL);

add_metadata_watcher(mpris_metadata_watcher, NULL);

debug(1, "Shairport Sync D-BUS service started on interface \"%s\".", name);

debug(1, "MPRIS service started on interface \"%s\".", name);
Expand Down

0 comments on commit aaee366

Please sign in to comment.