diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/map-file | 3 | ||||
-rw-r--r-- | src/modules/module-device-manager.c | 222 | ||||
-rw-r--r-- | src/pulse/ext-device-manager.c | 53 | ||||
-rw-r--r-- | src/pulse/ext-device-manager.h | 12 |
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); |