struct entry {
uint8_t version;
char description[PA_NAME_MAX];
+ pa_bool_t user_set_description;
char icon[PA_NAME_MAX];
role_indexes_t priority;
} PA_GCC_PACKED;
goto fail;
}
+ if (!memchr(e->icon, 0, sizeof(e->icon))) {
+ pa_log_warn("Database contains entry for device %s with missing NUL byte in icon", name);
+ goto fail;
+ }
+
return e;
fail:
pa_assert(b);
if (strncmp(a->description, b->description, sizeof(a->description))
+ || a->user_set_description != b->user_set_description
|| strncmp(a->icon, b->icon, sizeof(a->icon)))
return FALSE;
for (uint32_t i = 0; i < NUM_ROLES; ++i) {
entry->priority[i] = max_priority[i] + 1;
}
+ entry->user_set_description = FALSE;
}
return old;
old = load_or_initialize_entry(u, &entry, name, "sink:");
- pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
+ if (!entry.user_set_description)
+ pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
+ else if (strncmp(entry.description, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description)) != 0) {
+ /* Warning: If two modules fight over the description, this could cause an infinite loop.
+ by changing the description here, we retrigger this subscription callback. The only thing stopping us from
+ looping is the fact that the string comparison will fail on the second iteration. If another module tries to manage
+ the description, this will fail... */
+ pa_sink_set_description(sink, entry.description);
+ }
+
pa_strlcpy(entry.icon, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME)), sizeof(entry.icon));
} else if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE) {
old = load_or_initialize_entry(u, &entry, name, "source:");
- pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
+ if (!entry.user_set_description)
+ pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
+ else if (strncmp(entry.description, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description)) != 0) {
+ /* Warning: If two modules fight over the description, this could cause an infinite loop.
+ by changing the description here, we retrigger this subscription callback. The only thing stopping us from
+ looping is the fact that the string comparison will fail on the second iteration. If another module tries to manage
+ the description, this will fail... */
+ pa_source_set_description(source, entry.description);
+ }
+
pa_strlcpy(entry.icon, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_ICON_NAME)), sizeof(entry.icon));
}
pa_log_info("Storing device %s.", name);
- pa_database_set(u->database, &key, &data, TRUE);
+ if (pa_database_set(u->database, &key, &data, TRUE) == 0)
+ trigger_save(u);
+ else
+ pa_log_warn("Could not save device");;
pa_xfree(name);
-
- trigger_save(u);
}
static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
name = pa_sprintf_malloc("sink:%s", new_data->name);
if ((e = read_entry(u, name))) {
- if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
+ if (e->user_set_description && strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
pa_log_info("Restoring description for sink %s.", new_data->name);
pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
}
name = pa_sprintf_malloc("source:%s", new_data->name);
if ((e = read_entry(u, name))) {
- if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
+ if (e->user_set_description && strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
/* NB, We cannot detect if we are a monitor here... this could mess things up a bit... */
pa_log_info("Restoring description for source %s.", new_data->name);
pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
pa_assert(name);
pa_assert(e);
+ if (!e->user_set_description)
+ return;
+
if ((n = get_name(name, "sink:"))) {
for (sink = pa_idxset_first(u->core->sinks, &idx); sink; sink = pa_idxset_next(u->core->sinks, &idx)) {
if (!pa_streq(sink->name, n)) {
continue;
}
- pa_log_info("Setting description for sink %s.", sink->name);
+ pa_log_info("Setting description for sink %s to '%s'", sink->name, e->description);
pa_sink_set_description(sink, e->description);
}
pa_xfree(n);
continue;
}
- pa_log_info("Setting description for source %s.", source->name);
+ pa_log_info("Setting description for source %s to '%s'", source->name, e->description);
pa_source_set_description(source, e->description);
}
pa_xfree(n);
pa_datum key, data;
pa_strlcpy(e->description, description, sizeof(e->description));
+ e->user_set_description = TRUE;
key.data = (char *) device;
key.size = strlen(device);