mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-02 09:01:46 -05:00
device-manager: Provide a method for prefering/defering a device.
This allows clients to edit the priroity order. What is not yet in place is the initialisation of that priority list when new devices are detected or the cleaning (remove holes) when devices are removed. In order to keep the storage transparent I will likely remove the write functionality and replace it with a simple rename method. I also still need to expose the priority itself when reading the data.
This commit is contained in:
parent
a9bd1ab69c
commit
4981268738
3 changed files with 238 additions and 0 deletions
|
|
@ -87,9 +87,23 @@ struct userdata {
|
|||
|
||||
#define ENTRY_VERSION 1
|
||||
|
||||
#define NUM_ROLES 9
|
||||
enum {
|
||||
ROLE_NONE,
|
||||
ROLE_VIDEO,
|
||||
ROLE_MUSIC,
|
||||
ROLE_GAME,
|
||||
ROLE_EVENT,
|
||||
ROLE_PHONE,
|
||||
ROLE_ANIMATION,
|
||||
ROLE_PRODUCTION,
|
||||
ROLE_A11Y,
|
||||
};
|
||||
|
||||
struct entry {
|
||||
uint8_t version;
|
||||
char description[PA_NAME_MAX];
|
||||
uint32_t priority[NUM_ROLES];
|
||||
} PA_GCC_PACKED;
|
||||
|
||||
enum {
|
||||
|
|
@ -98,6 +112,8 @@ enum {
|
|||
SUBCOMMAND_WRITE,
|
||||
SUBCOMMAND_DELETE,
|
||||
SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
|
||||
SUBCOMMAND_PREFER_DEVICE,
|
||||
SUBCOMMAND_DEFER_DEVICE,
|
||||
SUBCOMMAND_SUBSCRIBE,
|
||||
SUBCOMMAND_EVENT
|
||||
};
|
||||
|
|
@ -346,6 +362,31 @@ static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static uint32_t get_role_index(const char* role) {
|
||||
pa_assert(role);
|
||||
|
||||
if (strcmp(role, "") == 0)
|
||||
return ROLE_NONE;
|
||||
if (strcmp(role, "video") == 0)
|
||||
return ROLE_VIDEO;
|
||||
if (strcmp(role, "music") == 0)
|
||||
return ROLE_MUSIC;
|
||||
if (strcmp(role, "game") == 0)
|
||||
return ROLE_GAME;
|
||||
if (strcmp(role, "event") == 0)
|
||||
return ROLE_EVENT;
|
||||
if (strcmp(role, "phone") == 0)
|
||||
return ROLE_PHONE;
|
||||
if (strcmp(role, "animation") == 0)
|
||||
return ROLE_ANIMATION;
|
||||
if (strcmp(role, "production") == 0)
|
||||
return ROLE_PRODUCTION;
|
||||
if (strcmp(role, "a11y") == 0)
|
||||
return ROLE_A11Y;
|
||||
return PA_INVALID_INDEX;
|
||||
}
|
||||
|
||||
#define EXT_VERSION 1
|
||||
|
||||
static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
|
||||
|
|
@ -526,6 +567,113 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
|
|||
break;
|
||||
}
|
||||
|
||||
case SUBCOMMAND_PREFER_DEVICE:
|
||||
case SUBCOMMAND_DEFER_DEVICE: {
|
||||
|
||||
const char *role, *device;
|
||||
struct entry *e;
|
||||
uint32_t role_index;
|
||||
|
||||
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)
|
||||
goto fail;
|
||||
|
||||
if ((e = read_entry(u, device)) && ENTRY_VERSION == e->version) {
|
||||
pa_datum key;
|
||||
pa_datum data;
|
||||
pa_bool_t done;
|
||||
char* prefix;
|
||||
uint32_t priority;
|
||||
pa_bool_t haschanged = FALSE;
|
||||
|
||||
if (strncmp(device, "sink:", 5) == 0)
|
||||
prefix = pa_xstrdup("sink:");
|
||||
else
|
||||
prefix = pa_xstrdup("source:");
|
||||
|
||||
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);
|
||||
pa_datum_free(&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;
|
||||
}
|
||||
}
|
||||
|
||||
if (haschanged) {
|
||||
data.data = e2;
|
||||
data.size = sizeof(*e2);
|
||||
|
||||
if (pa_database_set(u->database, &key, &data, FALSE))
|
||||
pa_log_warn("Could not save device");
|
||||
}
|
||||
pa_xfree(e2);
|
||||
}
|
||||
|
||||
pa_xfree(name);
|
||||
}
|
||||
|
||||
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]++;
|
||||
|
||||
key.data = (char *) device;
|
||||
key.size = strlen(device);
|
||||
|
||||
data.data = e;
|
||||
data.size = sizeof(*e);
|
||||
|
||||
if (pa_database_set(u->database, &key, &data, FALSE))
|
||||
pa_log_warn("Could not save device");
|
||||
|
||||
trigger_save(u);
|
||||
}
|
||||
|
||||
pa_xfree(e);
|
||||
|
||||
pa_xfree(prefix);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SUBCOMMAND_SUBSCRIBE: {
|
||||
|
||||
pa_bool_t enabled;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ enum {
|
|||
SUBCOMMAND_WRITE,
|
||||
SUBCOMMAND_DELETE,
|
||||
SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
|
||||
SUBCOMMAND_PREFER_DEVICE,
|
||||
SUBCOMMAND_DEFER_DEVICE,
|
||||
SUBCOMMAND_SUBSCRIBE,
|
||||
SUBCOMMAND_EVENT
|
||||
};
|
||||
|
|
@ -321,6 +323,78 @@ pa_operation *pa_ext_device_manager_enable_role_device_priority_routing(
|
|||
return o;
|
||||
}
|
||||
|
||||
pa_operation *pa_ext_device_manager_prefer_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_PREFER_DEVICE);
|
||||
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);
|
||||
|
||||
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_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_subscribe(
|
||||
pa_context *c,
|
||||
int enable,
|
||||
|
|
|
|||
|
|
@ -89,6 +89,22 @@ pa_operation *pa_ext_device_manager_enable_role_device_priority_routing(
|
|||
pa_context_success_cb_t cb,
|
||||
void *userdata);
|
||||
|
||||
/** Subscribe to changes in the device database. \since 0.9.19 */
|
||||
pa_operation *pa_ext_device_manager_prefer_device(
|
||||
pa_context *c,
|
||||
const char* role,
|
||||
const char* device,
|
||||
pa_context_success_cb_t cb,
|
||||
void *userdata);
|
||||
|
||||
/** Subscribe to changes in the device database. \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,
|
||||
void *userdata);
|
||||
|
||||
/** Subscribe to changes in the device database. \since 0.9.19 */
|
||||
pa_operation *pa_ext_device_manager_subscribe(
|
||||
pa_context *c,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue