mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
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.
This commit is contained in:
parent
8977abdc84
commit
f9b2d6500b
4 changed files with 167 additions and 149 deletions
|
|
@ -144,11 +144,10 @@ pa_cvolume_set_fade;
|
||||||
pa_cvolume_set_position;
|
pa_cvolume_set_position;
|
||||||
pa_cvolume_snprint;
|
pa_cvolume_snprint;
|
||||||
pa_cvolume_valid;
|
pa_cvolume_valid;
|
||||||
pa_ext_device_manager_defer_device;
|
|
||||||
pa_ext_device_manager_delete;
|
pa_ext_device_manager_delete;
|
||||||
pa_ext_device_manager_enable_role_device_priority_routing;
|
pa_ext_device_manager_enable_role_device_priority_routing;
|
||||||
pa_ext_device_manager_prefer_device;
|
|
||||||
pa_ext_device_manager_read;
|
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_device_description;
|
||||||
pa_ext_device_manager_set_subscribe_cb;
|
pa_ext_device_manager_set_subscribe_cb;
|
||||||
pa_ext_device_manager_subscribe;
|
pa_ext_device_manager_subscribe;
|
||||||
|
|
|
||||||
|
|
@ -143,8 +143,7 @@ enum {
|
||||||
SUBCOMMAND_RENAME,
|
SUBCOMMAND_RENAME,
|
||||||
SUBCOMMAND_DELETE,
|
SUBCOMMAND_DELETE,
|
||||||
SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
|
SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
|
||||||
SUBCOMMAND_PREFER_DEVICE,
|
SUBCOMMAND_REORDER,
|
||||||
SUBCOMMAND_DEFER_DEVICE,
|
|
||||||
SUBCOMMAND_SUBSCRIBE,
|
SUBCOMMAND_SUBSCRIBE,
|
||||||
SUBCOMMAND_EVENT
|
SUBCOMMAND_EVENT
|
||||||
};
|
};
|
||||||
|
|
@ -1121,115 +1120,174 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SUBCOMMAND_PREFER_DEVICE:
|
case SUBCOMMAND_REORDER: {
|
||||||
case SUBCOMMAND_DEFER_DEVICE: {
|
|
||||||
|
|
||||||
const char *role, *device;
|
const char *role;
|
||||||
struct entry *e;
|
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 ||
|
if (pa_tagstruct_gets(t, &role) < 0 ||
|
||||||
pa_tagstruct_gets(t, &device) < 0)
|
pa_tagstruct_getu32(t, &n_devices) < 0 ||
|
||||||
|
n_devices < 1)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (!role || !device || !*device)
|
if (PA_INVALID_INDEX == (role_index = get_role_index(role)))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
role_index = get_role_index(role);
|
/* Cycle through the devices given and make sure they exist */
|
||||||
if (PA_INVALID_INDEX == role_index)
|
h = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
|
||||||
goto fail;
|
first = TRUE;
|
||||||
|
idx = 0;
|
||||||
if ((e = read_entry(u, device)) && ENTRY_VERSION == e->version) {
|
for (i = 0; i < n_devices; ++i) {
|
||||||
pa_datum key, data;
|
const char *s;
|
||||||
pa_bool_t done;
|
if (pa_tagstruct_gets(t, &s) < 0) {
|
||||||
char* prefix = NULL;
|
while ((device = pa_hashmap_steal_first(h))) {
|
||||||
uint32_t priority;
|
pa_xfree(device->device);
|
||||||
pa_bool_t haschanged = FALSE;
|
pa_xfree(device);
|
||||||
|
|
||||||
if (strncmp(device, "sink:", 5) == 0)
|
|
||||||
prefix = pa_xstrdup("sink:");
|
|
||||||
else if (strncmp(device, "source:", 7) == 0)
|
|
||||||
prefix = pa_xstrdup("source:");
|
|
||||||
|
|
||||||
if (!prefix)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
priority = e->priority[role_index];
|
|
||||||
|
|
||||||
/* Now we need to load up all the other entries of this type and shuffle the priroities around */
|
|
||||||
|
|
||||||
done = !pa_database_first(u->database, &key, NULL);
|
|
||||||
|
|
||||||
while (!done && !haschanged) {
|
|
||||||
pa_datum next_key;
|
|
||||||
|
|
||||||
done = !pa_database_next(u->database, &key, &next_key, NULL);
|
|
||||||
|
|
||||||
/* Only read devices with the right prefix */
|
|
||||||
if (key.size > strlen(prefix) && strncmp(key.data, prefix, strlen(prefix)) == 0) {
|
|
||||||
char *name;
|
|
||||||
struct entry *e2;
|
|
||||||
|
|
||||||
name = pa_xstrndup(key.data, key.size);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (haschanged) {
|
|
||||||
data.data = e2;
|
|
||||||
data.size = sizeof(*e2);
|
|
||||||
|
|
||||||
if (pa_database_set(u->database, &key, &data, TRUE))
|
|
||||||
pa_log_warn("Could not save device");
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_xfree(e2);
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_xfree(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_datum_free(&key);
|
pa_hashmap_free(h, NULL, NULL);
|
||||||
key = next_key;
|
pa_log_error("Protocol error on reorder");
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now write out our actual entry */
|
/* Ensure this is a valid entry */
|
||||||
if (haschanged) {
|
if (!(e = read_entry(u, s))) {
|
||||||
if (SUBCOMMAND_PREFER_DEVICE == command)
|
while ((device = pa_hashmap_steal_first(h))) {
|
||||||
e->priority[role_index]--;
|
pa_xfree(device->device);
|
||||||
else
|
pa_xfree(device);
|
||||||
e->priority[role_index]++;
|
}
|
||||||
|
|
||||||
key.data = (char *) device;
|
pa_hashmap_free(h, NULL, NULL);
|
||||||
key.size = strlen(device);
|
pa_log_error("Client specified an unknown device in it's reorder list.");
|
||||||
|
goto fail;
|
||||||
data.data = e;
|
|
||||||
data.size = sizeof(*e);
|
|
||||||
|
|
||||||
if (pa_database_set(u->database, &key, &data, TRUE))
|
|
||||||
pa_log_warn("Could not save device");
|
|
||||||
|
|
||||||
trigger_save(u);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_xfree(e);
|
pa_xfree(e);
|
||||||
|
|
||||||
pa_xfree(prefix);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_hashmap_free(h, NULL, NULL);
|
||||||
|
pa_log_error("Attempted to reorder mixed devices (sinks and sources)");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
pa_log_warn("Could not reorder device %s, no entry in database", device);
|
/* 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);
|
||||||
|
|
||||||
|
while (!done && idx < 256) {
|
||||||
|
pa_datum next_key;
|
||||||
|
|
||||||
|
done = !pa_database_next(u->database, &key, &next_key, NULL);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_datum_free(&key);
|
||||||
|
|
||||||
|
key = next_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 *) devices[i]->device;
|
||||||
|
key.size = strlen(devices[i]->device);
|
||||||
|
|
||||||
|
data.data = e;
|
||||||
|
data.size = sizeof(*e);
|
||||||
|
|
||||||
|
if (pa_database_set(u->database, &key, &data, TRUE) == 0) {
|
||||||
|
first = FALSE;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_xfree(e);
|
||||||
|
}
|
||||||
|
pa_xfree(devices[i]->device);
|
||||||
|
pa_xfree(devices[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!first)
|
||||||
|
trigger_save(u);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,7 @@ enum {
|
||||||
SUBCOMMAND_RENAME,
|
SUBCOMMAND_RENAME,
|
||||||
SUBCOMMAND_DELETE,
|
SUBCOMMAND_DELETE,
|
||||||
SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
|
SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
|
||||||
SUBCOMMAND_PREFER_DEVICE,
|
SUBCOMMAND_REORDER,
|
||||||
SUBCOMMAND_DEFER_DEVICE,
|
|
||||||
SUBCOMMAND_SUBSCRIBE,
|
SUBCOMMAND_SUBSCRIBE,
|
||||||
SUBCOMMAND_EVENT
|
SUBCOMMAND_EVENT
|
||||||
};
|
};
|
||||||
|
|
@ -330,14 +329,14 @@ pa_operation *pa_ext_device_manager_enable_role_device_priority_routing(
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_operation *pa_ext_device_manager_prefer_device(
|
pa_operation *pa_ext_device_manager_reorder_devices_for_role(
|
||||||
pa_context *c,
|
pa_context *c,
|
||||||
const char* role,
|
const char* role,
|
||||||
const char* device,
|
const char** devices,
|
||||||
pa_context_success_cb_t cb,
|
pa_context_success_cb_t cb,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
uint32_t tag;
|
uint32_t tag, i;
|
||||||
pa_operation *o = NULL;
|
pa_operation *o = NULL;
|
||||||
pa_tagstruct *t = 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_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
|
||||||
|
|
||||||
pa_assert(role);
|
pa_assert(role);
|
||||||
pa_assert(device);
|
pa_assert(devices);
|
||||||
|
|
||||||
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
|
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
|
||||||
|
|
||||||
t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
|
t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
|
||||||
pa_tagstruct_putu32(t, PA_INVALID_INDEX);
|
pa_tagstruct_putu32(t, PA_INVALID_INDEX);
|
||||||
pa_tagstruct_puts(t, "module-device-manager");
|
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, role);
|
||||||
pa_tagstruct_puts(t, device);
|
|
||||||
|
|
||||||
pa_pstream_send_tagstruct(c->pstream, t);
|
i = 0; while (devices[i]) i++;
|
||||||
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);
|
pa_tagstruct_putu32(t, i);
|
||||||
|
|
||||||
return o;
|
i = 0;
|
||||||
}
|
while (devices[i])
|
||||||
|
pa_tagstruct_puts(t, devices[i++]);
|
||||||
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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
pa_pstream_send_tagstruct(c->pstream, t);
|
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);
|
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);
|
||||||
|
|
|
||||||
|
|
@ -97,18 +97,10 @@ pa_operation *pa_ext_device_manager_enable_role_device_priority_routing(
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
/** Prefer a given device in the priority list. \since 0.9.19 */
|
/** 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,
|
pa_context *c,
|
||||||
const char* role,
|
const char* role,
|
||||||
const char* device,
|
const char** devices,
|
||||||
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,
|
|
||||||
pa_context_success_cb_t cb,
|
pa_context_success_cb_t cb,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue