summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTanu Kaskinen <tanuk@iki.fi>2016-03-11 12:02:22 +0200
committerTanu Kaskinen <tanuk@iki.fi>2016-04-25 13:50:47 +0300
commit3e7e901ba0a8e368b3ac99febebdd3918495e3c6 (patch)
tree044e180333a247ac9c480a8a1b3d8764145378d3
parent085cced42ce0901a2f677fc2f630801b0f4edf80 (diff)
downloadpulseaudio-3e7e901ba0a8e368b3ac99febebdd3918495e3c6.tar.gz
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.)
-rw-r--r--src/pulsecore/sink-input.c117
-rw-r--r--src/pulsecore/sink-input.h2
-rw-r--r--src/pulsecore/source-output.c117
-rw-r--r--src/pulsecore/source-output.h2
4 files changed, 228 insertions, 10 deletions
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 843297f6c..42d0b32f5 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -1426,17 +1426,124 @@ void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save) {
pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MUTE_CHANGED], i);
}
+void pa_sink_input_set_property(pa_sink_input *i, const char *key, const char *value) {
+ char *old_value = NULL;
+ const char *new_value;
+
+ pa_assert(i);
+ pa_assert(key);
+
+ if (pa_proplist_contains(i->proplist, key)) {
+ old_value = pa_xstrdup(pa_proplist_gets(i->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(i->proplist, key, value);
+ new_value = value;
+ } else {
+ pa_proplist_unset(i->proplist, key);
+ new_value = "(unset)";
+ }
+
+ if (PA_SINK_INPUT_IS_LINKED(i->state)) {
+ pa_log_debug("Sink input %u: proplist[%s]: %s -> %s", i->index, key, old_value, new_value);
+ pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], i);
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT | PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ }
+
+finish:
+ pa_xfree(old_value);
+}
+
+void pa_sink_input_set_property_arbitrary(pa_sink_input *i, 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(i);
+ pa_assert(key);
+
+ if (pa_proplist_get(i->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(i->proplist, key, value, nbytes);
+ new_value_str = "(data)";
+ } else {
+ pa_proplist_unset(i->proplist, key);
+ new_value_str = "(unset)";
+ }
+
+ if (PA_SINK_INPUT_IS_LINKED(i->state)) {
+ pa_log_debug("Sink input %u: proplist[%s]: %s -> %s", i->index, key, old_value_str, new_value_str);
+ pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], i);
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT | PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ }
+}
+
/* Called from main thread */
void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p) {
+ void *state;
+ const char *key;
+ const uint8_t *value;
+ size_t nbytes;
+
pa_sink_input_assert_ref(i);
+ pa_assert(p);
pa_assert_ctl_context();
- if (p)
- pa_proplist_update(i->proplist, mode, p);
+ switch (mode) {
+ case PA_UPDATE_SET: {
+ /* Delete everything that is not in p. */
+ for (state = NULL; (key = pa_proplist_iterate(i->proplist, &state));) {
+ if (!pa_proplist_contains(p, key))
+ pa_sink_input_set_property(i, key, NULL);
+ }
- if (PA_SINK_INPUT_IS_LINKED(i->state)) {
- pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], i);
- pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ /* 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_sink_input_set_property_arbitrary(i, key, value, nbytes);
+ }
+
+ break;
+ }
+
+ case PA_UPDATE_MERGE: {
+ for (state = NULL; (key = pa_proplist_iterate(p, &state));) {
+ if (pa_proplist_contains(i->proplist, key))
+ continue;
+
+ pa_proplist_get(p, key, (const void **) &value, &nbytes);
+ pa_sink_input_set_property_arbitrary(i, key, value, nbytes);
+ }
+
+ break;
+ }
}
}
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 86deab278..3485d6e03 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -373,6 +373,8 @@ pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, bool
void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save);
+void pa_sink_input_set_property(pa_sink_input *i, const char *key, const char *value);
+void pa_sink_input_set_property_arbitrary(pa_sink_input *i, const char *key, const uint8_t *value, size_t nbytes);
void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p);
pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i);
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 6d54ae826..f3910c58d 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -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);
}
+void pa_source_output_set_property(pa_source_output *o, const char *key, const char *value) {
+ char *old_value = NULL;
+ const char *new_value;
+
+ 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);
+ }
+}
+
/* 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();
- if (p)
- pa_proplist_update(o->proplist, mode, p);
+ 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);
+ }
- if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) {
- 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);
+ /* 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;
+ }
}
}
diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
index 26be4846c..b804092ba 100644
--- a/src/pulsecore/source-output.h
+++ b/src/pulsecore/source-output.h
@@ -316,6 +316,8 @@ pa_cvolume *pa_source_output_get_volume(pa_source_output *o, pa_cvolume *volume,
void pa_source_output_set_mute(pa_source_output *o, bool mute, bool save);
+void pa_source_output_set_property(pa_source_output *o, const char *key, const char *value);
+void pa_source_output_set_property_arbitrary(pa_source_output *o, const char *key, const uint8_t *value, size_t nbytes);
void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode, pa_proplist *p);
pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o);