]> code.delx.au - pulseaudio/commitdiff
device-manager: Change the prefer/defer options to a single 'reorder' command.
authorColin Guthrie <cguthrie@mandriva.org>
Thu, 1 Oct 2009 00:27:02 +0000 (01:27 +0100)
committerColin Guthrie <cguthrie@mandriva.org>
Thu, 1 Oct 2009 08:08:32 +0000 (09:08 +0100)
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.

src/map-file
src/modules/module-device-manager.c
src/pulse/ext-device-manager.c
src/pulse/ext-device-manager.h

index d7b341df5bffbddba0f9a76f62153acab26118a6..3fc934c39fc3b00d7c003d3659906396e93012dd 100644 (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;
index 89fb46095f8a6604df3a360d5757e79d9e77d327..407d76dda00556791831c6f3504ca7ac7ce87eaf 100644 (file)
@@ -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;
     }
index 01e4594b6eb7adc37fd7456807fa4e235126da2c..138ed838dca9cbc151df1c2bf3df73f7a9c63f85 100644 (file)
@@ -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);
index bd52331cfa4930c826153e1c795926a31b592d92..13538f0ce38469f4b04f9c66d7b6e938841a69d7 100644 (file)
@@ -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);