mirror of
https://codeberg.org/dnkl/yambar.git
synced 2025-04-20 03:35:41 +02:00
module_mpris: Cleanup
This commit is contained in:
parent
c1ddafd34a
commit
c2ba93aa4f
1 changed files with 56 additions and 61 deletions
105
modules/mpris.c
105
modules/mpris.c
|
@ -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++) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue