sink-input, source-output: rework property setting

pa_sink_input_update_proplist() is inconvenient in many cases, because
it requires allocating a new proplist, even if the goal is to just set
one property. pa_sink_input_update_properties also can't properly log
property changes, because it has to assume that all values are
arbitrary binary data.

This patch adds pa_sink_input_set_property() for setting a string
value for a single property, and pa_sink_input_set_property_arbitrary()
for setting a binary value for a single property.
pa_sink_input_update_properties() is reimplemented as a wrapper around
pa_sink_input_set_property_arbitrary() to centralize logging and
sending change notifications.

(The above mentions only sink input functions for brevity, but the
same changes are implemented for source outputs too.)
This commit is contained in:
Tanu Kaskinen 2016-03-11 12:02:22 +02:00
parent 085cced42c
commit 3e7e901ba0
4 changed files with 232 additions and 14 deletions

View file

@ -1078,17 +1078,124 @@ void pa_source_output_set_mute(pa_source_output *o, bool mute, bool save) {
pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MUTE_CHANGED], o);
}
/* Called from main thread */
void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode, pa_proplist *p) {
pa_source_output_assert_ref(o);
pa_assert_ctl_context();
void pa_source_output_set_property(pa_source_output *o, const char *key, const char *value) {
char *old_value = NULL;
const char *new_value;
if (p)
pa_proplist_update(o->proplist, mode, p);
pa_assert(o);
pa_assert(key);
if (pa_proplist_contains(o->proplist, key)) {
old_value = pa_xstrdup(pa_proplist_gets(o->proplist, key));
if (old_value) {
if (pa_streq(value, old_value))
goto finish;
} else
old_value = pa_xstrdup("(data)");
} else {
if (!value)
goto finish;
old_value = pa_xstrdup("(unset)");
}
if (value) {
pa_proplist_sets(o->proplist, key, value);
new_value = value;
} else {
pa_proplist_unset(o->proplist, key);
new_value = "(unset)";
}
if (PA_SINK_INPUT_IS_LINKED(o->state)) {
pa_log_debug("Source output %u: proplist[%s]: %s -> %s", o->index, key, old_value, new_value);
pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o);
pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT | PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
}
finish:
pa_xfree(old_value);
}
void pa_source_output_set_property_arbitrary(pa_source_output *o, const char *key, const uint8_t *value, size_t nbytes) {
const uint8_t *old_value;
size_t old_nbytes;
const char *old_value_str;
const char *new_value_str;
pa_assert(o);
pa_assert(key);
if (pa_proplist_get(o->proplist, key, (const void **) &old_value, &old_nbytes) >= 0) {
if (value && nbytes == old_nbytes && !memcmp(value, old_value, nbytes))
return;
old_value_str = "(data)";
} else {
if (!value)
return;
old_value_str = "(unset)";
}
if (value) {
pa_proplist_set(o->proplist, key, value, nbytes);
new_value_str = "(data)";
} else {
pa_proplist_unset(o->proplist, key);
new_value_str = "(unset)";
}
if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) {
pa_log_debug("Source output %u: proplist[%s]: %s -> %s", o->index, key, old_value_str, new_value_str);
pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o);
pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT | PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
}
}
/* Called from main thread */
void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode, pa_proplist *p) {
void *state;
const char *key;
const uint8_t *value;
size_t nbytes;
pa_source_output_assert_ref(o);
pa_assert(p);
pa_assert_ctl_context();
switch (mode) {
case PA_UPDATE_SET: {
/* Delete everything that is not in p. */
for (state = NULL; (key = pa_proplist_iterate(o->proplist, &state));) {
if (!pa_proplist_contains(p, key))
pa_source_output_set_property(o, key, NULL);
}
/* Fall through. */
}
case PA_UPDATE_REPLACE: {
for (state = NULL; (key = pa_proplist_iterate(p, &state));) {
pa_proplist_get(p, key, (const void **) &value, &nbytes);
pa_source_output_set_property_arbitrary(o, key, value, nbytes);
}
break;
}
case PA_UPDATE_MERGE: {
for (state = NULL; (key = pa_proplist_iterate(p, &state));) {
if (pa_proplist_contains(o->proplist, key))
continue;
pa_proplist_get(p, key, (const void **) &value, &nbytes);
pa_source_output_set_property_arbitrary(o, key, value, nbytes);
}
break;
}
}
}