summaryrefslogtreecommitdiffstats
path: root/src/modules/module-device-manager.c
diff options
context:
space:
mode:
authorColin Guthrie <cguthrie@mandriva.org>2009-10-01 01:27:02 +0100
committerColin Guthrie <cguthrie@mandriva.org>2009-11-11 17:44:26 +0000
commit8a5778dcc59cecc8dbd0e3ac4fa2fe951d87de10 (patch)
tree720a977175535b2d82e5c96467fc936aba2e641d /src/modules/module-device-manager.c
parent45a4d26aca37abd917c784ec8a40d26acc02246f (diff)
device-manager: Change the prefer/defer options to a single 'reorder' command.
We put in the devices from the wire into a hashmap and then add all like type device in the database and then order them based on priority (with the ones specified on the wire always being in that order at the top of the list.
Diffstat (limited to 'src/modules/module-device-manager.c')
-rw-r--r--src/modules/module-device-manager.c222
1 files changed, 140 insertions, 82 deletions
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;
}