module_mpris: Cleanup

This commit is contained in:
haruInDisguise 2025-03-20 11:00:17 +01:00
parent c1ddafd34a
commit c2ba93aa4f

View file

@ -83,7 +83,7 @@ struct client {
}; };
struct context { struct context {
const struct private *mpd_config; const struct private *mpris_config;
sd_bus *monitor_connection; sd_bus *monitor_connection;
sd_bus_message *update_message; sd_bus_message *update_message;
@ -116,25 +116,37 @@ struct private
} while (0) } while (0)
#endif #endif
static void static uint64_t
metadata_clear(struct metadata *metadata) timespec_diff_us(const struct timespec *a, const struct timespec *b)
{ {
tll_free_and_free(metadata->artists, free); uint64_t nsecs_a = a->tv_sec * 1000000000 + a->tv_nsec;
uint64_t nsecs_b = b->tv_sec * 1000000000 + b->tv_nsec;
if (metadata->album != NULL) { assert(nsecs_a >= nsecs_b);
free(metadata->album); uint64_t nsec_diff = nsecs_a - nsecs_b;
metadata->album = NULL; return nsec_diff / 1000;
}
static bool
verify_bus_name(const string_array *identity_list, const char *name)
{
tll_foreach(*identity_list, it)
{
const char *ident = it->item;
if (strlen(name) < strlen(MPRIS_BUS_NAME ".") + strlen(ident)) {
continue;
} }
if (metadata->title != NULL) { const char *cmp = name + strlen(MPRIS_BUS_NAME ".");
free(metadata->title); if (strncmp(cmp, ident, strlen(ident)) != 0) {
metadata->title = NULL; continue;
} }
if (metadata->trackid != NULL) { return true;
free(metadata->trackid);
metadata->trackid = NULL;
} }
return false;
} }
static void static void
@ -198,40 +210,35 @@ client_change_unique_name(struct client *client, const char *new_name)
client->bus_unique_name = strdup(new_name); client->bus_unique_name = strdup(new_name);
} }
static bool static void
verify_bus_name(const string_array *identity_list, const char *name) metadata_clear(struct metadata *metadata)
{ {
tll_foreach(*identity_list, it) tll_free_and_free(metadata->artists, free);
{
const char *ident = it->item;
if (strlen(name) < strlen(MPRIS_BUS_NAME ".") + strlen(ident)) { if (metadata->album != NULL) {
continue; free(metadata->album);
metadata->album = NULL;
} }
const char *cmp = name + strlen(MPRIS_BUS_NAME "."); if (metadata->title != NULL) {
if (strncmp(cmp, ident, strlen(ident)) != 0) { free(metadata->title);
continue; metadata->title = NULL;
} }
return true; if (metadata->trackid != NULL) {
free(metadata->trackid);
metadata->trackid = NULL;
} }
return false;
} }
static bool static bool
read_string_array(sd_bus_message *message, string_array *list) metadata_parse_array(sd_bus_message *message, string_array *list)
{ {
int status = 0; int status = 0;
/* message argument layout: 'vas' */ /* message argument layout: 'vas' */
/* enter variant */ /* enter variant */
status = sd_bus_message_enter_container(message, SD_BUS_TYPE_VARIANT, "as"); status = sd_bus_message_enter_container(message, SD_BUS_TYPE_VARIANT, "as");
if (status <= 0) {
LOG_DBG("unexpected layout: errno=%d (%s)", status, strerror(-status));
return false;
}
/* enter array */ /* enter array */
status = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "s"); status = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "s");
@ -283,7 +290,7 @@ metadata_parse_property(const char *property_name, sd_bus_message *message, stru
buffer->album = strdup(string); buffer->album = strdup(string);
} else if (strcmp(property_name, "xesam:artist") == 0) { } else if (strcmp(property_name, "xesam:artist") == 0) {
status = read_string_array(message, &buffer->artists); status = metadata_parse_array(message, &buffer->artists);
} else if (strcmp(property_name, "xesam:title") == 0) { } else if (strcmp(property_name, "xesam:title") == 0) {
status = sd_bus_message_read(message, "v", "s", &string); status = sd_bus_message_read(message, "v", "s", &string);
@ -317,7 +324,7 @@ unexpected_type:
} }
static bool static bool
metadata_parse_array(struct metadata *metadata, sd_bus_message *message) metadata_parse(struct metadata *metadata, sd_bus_message *message)
{ {
int status = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "{sv}"); int status = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "{sv}");
assert(status >= 0); assert(status >= 0);
@ -387,7 +394,7 @@ property_parse(struct property *prop, const char *property_name, sd_bus_message
} else if (strcmp(property_name, "Metadata") == 0) { } else if (strcmp(property_name, "Metadata") == 0) {
metadata_clear(&prop->metadata); metadata_clear(&prop->metadata);
status = metadata_parse_array(&prop->metadata, message); status = metadata_parse(&prop->metadata, message);
} else { } else {
LOG_DBG("property: ignoring property: %s", property_name); LOG_DBG("property: ignoring property: %s", property_name);
@ -403,17 +410,6 @@ property_parse(struct property *prop, const char *property_name, sd_bus_message
return status > 0; return status > 0;
} }
static uint64_t
timespec_diff_us(const struct timespec *a, const struct timespec *b)
{
uint64_t nsecs_a = a->tv_sec * 1000000000 + a->tv_nsec;
uint64_t nsecs_b = b->tv_sec * 1000000000 + b->tv_nsec;
assert(nsecs_a >= nsecs_b);
uint64_t nsec_diff = nsecs_a - nsecs_b;
return nsec_diff / 1000;
}
static bool static bool
update_client_from_message(struct client *client, sd_bus_message *message) update_client_from_message(struct client *client, sd_bus_message *message)
{ {
@ -505,8 +501,6 @@ update_client_from_message(struct client *client, sd_bus_message *message)
return true; return true;
} }
/* ------------- */
static void static void
context_event_handle_name_owner_changed(sd_bus_message *message, struct context *context) context_event_handle_name_owner_changed(sd_bus_message *message, struct context *context)
{ {
@ -567,7 +561,7 @@ context_event_handle_name_acquired(sd_bus_message *message, struct context *cont
return; return;
} }
if (verify_bus_name(&context->mpd_config->identity_list, name)) { if (verify_bus_name(&context->mpris_config->identity_list, name)) {
const char *unique_name = sd_bus_message_get_destination(message); const char *unique_name = sd_bus_message_get_destination(message);
LOG_DBG("'NameAcquired': Acquired new client: %s unique: %s", name, unique_name); LOG_DBG("'NameAcquired': Acquired new client: %s unique: %s", name, unique_name);
client_add(context, name, unique_name); client_add(context, name, unique_name);
@ -655,6 +649,8 @@ context_process_events(struct context *context, uint32_t timeout_ms)
return true; return true;
} }
/* Setup */
static bool static bool
find_existing_clients(struct context *context, sd_bus *connection, uint32_t timeout_ms) find_existing_clients(struct context *context, sd_bus *connection, uint32_t timeout_ms)
{ {
@ -678,7 +674,7 @@ find_existing_clients(struct context *context, sd_bus *connection, uint32_t time
status = sd_bus_message_read_basic(list_names_reply, SD_BUS_TYPE_STRING, &client_name); status = sd_bus_message_read_basic(list_names_reply, SD_BUS_TYPE_STRING, &client_name);
assert(status >= 0); assert(status >= 0);
if (!verify_bus_name(&context->mpd_config->identity_list, client_name)) if (!verify_bus_name(&context->mpris_config->identity_list, client_name))
continue; continue;
/* Request the clients unique identifier */ /* Request the clients unique identifier */
@ -716,10 +712,11 @@ find_existing_clients(struct context *context, sd_bus *connection, uint32_t time
/* Process the new clients properties */ /* Process the new clients properties */
client_add(context, client_name, client_uniq_name); client_add(context, client_name, client_uniq_name);
struct client *client = tll_back(context->clients); struct client *client = tll_back(context->clients);
LOG_INFO("Found existing client: %s", client->bus_name);
if (!update_client_from_message(client, props_reply)) { if (!update_client_from_message(client, props_reply)) {
LOG_WARN("Failed to process existing client: %s", client_name); LOG_WARN("Failed to process existing client: %s", client_name);
tll_pop_front(context->clients); tll_pop_back(context->clients);
} }
} }
@ -750,7 +747,7 @@ context_setup(struct context *context)
/* Existing clients must be processed before /* Existing clients must be processed before
* the connection is turned into a monitor, since * the connection is turned into a monitor, since
* monitor connections cannot send messages. */ * monitor connections cannot send messages. */
if (find_existing_clients(context, connection, context->mpd_config->timeout_ms)) { if (find_existing_clients(context, connection, context->mpris_config->timeout_ms)) {
context->current_client = tll_back(context->clients); context->current_client = tll_back(context->clients);
LOG_INFO("Selecting last registered client: %s", context->current_client->bus_name); LOG_INFO("Selecting last registered client: %s", context->current_client->bus_name);
} }
@ -776,11 +773,9 @@ context_setup(struct context *context)
"path='/org/mpris/MediaPlayer2'", "path='/org/mpris/MediaPlayer2'",
}; };
/* TODO: Error handling */
/* "BecomeMonitor" ('asu'): (Rules: String[], Flags: UINT32) */ /* "BecomeMonitor" ('asu'): (Rules: String[], Flags: UINT32) */
/* https://dbus.freedesktop.org/doc/dbus-specification.html#bus-messages-become-monitor */ /* https://dbus.freedesktop.org/doc/dbus-specification.html#bus-messages-become-monitor */
status = sd_bus_message_open_container(message, SD_BUS_TYPE_ARRAY, "s"); status = sd_bus_message_open_container(message, SD_BUS_TYPE_ARRAY, "s");
assert(status >= 0);
for (uint32_t i = 0; i < sizeof(matching_rules) / sizeof(matching_rules[0]); i++) { for (uint32_t i = 0; i < sizeof(matching_rules) / sizeof(matching_rules[0]); i++) {
status = sd_bus_message_append_basic(message, SD_BUS_TYPE_STRING, matching_rules[i]); status = sd_bus_message_append_basic(message, SD_BUS_TYPE_STRING, matching_rules[i]);
assert(status >= 0); assert(status >= 0);
@ -790,7 +785,7 @@ context_setup(struct context *context)
sd_bus_message *reply = NULL; sd_bus_message *reply = NULL;
sd_bus_error error = {}; sd_bus_error error = {};
status = sd_bus_call(connection, message, context->mpd_config->timeout_ms, &error, &reply); status = sd_bus_call(connection, message, context->mpris_config->timeout_ms, &error, &reply);
if (status < 0 && sd_bus_error_is_set(&error)) { if (status < 0 && sd_bus_error_is_set(&error)) {
LOG_ERR("Failed to create context: %s: %s (%d)", error.name, error.message, sd_bus_error_get_errno(&error)); LOG_ERR("Failed to create context: %s: %s (%d)", error.name, error.message, sd_bus_error_get_errno(&error));
return false; return false;
@ -1127,7 +1122,7 @@ mpris_new(const struct yml_node *ident_list, size_t timeout_ms, struct particle
struct private *priv = calloc(1, sizeof(*priv)); struct private *priv = calloc(1, sizeof(*priv));
priv->label = label; priv->label = label;
priv->timeout_ms = timeout_ms; priv->timeout_ms = timeout_ms;
priv->context.mpd_config = priv; priv->context.mpris_config = priv;
size_t i = 0; size_t i = 0;
for (struct yml_list_iter iter = yml_list_iter(ident_list); iter.node != NULL; yml_list_next(&iter), i++) { for (struct yml_list_iter iter = yml_list_iter(ident_list); iter.node != NULL; yml_list_next(&iter), i++) {