summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/map-file3
-rw-r--r--src/modules/module-device-manager.c222
-rw-r--r--src/pulse/ext-device-manager.c53
-rw-r--r--src/pulse/ext-device-manager.h12
4 files changed, 154 insertions, 136 deletions
diff --git a/src/map-file b/src/map-file
index d7b341df..3fc934c3 100644
--- a/src/map-file
+++ b/src/map-file
@@ -144,11 +144,10 @@ pa_cvolume_set_fade;
pa_cvolume_set_position;
pa_cvolume_snprint;
pa_cvolume_valid;
-pa_ext_device_manager_defer_device;
pa_ext_device_manager_delete;
pa_ext_device_manager_enable_role_device_priority_routing;
-pa_ext_device_manager_prefer_device;
pa_ext_device_manager_read;
+pa_ext_device_manager_reorder_devices_for_role;
pa_ext_device_manager_set_device_description;
pa_ext_device_manager_set_subscribe_cb;
pa_ext_device_manager_subscribe;
diff --git a/src/modules/module-device-manager.c b/src/modules/module-device-manager.c
index 89fb4609..407d76dd 100644
--- a/src/modules/module-device-manager.c
+++ b/src/modules/module-device-manager.c
@@ -143,8 +143,7 @@ enum {
SUBCOMMAND_RENAME,
SUBCOMMAND_DELETE,
SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
- SUBCOMMAND_PREFER_DEVICE,
- SUBCOMMAND_DEFER_DEVICE,
+ SUBCOMMAND_REORDER,
SUBCOMMAND_SUBSCRIBE,
SUBCOMMAND_EVENT
};
@@ -1121,115 +1120,174 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
break;
}
- case SUBCOMMAND_PREFER_DEVICE:
- case SUBCOMMAND_DEFER_DEVICE: {
+ case SUBCOMMAND_REORDER: {
- const char *role, *device;
+ const char *role;
struct entry *e;
- uint32_t role_index;
+ uint32_t role_index, n_devices;
+ pa_datum key, data;
+ pa_bool_t done, sink_mode = TRUE;
+ struct device_t { uint32_t prio; char *device; };
+ struct device_t *device;
+ struct device_t **devices;
+ uint32_t i, idx, offset;
+ pa_hashmap *h;
+ pa_bool_t first;
if (pa_tagstruct_gets(t, &role) < 0 ||
- pa_tagstruct_gets(t, &device) < 0)
- goto fail;
-
- if (!role || !device || !*device)
- goto fail;
-
- role_index = get_role_index(role);
- if (PA_INVALID_INDEX == role_index)
+ pa_tagstruct_getu32(t, &n_devices) < 0 ||
+ n_devices < 1)
goto fail;
- if ((e = read_entry(u, device)) && ENTRY_VERSION == e->version) {
- pa_datum key, data;
- pa_bool_t done;
- char* prefix = NULL;
- uint32_t priority;
- pa_bool_t haschanged = FALSE;
-
- if (strncmp(device, "sink:", 5) == 0)
- prefix = pa_xstrdup("sink:");
- else if (strncmp(device, "source:", 7) == 0)
- prefix = pa_xstrdup("source:");
+ if (PA_INVALID_INDEX == (role_index = get_role_index(role)))
+ goto fail;
+
+ /* Cycle through the devices given and make sure they exist */
+ h = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+ first = TRUE;
+ idx = 0;
+ for (i = 0; i < n_devices; ++i) {
+ const char *s;
+ if (pa_tagstruct_gets(t, &s) < 0) {
+ while ((device = pa_hashmap_steal_first(h))) {
+ pa_xfree(device->device);
+ pa_xfree(device);
+ }
- if (!prefix)
+ pa_hashmap_free(h, NULL, NULL);
+ pa_log_error("Protocol error on reorder");
goto fail;
+ }
- priority = e->priority[role_index];
+ /* Ensure this is a valid entry */
+ if (!(e = read_entry(u, s))) {
+ while ((device = pa_hashmap_steal_first(h))) {
+ pa_xfree(device->device);
+ pa_xfree(device);
+ }
- /* Now we need to load up all the other entries of this type and shuffle the priroities around */
+ pa_hashmap_free(h, NULL, NULL);
+ pa_log_error("Client specified an unknown device in it's reorder list.");
+ goto fail;
+ }
+ pa_xfree(e);
- done = !pa_database_first(u->database, &key, NULL);
+ if (first) {
+ first = FALSE;
+ sink_mode = (0 == strncmp("sink:", s, 5));
+ } else if ((sink_mode && 0 != strncmp("sink:", s, 5))
+ || (!sink_mode && 0 != strncmp("source:", s, 7)))
+ {
+ while ((device = pa_hashmap_steal_first(h))) {
+ pa_xfree(device->device);
+ pa_xfree(device);
+ }
- while (!done && !haschanged) {
- pa_datum next_key;
+ pa_hashmap_free(h, NULL, NULL);
+ pa_log_error("Attempted to reorder mixed devices (sinks and sources)");
+ goto fail;
+ }
- done = !pa_database_next(u->database, &key, &next_key, NULL);
+ /* Add the device to our hashmap. If it's alredy in it, free it now and carry on */
+ device = pa_xnew(struct device_t, 1);
+ device->device = pa_xstrdup(s);
+ if (pa_hashmap_put(h, device->device, device) == 0) {
+ device->prio = idx;
+ idx++;
+ } else {
+ pa_xfree(device->device);
+ pa_xfree(device);
+ }
+ }
- /* Only read devices with the right prefix */
- if (key.size > strlen(prefix) && strncmp(key.data, prefix, strlen(prefix)) == 0) {
- char *name;
- struct entry *e2;
+ /* Now cycle through our list and add all the devices.
+ This has the effect of addign in any in our DB,
+ not specified in the device list (and thus will be
+ tacked on at the end) */
+ offset = idx;
+ done = !pa_database_first(u->database, &key, NULL);
- name = pa_xstrndup(key.data, key.size);
+ while (!done && idx < 256) {
+ pa_datum next_key;
- if ((e2 = read_entry(u, name))) {
- if (SUBCOMMAND_PREFER_DEVICE == command) {
- /* PREFER */
- if (e2->priority[role_index] == (priority - 1)) {
- e2->priority[role_index]++;
- haschanged = TRUE;
- }
- } else {
- /* DEFER */
- if (e2->priority[role_index] == (priority + 1)) {
- e2->priority[role_index]--;
- haschanged = TRUE;
- }
- }
+ done = !pa_database_next(u->database, &key, &next_key, NULL);
- if (haschanged) {
- data.data = e2;
- data.size = sizeof(*e2);
+ device = pa_xnew(struct device_t, 1);
+ device->device = pa_xstrndup(key.data, key.size);
+ if ((sink_mode && 0 == strncmp("sink:", device->device, 5))
+ || (!sink_mode && 0 == strncmp("source:", device->device, 7))) {
+
+ /* Add the device to our hashmap. If it's alredy in it, free it now and carry on */
+ if (pa_hashmap_put(h, device->device, device) == 0
+ && (e = read_entry(u, device->device)) && ENTRY_VERSION == e->version) {
+ /* We add offset on to the existing priorirty so that when we order, the
+ existing entries are always lower priority than the new ones. */
+ device->prio = (offset + e->priority[role_index]);
+ pa_xfree(e);
+ }
+ else {
+ pa_xfree(device->device);
+ pa_xfree(device);
+ }
+ } else {
+ pa_xfree(device->device);
+ pa_xfree(device);
+ }
- if (pa_database_set(u->database, &key, &data, TRUE))
- pa_log_warn("Could not save device");
- }
+ pa_datum_free(&key);
- pa_xfree(e2);
- }
+ key = next_key;
+ }
- pa_xfree(name);
+ /* Now we put all the entries in a simple list for sorting it. */
+ n_devices = pa_hashmap_size(h);
+ devices = pa_xnew(struct device_t *, n_devices);
+ idx = 0;
+ while ((device = pa_hashmap_steal_first(h))) {
+ devices[idx++] = device;
+ }
+ pa_hashmap_free(h, NULL, NULL);
+
+ /* Simple bubble sort */
+ for (i = 0; i < n_devices; ++i) {
+ for (uint32_t j = i; j < n_devices; ++j) {
+ if (devices[i]->prio > devices[j]->prio) {
+ struct device_t *tmp;
+ tmp = devices[i];
+ devices[i] = devices[j];
+ devices[j] = tmp;
}
-
- pa_datum_free(&key);
- key = next_key;
}
+ }
- /* Now write out our actual entry */
- if (haschanged) {
- if (SUBCOMMAND_PREFER_DEVICE == command)
- e->priority[role_index]--;
- else
- e->priority[role_index]++;
+ /* Go through in order and write the new entry and cleanup our own list */
+ i = 0; idx = 1;
+ first = TRUE;
+ for (i = 0; i < n_devices; ++i) {
+ if ((e = read_entry(u, devices[i]->device)) && ENTRY_VERSION == e->version) {
+ if (e->priority[role_index] != idx) {
+ e->priority[role_index] = idx;
- key.data = (char *) device;
- key.size = strlen(device);
+ key.data = (char *) devices[i]->device;
+ key.size = strlen(devices[i]->device);
- data.data = e;
- data.size = sizeof(*e);
+ data.data = e;
+ data.size = sizeof(*e);
- if (pa_database_set(u->database, &key, &data, TRUE))
- pa_log_warn("Could not save device");
+ if (pa_database_set(u->database, &key, &data, TRUE) == 0) {
+ first = FALSE;
+ idx++;
+ }
+ }
- trigger_save(u);
+ pa_xfree(e);
}
-
- pa_xfree(e);
-
- pa_xfree(prefix);
+ pa_xfree(devices[i]->device);
+ pa_xfree(devices[i]);
}
- else
- pa_log_warn("Could not reorder device %s, no entry in database", device);
+
+ if (!first)
+ trigger_save(u);
break;
}
diff --git a/src/pulse/ext-device-manager.c b/src/pulse/ext-device-manager.c
index 01e4594b..138ed838 100644
--- a/src/pulse/ext-device-manager.c
+++ b/src/pulse/ext-device-manager.c
@@ -43,8 +43,7 @@ enum {
SUBCOMMAND_RENAME,
SUBCOMMAND_DELETE,
SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
- SUBCOMMAND_PREFER_DEVICE,
- SUBCOMMAND_DEFER_DEVICE,
+ SUBCOMMAND_REORDER,
SUBCOMMAND_SUBSCRIBE,
SUBCOMMAND_EVENT
};
@@ -330,14 +329,14 @@ pa_operation *pa_ext_device_manager_enable_role_device_priority_routing(
return o;
}
-pa_operation *pa_ext_device_manager_prefer_device(
+pa_operation *pa_ext_device_manager_reorder_devices_for_role(
pa_context *c,
const char* role,
- const char* device,
+ const char** devices,
pa_context_success_cb_t cb,
void *userdata) {
- uint32_t tag;
+ uint32_t tag, i;
pa_operation *o = NULL;
pa_tagstruct *t = NULL;
@@ -349,52 +348,22 @@ pa_operation *pa_ext_device_manager_prefer_device(
PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
pa_assert(role);
- pa_assert(device);
+ pa_assert(devices);
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
pa_tagstruct_putu32(t, PA_INVALID_INDEX);
pa_tagstruct_puts(t, "module-device-manager");
- pa_tagstruct_putu32(t, SUBCOMMAND_PREFER_DEVICE);
+ pa_tagstruct_putu32(t, SUBCOMMAND_REORDER);
pa_tagstruct_puts(t, role);
- pa_tagstruct_puts(t, device);
-
- pa_pstream_send_tagstruct(c->pstream, t);
- pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
-
- return o;
-}
-
-pa_operation *pa_ext_device_manager_defer_device(
- pa_context *c,
- const char* role,
- const char* device,
- pa_context_success_cb_t cb,
- void *userdata) {
-
- uint32_t tag;
- pa_operation *o = NULL;
- pa_tagstruct *t = NULL;
-
- pa_assert(c);
- pa_assert(PA_REFCNT_VALUE(c) >= 1);
-
- PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
- PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
- PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
- pa_assert(role);
- pa_assert(device);
+ i = 0; while (devices[i]) i++;
+ pa_tagstruct_putu32(t, i);
- o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
-
- t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
- pa_tagstruct_putu32(t, PA_INVALID_INDEX);
- pa_tagstruct_puts(t, "module-device-manager");
- pa_tagstruct_putu32(t, SUBCOMMAND_DEFER_DEVICE);
- pa_tagstruct_puts(t, role);
- pa_tagstruct_puts(t, device);
+ i = 0;
+ while (devices[i])
+ pa_tagstruct_puts(t, devices[i++]);
pa_pstream_send_tagstruct(c->pstream, t);
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
diff --git a/src/pulse/ext-device-manager.h b/src/pulse/ext-device-manager.h
index bd52331c..13538f0c 100644
--- a/src/pulse/ext-device-manager.h
+++ b/src/pulse/ext-device-manager.h
@@ -97,18 +97,10 @@ pa_operation *pa_ext_device_manager_enable_role_device_priority_routing(
void *userdata);
/** Prefer a given device in the priority list. \since 0.9.19 */
-pa_operation *pa_ext_device_manager_prefer_device(
+pa_operation *pa_ext_device_manager_reorder_devices_for_role(
pa_context *c,
const char* role,
- const char* device,
- pa_context_success_cb_t cb,
- void *userdata);
-
-/** Defer a given device in the priority list. \since 0.9.19 */
-pa_operation *pa_ext_device_manager_defer_device(
- pa_context *c,
- const char* role,
- const char* device,
+ const char** devices,
pa_context_success_cb_t cb,
void *userdata);