acp: sync with pulseaudio

This commit is contained in:
Wim Taymans 2022-07-07 12:23:28 +02:00
parent 752afa06a2
commit 57f0fdf746
7 changed files with 680 additions and 552 deletions

View file

@ -469,7 +469,7 @@ static void add_profiles(pa_card *impl)
pa_dynarray_append(&impl->out.devices, dev); pa_dynarray_append(&impl->out.devices, dev);
} }
if (impl->use_ucm) { if (impl->use_ucm) {
pa_alsa_ucm_add_ports_combination(NULL, &m->ucm_context, pa_alsa_ucm_add_port(NULL, &m->ucm_context,
true, impl->ports, ap, NULL); true, impl->ports, ap, NULL);
pa_alsa_ucm_add_ports(&dev->ports, m->proplist, &m->ucm_context, pa_alsa_ucm_add_ports(&dev->ports, m->proplist, &m->ucm_context,
true, impl, dev->pcm_handle, impl->profile_set->ignore_dB); true, impl, dev->pcm_handle, impl->profile_set->ignore_dB);
@ -491,7 +491,7 @@ static void add_profiles(pa_card *impl)
} }
if (impl->use_ucm) { if (impl->use_ucm) {
pa_alsa_ucm_add_ports_combination(NULL, &m->ucm_context, pa_alsa_ucm_add_port(NULL, &m->ucm_context,
false, impl->ports, ap, NULL); false, impl->ports, ap, NULL);
pa_alsa_ucm_add_ports(&dev->ports, m->proplist, &m->ucm_context, pa_alsa_ucm_add_ports(&dev->ports, m->proplist, &m->ucm_context,
false, impl, dev->pcm_handle, impl->profile_set->ignore_dB); false, impl, dev->pcm_handle, impl->profile_set->ignore_dB);
@ -1231,8 +1231,7 @@ static int setup_mixer(pa_card *impl, pa_alsa_device *dev, bool ignore_dB)
* will be NULL, but the UCM device enable sequence will still need to be * will be NULL, but the UCM device enable sequence will still need to be
* executed. */ * executed. */
if (dev->active_port && dev->ucm_context) { if (dev->active_port && dev->ucm_context) {
if ((res = pa_alsa_ucm_set_port(dev->ucm_context, dev->active_port, if ((res = pa_alsa_ucm_set_port(dev->ucm_context, dev->active_port)) < 0)
dev->direction == PA_ALSA_DIRECTION_OUTPUT)) < 0)
return res; return res;
} }
@ -1408,8 +1407,7 @@ int acp_card_set_profile(struct acp_card *card, uint32_t new_index, uint32_t fla
/* if UCM is available for this card then update the verb */ /* if UCM is available for this card then update the verb */
if (impl->use_ucm) { if (impl->use_ucm) {
if ((res = pa_alsa_ucm_set_profile(&impl->ucm, impl, if ((res = pa_alsa_ucm_set_profile(&impl->ucm, impl,
np->profile.flags & ACP_PROFILE_OFF ? NULL : np->profile.name, np->profile.flags & ACP_PROFILE_OFF ? NULL : np, op)) < 0) {
op ? op->profile.name : NULL)) < 0) {
return res; return res;
} }
} }
@ -1418,7 +1416,7 @@ int acp_card_set_profile(struct acp_card *card, uint32_t new_index, uint32_t fla
PA_IDXSET_FOREACH(am, np->output_mappings, idx) { PA_IDXSET_FOREACH(am, np->output_mappings, idx) {
if (impl->use_ucm) if (impl->use_ucm)
/* Update ports priorities */ /* Update ports priorities */
pa_alsa_ucm_add_ports_combination(am->output.ports, &am->ucm_context, pa_alsa_ucm_add_port(am->output.ports, &am->ucm_context,
true, impl->ports, np, NULL); true, impl->ports, np, NULL);
device_enable(impl, am, &am->output); device_enable(impl, am, &am->output);
} }
@ -1428,7 +1426,7 @@ int acp_card_set_profile(struct acp_card *card, uint32_t new_index, uint32_t fla
PA_IDXSET_FOREACH(am, np->input_mappings, idx) { PA_IDXSET_FOREACH(am, np->input_mappings, idx) {
if (impl->use_ucm) if (impl->use_ucm)
/* Update ports priorities */ /* Update ports priorities */
pa_alsa_ucm_add_ports_combination(am->input.ports, &am->ucm_context, pa_alsa_ucm_add_port(am->input.ports, &am->ucm_context,
false, impl->ports, np, NULL); false, impl->ports, np, NULL);
device_enable(impl, am, &am->input); device_enable(impl, am, &am->input);
} }
@ -1810,8 +1808,7 @@ int acp_device_set_port(struct acp_device *dev, uint32_t port_index, uint32_t fl
mixer_volume_init(impl, d); mixer_volume_init(impl, d);
sync_mixer(d, p); sync_mixer(d, p);
res = pa_alsa_ucm_set_port(d->ucm_context, p, res = pa_alsa_ucm_set_port(d->ucm_context, p);
dev->direction == ACP_DIRECTION_PLAYBACK);
} else { } else {
pa_alsa_port_data *data; pa_alsa_port_data *data;

View file

@ -381,6 +381,9 @@ struct pa_alsa_profile {
pa_idxset *input_mappings; pa_idxset *input_mappings;
pa_idxset *output_mappings; pa_idxset *output_mappings;
/* ucm device context */
pa_alsa_ucm_profile_context ucm_context;
struct { struct {
pa_dynarray devices; pa_dynarray devices;
} out; } out;

File diff suppressed because it is too large Load diff

View file

@ -142,12 +142,13 @@ typedef struct pa_alsa_ucm_modifier pa_alsa_ucm_modifier;
typedef struct pa_alsa_ucm_device pa_alsa_ucm_device; typedef struct pa_alsa_ucm_device pa_alsa_ucm_device;
typedef struct pa_alsa_ucm_config pa_alsa_ucm_config; typedef struct pa_alsa_ucm_config pa_alsa_ucm_config;
typedef struct pa_alsa_ucm_mapping_context pa_alsa_ucm_mapping_context; typedef struct pa_alsa_ucm_mapping_context pa_alsa_ucm_mapping_context;
typedef struct pa_alsa_ucm_profile_context pa_alsa_ucm_profile_context;
typedef struct pa_alsa_ucm_port_data pa_alsa_ucm_port_data; typedef struct pa_alsa_ucm_port_data pa_alsa_ucm_port_data;
typedef struct pa_alsa_ucm_volume pa_alsa_ucm_volume; typedef struct pa_alsa_ucm_volume pa_alsa_ucm_volume;
int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index); int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index);
pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map); pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map);
int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, const char *new_profile, const char *old_profile); int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_profile *new_profile, pa_alsa_profile *old_profile);
int pa_alsa_ucm_get_verb(snd_use_case_mgr_t *uc_mgr, const char *verb_name, const char *verb_desc, pa_alsa_ucm_verb **p_verb); int pa_alsa_ucm_get_verb(snd_use_case_mgr_t *uc_mgr, const char *verb_name, const char *verb_desc, pa_alsa_ucm_verb **p_verb);
@ -159,14 +160,14 @@ void pa_alsa_ucm_add_ports(
pa_card *card, pa_card *card,
snd_pcm_t *pcm_handle, snd_pcm_t *pcm_handle,
bool ignore_dB); bool ignore_dB);
void pa_alsa_ucm_add_ports_combination( void pa_alsa_ucm_add_port(
pa_hashmap *hash, pa_hashmap *hash,
pa_alsa_ucm_mapping_context *context, pa_alsa_ucm_mapping_context *context,
bool is_sink, bool is_sink,
pa_hashmap *ports, pa_hashmap *ports,
pa_card_profile *cp, pa_card_profile *cp,
pa_core *core); pa_core *core);
int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port, bool is_sink); int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port);
void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm); void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm);
void pa_alsa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context); void pa_alsa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context);
@ -223,11 +224,8 @@ struct pa_alsa_ucm_modifier {
pa_proplist *proplist; pa_proplist *proplist;
int n_confdev; pa_idxset *conflicting_devices;
int n_suppdev; pa_idxset *supported_devices;
const char **conflicting_devices;
const char **supported_devices;
pa_direction_t action_direction; pa_direction_t action_direction;
@ -270,17 +268,19 @@ struct pa_alsa_ucm_mapping_context {
pa_alsa_ucm_config *ucm; pa_alsa_ucm_config *ucm;
pa_direction_t direction; pa_direction_t direction;
pa_idxset *ucm_devices; pa_alsa_ucm_device *ucm_device;
pa_idxset *ucm_modifiers; pa_alsa_ucm_modifier *ucm_modifier;
};
struct pa_alsa_ucm_profile_context {
pa_alsa_ucm_verb *verb;
}; };
struct pa_alsa_ucm_port_data { struct pa_alsa_ucm_port_data {
pa_alsa_ucm_config *ucm; pa_alsa_ucm_config *ucm;
pa_device_port *core_port; pa_device_port *core_port;
/* A single port will be associated with multiple devices if it represents pa_alsa_ucm_device *device;
* a combination of devices. */
pa_dynarray *devices; /* pa_alsa_ucm_device */
/* profile name -> pa_alsa_path for volume control */ /* profile name -> pa_alsa_path for volume control */
pa_hashmap *paths; pa_hashmap *paths;

View file

@ -1626,20 +1626,29 @@ static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask,
{ {
int err; int err;
const char *name = snd_hctl_elem_get_name(helem); const char *name = snd_hctl_elem_get_name(helem);
// NOTE: The remove event defined as '~0U`. /* NOTE: The remove event is defined as '~0U`. */
if (mask == SND_CTL_EVENT_MASK_REMOVE) { if (mask == SND_CTL_EVENT_MASK_REMOVE) {
// NOTE: unless remove pointer to melem from link-list at private_data of helem, hits /* NOTE: Unless we remove the pointer to melem from the linked-list at
// assersion in alsa-lib since the list is not empty. * private_data of helem, an assertion will be hit in alsa-lib since
* the list is not empty. */
snd_mixer_elem_detach(melem, helem); snd_mixer_elem_detach(melem, helem);
} else if (mask & SND_CTL_EVENT_MASK_ADD) { } else if (mask & SND_CTL_EVENT_MASK_ADD) {
snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem); snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem);
if (iface == SND_CTL_ELEM_IFACE_CARD || iface == SND_CTL_ELEM_IFACE_PCM) { if (iface == SND_CTL_ELEM_IFACE_CARD || iface == SND_CTL_ELEM_IFACE_PCM) {
snd_mixer_t *mixer = snd_mixer_class_get_mixer(class);
snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem);
const char *name = snd_hctl_elem_get_name(helem);
const int index = snd_hctl_elem_get_index(helem);
const int device = snd_hctl_elem_get_device(helem);
snd_mixer_elem_t *new_melem; snd_mixer_elem_t *new_melem;
/* Put the hctl pointer as our private data - it will be useful for callbacks */ new_melem = pa_alsa_mixer_find(mixer, iface, name, index, device);
if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, helem, NULL)) < 0) { if (!new_melem) {
pa_log_warn("snd_mixer_elem_new failed: %s", pa_alsa_strerror(err)); /* Put the hctl pointer as our private data - it will be useful for callbacks */
return 0; if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, helem, NULL)) < 0) {
pa_log_warn("snd_mixer_elem_new failed: %s", pa_alsa_strerror(err));
return 0;
}
} }
if ((err = snd_mixer_elem_attach(new_melem, helem)) < 0) { if ((err = snd_mixer_elem_attach(new_melem, helem)) < 0) {

View file

@ -52,6 +52,7 @@ typedef void (*pa_free_cb_t)(void *p);
#define PA_UNLIKELY(x) (x) #define PA_UNLIKELY(x) (x)
#define PA_PRINTF_FUNC(fmt, arg1) #define PA_PRINTF_FUNC(fmt, arg1)
#endif #endif
#define PA_UNUSED SPA_UNUSED
#define PA_MIN(a,b) \ #define PA_MIN(a,b) \
({ \ ({ \

View file

@ -115,6 +115,11 @@ static inline int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx)
return res; return res;
} }
static inline bool pa_idxset_contains(pa_idxset *s, const void *p)
{
return pa_idxset_find(s, p) != NULL;
}
static inline pa_idxset *pa_idxset_copy(pa_idxset *s, pa_copy_func_t copy_func) static inline pa_idxset *pa_idxset_copy(pa_idxset *s, pa_copy_func_t copy_func)
{ {
pa_idxset_item *item; pa_idxset_item *item;
@ -134,6 +139,35 @@ static inline bool pa_idxset_isempty(const pa_idxset *s)
return false; return false;
return true; return true;
} }
static inline bool pa_idxset_isdisjoint(pa_idxset *s, pa_idxset *t)
{
pa_idxset_item *item;
pa_array_for_each(item, &s->array)
if (item->ptr != NULL && pa_idxset_contains(t, item->ptr))
return false;
return true;
}
static inline bool pa_idxset_issubset(pa_idxset *s, pa_idxset *t)
{
pa_idxset_item *item;
pa_array_for_each(item, &s->array)
if (item->ptr != NULL && !pa_idxset_contains(t, item->ptr))
return false;
return true;
}
static inline bool pa_idxset_issuperset(pa_idxset *s, pa_idxset *t)
{
return pa_idxset_issubset(t, s);
}
static inline bool pa_idxset_equals(pa_idxset *s, pa_idxset *t)
{
return pa_idxset_issubset(s, t) && pa_idxset_issuperset(s, t);
}
static inline unsigned pa_idxset_size(pa_idxset*s) static inline unsigned pa_idxset_size(pa_idxset*s)
{ {
unsigned count = 0; unsigned count = 0;
@ -144,13 +178,13 @@ static inline unsigned pa_idxset_size(pa_idxset*s)
return count; return count;
} }
static inline void *pa_idxset_search(pa_idxset *s, uint32_t *idx) static inline pa_idxset_item *pa_idxset_search(pa_idxset *s, uint32_t *idx)
{ {
pa_idxset_item *item; pa_idxset_item *item;
for (item = pa_array_get_unchecked(&s->array, *idx, pa_idxset_item); for (item = pa_array_get_unchecked(&s->array, *idx, pa_idxset_item);
pa_array_check(&s->array, item); item++, (*idx)++) { pa_array_check(&s->array, item); item++, (*idx)++) {
if (item->ptr != NULL) if (item->ptr != NULL)
return item->ptr; return item;
} }
*idx = PA_IDXSET_INVALID; *idx = PA_IDXSET_INVALID;
return NULL; return NULL;
@ -158,19 +192,52 @@ static inline void *pa_idxset_search(pa_idxset *s, uint32_t *idx)
static inline void *pa_idxset_next(pa_idxset *s, uint32_t *idx) static inline void *pa_idxset_next(pa_idxset *s, uint32_t *idx)
{ {
pa_idxset_item *item;
(*idx)++;; (*idx)++;;
return pa_idxset_search(s, idx); item = pa_idxset_search(s, idx);
return item ? item->ptr : NULL;
} }
static inline void* pa_idxset_first(pa_idxset *s, uint32_t *idx) static inline void* pa_idxset_first(pa_idxset *s, uint32_t *idx)
{ {
uint32_t i = 0; uint32_t i = 0;
void *ptr = pa_idxset_search(s, &i); pa_idxset_item *item = pa_idxset_search(s, &i);
if (idx) if (idx)
*idx = i; *idx = i;
return item ? item->ptr : NULL;
}
static inline void* pa_idxset_steal_first(pa_idxset *s, uint32_t *idx)
{
uint32_t i = 0;
void *ptr;
pa_idxset_item *item = pa_idxset_search(s, &i);
if (idx)
*idx = i;
ptr = item ? item->ptr : NULL;
item->ptr = NULL;
return ptr; return ptr;
} }
static inline void* pa_idxset_steal_last(pa_idxset *s, uint32_t *idx)
{
pa_idxset_item *item;
uint32_t i;
for (i = pa_array_get_len(&s->array, pa_idxset_item); i > 0; i--) {
item = pa_array_get_unchecked(&s->array, i-1, pa_idxset_item);
if (item->ptr != NULL) {
void *ptr = item->ptr;
item->ptr = NULL;
if (idx)
*idx = i-1;
return ptr;
}
}
if (idx)
*idx = PA_IDXSET_INVALID;
return NULL;
}
static inline void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) static inline void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx)
{ {
pa_idxset_item *item = pa_idxset_find(s, p); pa_idxset_item *item = pa_idxset_find(s, p);