alsa: sync with latest pulseaudio

Move some things around to make it easier to merge in changes.
This commit is contained in:
Wim Taymans 2020-08-18 12:31:03 +02:00
parent 6aa6b4eac7
commit a67af43cad
15 changed files with 539 additions and 135 deletions

View file

@ -131,6 +131,16 @@ ATTRS{idVendor}=="1038", ATTRS{idProduct}=="1252", ENV{PULSE_PROFILE_SET}="steel
ATTRS{idVendor}=="147a", ATTRS{idProduct}=="e055", ENV{PULSE_PROFILE_SET}="cmedia-high-speed-true-hdaudio.conf"
# HyperX Cloud Orbit S has three modes. Each mode has a separate product ID.
# ID_SERIAL for this device is the device name + mode repeated three times.
# ID_SERIAL is used for the ID_ID property, and the ID_ID property is used in
# the card name in PulseAudio. The resulting card name is too long for the name
# length limit, so we set a more sensible ID_ID here (the same as the default
# ID_ID, but without repetition in the serial part).
ATTRS{idVendor}=="0951", ATTRS{idProduct}=="16ff", ENV{ID_ID}="usb-HyperX_Cloud_Orbit_S_2Ch-$env{ID_USB_INTERFACE_NUM}"
ATTRS{idVendor}=="0951", ATTRS{idProduct}=="1702", ENV{ID_ID}="usb-HyperX_Cloud_Orbit_S_Hi-Res_2Ch-$env{ID_USB_INTERFACE_NUM}"
ATTRS{idVendor}=="0951", ATTRS{idProduct}=="1703", ENV{ID_ID}="usb-HyperX_Cloud_Orbit_S_3D_8Ch-$env{ID_USB_INTERFACE_NUM}"
GOTO="pulseaudio_end"
LABEL="pulseaudio_firewire_quirk"

View file

@ -51,7 +51,7 @@ static void init_device(pa_card *impl, pa_alsa_device *dev, pa_alsa_direction_t
dev->device.name = m->name;
dev->device.description = m->description;
dev->device.priority = m->priority;
dev->device.device_strings = m->device_strings;
dev->device.device_strings = (const char **)m->device_strings;
dev->device.format.format_mask = m->sample_spec.format;
dev->device.format.rate_mask = m->sample_spec.rate;
dev->device.format.channels = m->channel_map.channels;
@ -114,15 +114,18 @@ static void add_profiles(pa_card *impl)
pa_dynarray_init(&impl->out.devices, NULL);
ap = pa_xnew0(pa_alsa_profile, 1);
ap->profile.name = pa_xstrdup("off");
ap->profile.description = pa_xstrdup(_("Off"));
ap->profile.name = ap->name = pa_xstrdup("off");
ap->profile.description = ap->description = pa_xstrdup(_("Off"));
ap->profile.available = ACP_AVAILABLE_YES;
pa_hashmap_put(impl->profiles, ap->profile.name, ap);
pa_hashmap_put(impl->profiles, ap->name, ap);
PA_HASHMAP_FOREACH(ap, impl->profile_set->profiles, state) {
pa_alsa_mapping *m;
cp = &ap->profile;
cp->name = ap->name;
cp->description = ap->description;
cp->priority = ap->priority ? ap->priority : 1;
pa_dynarray_init(&ap->out.devices, NULL);
@ -164,7 +167,7 @@ static void add_profiles(pa_card *impl)
}
cp->n_devices = pa_dynarray_size(&ap->out.devices);
cp->devices = ap->out.devices.array.data;
pa_hashmap_put(impl->profiles, cp->name, cp);
pa_hashmap_put(impl->profiles, ap->name, cp);
}
pa_dynarray_init(&impl->out.ports, NULL);
@ -173,6 +176,7 @@ static void add_profiles(pa_card *impl)
void *state2;
dp->card = impl;
dp->port.index = n_ports++;
dp->port.priority = dp->priority;
pa_dynarray_init(&dp->prof, NULL);
pa_dynarray_init(&dp->devices, NULL);
n_profiles = 0;
@ -1320,7 +1324,7 @@ int acp_device_set_port(struct acp_device *dev, uint32_t port_index)
if (p == old)
return 0;
if (!pa_hashmap_get(d->ports, p->port.name))
if (!pa_hashmap_get(d->ports, p->name))
return -EINVAL;
if (old)

View file

@ -81,6 +81,9 @@ enum acp_available {
ACP_AVAILABLE_YES = 2
};
/** Port type. New types can be added in the future, so applications should
* gracefully handle situations where a type identifier doesn't match any item
* in this enumeration. */
enum acp_port_type {
ACP_PORT_TYPE_UNKNOWN = 0,
ACP_PORT_TYPE_AUX = 1,
@ -136,26 +139,47 @@ struct acp_card_events {
};
struct acp_port {
uint32_t index;
uint32_t index; /**< unique index for this port */
#define ACP_PORT_ACTIVE (1<<0)
uint32_t flags;
uint32_t flags; /**< extra port flags */
char *name;
char *description;
uint32_t priority;
const char *name; /**< Name of this port */
const char *description; /**< Description of this port */
uint32_t priority; /**< The higher this value is, the more useful this port is as a default. */
enum acp_direction direction;
enum acp_available available;
char *available_group; /* a string identifier which determine the group of devices
* handling the available state simultaneously */
enum acp_port_type type;
enum acp_available available; /**< A flags (see #acp_port_available), indicating availability status of this port. */
const char *availability_group; /**< An indentifier for the group of ports that share their availability status with
* each other. This is meant especially for handling cases where one 3.5 mm connector
* is used for headphones, headsets and microphones, and the hardware can only tell
* that something was plugged in but not what exactly. In this situation the ports for
* all those devices share their availability status, and PulseAudio can't tell which
* one is actually plugged in, and some application may ask the user what was plugged
* in. Such applications should get a list of all card ports and compare their
* `available_group` fields. Ports that have the same group are those that need
* input from the user to determine which device was plugged in. The application should
* then activate the user-chosen port.
*
* May be NULL, in which case the port is not part of any availability group (which is
* the same as having a group with only one member).
*
* The group identifier must be treated as an opaque identifier. The string may look
* like an ALSA control name, but applications must not assume any such relationship.
* The group naming scheme can change without a warning.
*
* Since one group can include both input and output ports, the grouping should be done
* using pa_card_port_info instead of pa_sink_port_info, but this field is duplicated
* also in pa_sink_port_info (and pa_source_port_info) in case someone finds that
* convenient.
*/
enum acp_port_type type; /**< Port type, see #pa_device_port_type. */
struct acp_dict props;
struct acp_dict props; /**< extra port properties */
uint32_t n_profiles;
struct acp_card_profile **profiles;
uint32_t n_profiles; /**< number of elements in profiles array */
struct acp_card_profile **profiles; /**< array of profiles for this port */
uint32_t n_devices;
struct acp_device **devices;
uint32_t n_devices; /**< number of elements in devices array */
struct acp_device **devices; /**< array of devices */
};
struct acp_device {
@ -165,13 +189,13 @@ struct acp_device {
#define ACP_DEVICE_HW_MUTE (1<<2)
uint32_t flags;
char *name;
char *description;
const char *name;
const char *description;
uint32_t priority;
enum acp_direction direction;
struct acp_dict props;
char **device_strings;
const char **device_strings;
struct acp_format format;
float base_volume;
@ -186,9 +210,8 @@ struct acp_card_profile {
#define ACP_PROFILE_ACTIVE (1<<0)
uint32_t flags;
char *name;
char *description;
char *description_key;
const char *name;
const char *description;
uint32_t priority;
enum acp_available available;
struct acp_dict props;

View file

@ -306,6 +306,327 @@ void pa_alsa_mixer_use_for_poll(pa_hashmap *mixers, snd_mixer_t *mixer_handle)
}
}
#if 0
struct pa_alsa_fdlist {
unsigned num_fds;
struct pollfd *fds;
/* This is a temporary buffer used to avoid lots of mallocs */
struct pollfd *work_fds;
snd_mixer_t *mixer;
snd_hctl_t *hctl;
pa_mainloop_api *m;
pa_defer_event *defer;
pa_io_event **ios;
bool polled;
void (*cb)(void *userdata);
void *userdata;
};
static void io_cb(pa_mainloop_api *a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
struct pa_alsa_fdlist *fdl = userdata;
int err;
unsigned i;
unsigned short revents;
pa_assert(a);
pa_assert(fdl);
pa_assert(fdl->mixer || fdl->hctl);
pa_assert(fdl->fds);
pa_assert(fdl->work_fds);
if (fdl->polled)
return;
fdl->polled = true;
memcpy(fdl->work_fds, fdl->fds, sizeof(struct pollfd) * fdl->num_fds);
for (i = 0; i < fdl->num_fds; i++) {
if (e == fdl->ios[i]) {
if (events & PA_IO_EVENT_INPUT)
fdl->work_fds[i].revents |= POLLIN;
if (events & PA_IO_EVENT_OUTPUT)
fdl->work_fds[i].revents |= POLLOUT;
if (events & PA_IO_EVENT_ERROR)
fdl->work_fds[i].revents |= POLLERR;
if (events & PA_IO_EVENT_HANGUP)
fdl->work_fds[i].revents |= POLLHUP;
break;
}
}
pa_assert(i != fdl->num_fds);
if (fdl->hctl)
err = snd_hctl_poll_descriptors_revents(fdl->hctl, fdl->work_fds, fdl->num_fds, &revents);
else
err = snd_mixer_poll_descriptors_revents(fdl->mixer, fdl->work_fds, fdl->num_fds, &revents);
if (err < 0) {
pa_log_error("Unable to get poll revent: %s", pa_alsa_strerror(err));
return;
}
a->defer_enable(fdl->defer, 1);
if (revents) {
if (fdl->hctl)
snd_hctl_handle_events(fdl->hctl);
else
snd_mixer_handle_events(fdl->mixer);
}
}
static void defer_cb(pa_mainloop_api *a, pa_defer_event *e, void *userdata) {
struct pa_alsa_fdlist *fdl = userdata;
unsigned num_fds, i;
int err, n;
struct pollfd *temp;
pa_assert(a);
pa_assert(fdl);
pa_assert(fdl->mixer || fdl->hctl);
a->defer_enable(fdl->defer, 0);
if (fdl->hctl)
n = snd_hctl_poll_descriptors_count(fdl->hctl);
else
n = snd_mixer_poll_descriptors_count(fdl->mixer);
if (n < 0) {
pa_log("snd_mixer_poll_descriptors_count() failed: %s", pa_alsa_strerror(n));
return;
}
else if (n == 0) {
pa_log_warn("Mixer has no poll descriptors. Please control mixer from PulseAudio only.");
return;
}
num_fds = (unsigned) n;
if (num_fds != fdl->num_fds) {
if (fdl->fds)
pa_xfree(fdl->fds);
if (fdl->work_fds)
pa_xfree(fdl->work_fds);
fdl->fds = pa_xnew0(struct pollfd, num_fds);
fdl->work_fds = pa_xnew(struct pollfd, num_fds);
}
memset(fdl->work_fds, 0, sizeof(struct pollfd) * num_fds);
if (fdl->hctl)
err = snd_hctl_poll_descriptors(fdl->hctl, fdl->work_fds, num_fds);
else
err = snd_mixer_poll_descriptors(fdl->mixer, fdl->work_fds, num_fds);
if (err < 0) {
pa_log_error("Unable to get poll descriptors: %s", pa_alsa_strerror(err));
return;
}
fdl->polled = false;
if (memcmp(fdl->fds, fdl->work_fds, sizeof(struct pollfd) * num_fds) == 0)
return;
if (fdl->ios) {
for (i = 0; i < fdl->num_fds; i++)
a->io_free(fdl->ios[i]);
if (num_fds != fdl->num_fds) {
pa_xfree(fdl->ios);
fdl->ios = NULL;
}
}
if (!fdl->ios)
fdl->ios = pa_xnew(pa_io_event*, num_fds);
/* Swap pointers */
temp = fdl->work_fds;
fdl->work_fds = fdl->fds;
fdl->fds = temp;
fdl->num_fds = num_fds;
for (i = 0;i < num_fds;i++)
fdl->ios[i] = a->io_new(a, fdl->fds[i].fd,
((fdl->fds[i].events & POLLIN) ? PA_IO_EVENT_INPUT : 0) |
((fdl->fds[i].events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0),
io_cb, fdl);
}
struct pa_alsa_fdlist *pa_alsa_fdlist_new(void) {
struct pa_alsa_fdlist *fdl;
fdl = pa_xnew0(struct pa_alsa_fdlist, 1);
return fdl;
}
void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl) {
pa_assert(fdl);
if (fdl->defer) {
pa_assert(fdl->m);
fdl->m->defer_free(fdl->defer);
}
if (fdl->ios) {
unsigned i;
pa_assert(fdl->m);
for (i = 0; i < fdl->num_fds; i++)
fdl->m->io_free(fdl->ios[i]);
pa_xfree(fdl->ios);
}
if (fdl->fds)
pa_xfree(fdl->fds);
if (fdl->work_fds)
pa_xfree(fdl->work_fds);
pa_xfree(fdl);
}
/* We can listen to either a snd_hctl_t or a snd_mixer_t, but not both */
int pa_alsa_fdlist_set_handle(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, snd_hctl_t *hctl_handle, pa_mainloop_api *m) {
pa_assert(fdl);
pa_assert(hctl_handle || mixer_handle);
pa_assert(!(hctl_handle && mixer_handle));
pa_assert(m);
pa_assert(!fdl->m);
fdl->hctl = hctl_handle;
fdl->mixer = mixer_handle;
fdl->m = m;
fdl->defer = m->defer_new(m, defer_cb, fdl);
return 0;
}
struct pa_alsa_mixer_pdata {
pa_rtpoll *rtpoll;
pa_rtpoll_item *poll_item;
snd_mixer_t *mixer;
};
struct pa_alsa_mixer_pdata *pa_alsa_mixer_pdata_new(void) {
struct pa_alsa_mixer_pdata *pd;
pd = pa_xnew0(struct pa_alsa_mixer_pdata, 1);
return pd;
}
void pa_alsa_mixer_pdata_free(struct pa_alsa_mixer_pdata *pd) {
pa_assert(pd);
if (pd->poll_item) {
pa_rtpoll_item_free(pd->poll_item);
}
pa_xfree(pd);
}
static int rtpoll_work_cb(pa_rtpoll_item *i) {
struct pa_alsa_mixer_pdata *pd;
struct pollfd *p;
unsigned n_fds;
unsigned short revents = 0;
int err, ret = 0;
pd = pa_rtpoll_item_get_work_userdata(i);
pa_assert_fp(pd);
pa_assert_fp(i == pd->poll_item);
p = pa_rtpoll_item_get_pollfd(i, &n_fds);
if ((err = snd_mixer_poll_descriptors_revents(pd->mixer, p, n_fds, &revents)) < 0) {
pa_log_error("Unable to get poll revent: %s", pa_alsa_strerror(err));
ret = -1;
goto fail;
}
if (revents) {
if (revents & (POLLNVAL | POLLERR)) {
pa_log_debug("Device disconnected, stopping poll on mixer");
goto fail;
} else if (revents & POLLERR) {
/* This shouldn't happen. */
pa_log_error("Got a POLLERR (revents = %04x), stopping poll on mixer", revents);
goto fail;
}
err = snd_mixer_handle_events(pd->mixer);
if (PA_LIKELY(err >= 0)) {
pa_rtpoll_item_free(i);
pa_alsa_set_mixer_rtpoll(pd, pd->mixer, pd->rtpoll);
} else {
pa_log_error("Error handling mixer event: %s", pa_alsa_strerror(err));
ret = -1;
goto fail;
}
}
return ret;
fail:
pa_rtpoll_item_free(i);
pd->poll_item = NULL;
pd->rtpoll = NULL;
pd->mixer = NULL;
return ret;
}
int pa_alsa_set_mixer_rtpoll(struct pa_alsa_mixer_pdata *pd, snd_mixer_t *mixer, pa_rtpoll *rtp) {
pa_rtpoll_item *i;
struct pollfd *p;
int err, n;
pa_assert(pd);
pa_assert(mixer);
pa_assert(rtp);
if ((n = snd_mixer_poll_descriptors_count(mixer)) < 0) {
pa_log("snd_mixer_poll_descriptors_count() failed: %s", pa_alsa_strerror(n));
return -1;
}
else if (n == 0) {
pa_log_warn("Mixer has no poll descriptors. Please control mixer from PulseAudio only.");
return 0;
}
i = pa_rtpoll_item_new(rtp, PA_RTPOLL_LATE, (unsigned) n);
p = pa_rtpoll_item_get_pollfd(i, NULL);
memset(p, 0, sizeof(struct pollfd) * n);
if ((err = snd_mixer_poll_descriptors(mixer, p, (unsigned) n)) < 0) {
pa_log_error("Unable to get poll descriptors: %s", pa_alsa_strerror(err));
pa_rtpoll_item_free(i);
return -1;
}
pd->rtpoll = rtp;
pd->poll_item = i;
pd->mixer = mixer;
pa_rtpoll_item_set_work_callback(i, rtpoll_work_cb, pd);
return 0;
}
#endif
static const snd_mixer_selem_channel_id_t alsa_channel_ids[PA_CHANNEL_POSITION_MAX] = {
[PA_CHANNEL_POSITION_MONO] = SND_MIXER_SCHN_MONO, /* The ALSA name is just an alias! */
@ -438,7 +759,7 @@ void pa_alsa_path_free(pa_alsa_path *p) {
}
pa_proplist_free(p->proplist);
pa_xfree(p->available_group);
pa_xfree(p->availability_group);
pa_xfree(p->name);
pa_xfree(p->description);
pa_xfree(p->description_key);
@ -3424,9 +3745,9 @@ static void mapping_free(pa_alsa_mapping *m) {
static void profile_free(pa_alsa_profile *p) {
pa_assert(p);
pa_xfree(p->profile.name);
pa_xfree(p->profile.description);
pa_xfree(p->profile.description_key);
pa_xfree(p->name);
pa_xfree(p->description);
pa_xfree(p->description_key);
pa_xfree(p->input_name);
pa_xfree(p->output_name);
@ -3503,9 +3824,9 @@ static pa_alsa_profile *profile_get(pa_alsa_profile_set *ps, const char *name) {
p = pa_xnew0(pa_alsa_profile, 1);
p->profile_set = ps;
p->profile.name = pa_xstrdup(name);
p->name = pa_xstrdup(name);
pa_hashmap_put(ps->profiles, p->profile.name, p);
pa_hashmap_put(ps->profiles, p->name, p);
return p;
}
@ -3693,8 +4014,8 @@ static int mapping_parse_description(pa_config_parser_state *state) {
pa_xfree(m->description);
m->description = pa_xstrdup(state->rvalue);
} else if ((p = profile_get(ps, state->section))) {
pa_xfree(p->profile.description);
p->profile.description = pa_xstrdup(state->rvalue);
pa_xfree(p->description);
p->description = pa_xstrdup(state->rvalue);
} else {
pa_log("[%s:%u] Section name %s invalid.", state->filename, state->lineno, state->section);
return -1;
@ -3716,8 +4037,8 @@ static int mapping_parse_description_key(pa_config_parser_state *state) {
pa_xfree(m->description_key);
m->description_key = pa_xstrdup(state->rvalue);
} else if ((p = profile_get(ps, state->section))) {
pa_xfree(p->profile.description_key);
p->profile.description_key = pa_xstrdup(state->rvalue);
pa_xfree(p->description_key);
p->description_key = pa_xstrdup(state->rvalue);
} else {
pa_log("[%s:%u] Section name %s invalid.", state->filename, state->lineno, state->section);
return -1;
@ -3745,7 +4066,7 @@ static int mapping_parse_priority(pa_config_parser_state *state) {
if ((m = pa_alsa_mapping_get(ps, state->section)))
m->priority = prio;
else if ((p = profile_get(ps, state->section)))
p->profile.priority = prio;
p->priority = prio;
else {
pa_log("[%s:%u] Section name %s invalid.", state->filename, state->lineno, state->section);
return -1;
@ -3963,7 +4284,7 @@ fail:
}
/* the logic is simple: if we see the jack in multiple paths */
/* assign all those jacks to one available_group */
/* assign all those jacks to one availability_group */
static void mapping_group_available(pa_hashmap *paths)
{
void *state, *state2;
@ -3975,34 +4296,34 @@ static void mapping_group_available(pa_hashmap *paths)
const char *found = NULL;
bool has_control = false;
PA_LLIST_FOREACH(j, p->jacks) {
if (!j->has_control || j->state_plugged == PA_AVAILABLE_NO)
continue;
has_control = true;
j->state_plugged = PA_AVAILABLE_UNKNOWN;
PA_HASHMAP_FOREACH(p2, paths, state2) {
if (p2 == p)
if (!j->has_control || j->state_plugged == PA_AVAILABLE_NO)
continue;
has_control = true;
PA_HASHMAP_FOREACH(p2, paths, state2) {
if (p2 == p)
break;
PA_LLIST_FOREACH(j2, p->jacks) {
if (!j2->has_control || j->state_plugged == PA_AVAILABLE_NO)
continue;
if (pa_streq(j->name, j2->name)) {
j2->state_plugged = PA_AVAILABLE_UNKNOWN;
found = p2->available_group;
break;
}
}
}
if (found)
break;
}
if (!has_control)
continue;
if (!found) {
p->available_group = pa_sprintf_malloc("Legacy %d", num);
} else {
p->available_group = pa_xstrdup(found);
}
if (!found)
PA_LLIST_FOREACH(j2, p2->jacks) {
if (!j2->has_control || j2->state_plugged == PA_AVAILABLE_NO)
continue;
if (pa_streq(j->name, j2->name)) {
j->state_plugged = PA_AVAILABLE_UNKNOWN;
j2->state_plugged = PA_AVAILABLE_UNKNOWN;
found = p2->availability_group;
break;
}
}
}
if (found)
break;
}
if (!has_control)
continue;
if (!found) {
p->availability_group = pa_sprintf_malloc("Legacy %d", num);
} else {
p->availability_group = pa_xstrdup(found);
}
if (!found)
num++;
}
}
@ -4180,13 +4501,13 @@ static void profile_set_add_auto_pair(
p = pa_xnew0(pa_alsa_profile, 1);
p->profile_set = ps;
p->profile.name = name;
p->name = name;
if (m) {
p->output_name = pa_xstrdup(m->name);
p->output_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
pa_idxset_put(p->output_mappings, m, NULL);
p->profile.priority += m->priority * 100;
p->priority += m->priority * 100;
p->fallback_output = m->fallback;
}
@ -4194,11 +4515,11 @@ static void profile_set_add_auto_pair(
p->input_name = pa_xstrdup(n->name);
p->input_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
pa_idxset_put(p->input_mappings, n, NULL);
p->profile.priority += n->priority;
p->priority += n->priority;
p->fallback_input = n->fallback;
}
pa_hashmap_put(ps->profiles, p->profile.name, p);
pa_hashmap_put(ps->profiles, p->name, p);
}
static void profile_set_add_auto(pa_alsa_profile_set *ps) {
@ -4236,7 +4557,7 @@ static int profile_verify(pa_alsa_profile *p) {
{ "output:unknown-stereo+input:unknown-stereo", N_("Stereo Duplex") },
{ "off", N_("Off") }
};
const char *description_key = p->profile.description_key ? p->profile.description_key : p->profile.name;
const char *description_key = p->description_key ? p->description_key : p->name;
pa_assert(p);
@ -4262,7 +4583,7 @@ static int profile_verify(pa_alsa_profile *p) {
continue;
if (!(m = pa_hashmap_get(p->profile_set->mappings, *name)) || m->direction == PA_ALSA_DIRECTION_INPUT) {
pa_log("Profile '%s' refers to nonexistent mapping '%s'.", p->profile.name, *name);
pa_log("Profile '%s' refers to nonexistent mapping '%s'.", p->name, *name);
return -1;
}
@ -4298,7 +4619,7 @@ static int profile_verify(pa_alsa_profile *p) {
continue;
if (!(m = pa_hashmap_get(p->profile_set->mappings, *name)) || m->direction == PA_ALSA_DIRECTION_OUTPUT) {
pa_log("Profile '%s' refers to nonexistent mapping '%s'.", p->profile.name, *name);
pa_log("Profile '%s' refers to nonexistent mapping '%s'.", p->name, *name);
return -1;
}
@ -4313,16 +4634,16 @@ static int profile_verify(pa_alsa_profile *p) {
}
if (!p->input_mappings && !p->output_mappings) {
pa_log("Profile '%s' lacks mappings.", p->profile.name);
pa_log("Profile '%s' lacks mappings.", p->name);
return -1;
}
if (!p->profile.description)
p->profile.description = pa_xstrdup(lookup_description(description_key,
if (!p->description)
p->description = pa_xstrdup(lookup_description(description_key,
well_known_descriptions,
PA_ELEMENTSOF(well_known_descriptions)));
if (!p->profile.description) {
if (!p->description) {
uint32_t idx;
pa_alsa_mapping *m;
char *ptr;
@ -4347,7 +4668,7 @@ static int profile_verify(pa_alsa_profile *p) {
}
fclose(f);
p->profile.description = ptr;
p->description = ptr;
}
return 0;
@ -4359,11 +4680,11 @@ void pa_alsa_profile_dump(pa_alsa_profile *p) {
pa_assert(p);
pa_log_debug("Profile %s (%s), input=%s, output=%s priority=%u, supported=%s n_input_mappings=%u, n_output_mappings=%u",
p->profile.name,
pa_strnull(p->profile.description),
p->name,
pa_strnull(p->description),
pa_strnull(p->input_name),
pa_strnull(p->output_name),
p->profile.priority,
p->priority,
pa_yes_no(p->supported),
p->input_mappings ? pa_idxset_size(p->input_mappings) : 0,
p->output_mappings ? pa_idxset_size(p->output_mappings) : 0);
@ -4703,8 +5024,7 @@ void pa_alsa_profile_set_probe(
if (p->output_mappings) {
PA_IDXSET_FOREACH(m, p->output_mappings, idx) {
if (pa_hashmap_get(broken_outputs, m) == m) {
pa_log_debug("Skipping profile %s - will not be able to open output:%s",
p->profile.name, m->name);
pa_log_debug("Skipping profile %s - will not be able to open output:%s", p->name, m->name);
p->supported = false;
break;
}
@ -4714,8 +5034,7 @@ void pa_alsa_profile_set_probe(
if (p->input_mappings && p->supported) {
PA_IDXSET_FOREACH(m, p->input_mappings, idx) {
if (pa_hashmap_get(broken_inputs, m) == m) {
pa_log_debug("Skipping profile %s - will not be able to open input:%s",
p->profile.name, m->name);
pa_log_debug("Skipping profile %s - will not be able to open input:%s", p->name, m->name);
p->supported = false;
break;
}
@ -4723,7 +5042,7 @@ void pa_alsa_profile_set_probe(
}
if (p->supported)
pa_log_debug("Looking at profile %s", p->profile.name);
pa_log_debug("Looking at profile %s", p->name);
/* Check if we can open all new ones */
if (p->output_mappings && p->supported)
@ -4780,7 +5099,7 @@ void pa_alsa_profile_set_probe(
continue;
}
pa_log_debug("Profile %s supported.", p->profile.name);
pa_log_debug("Profile %s supported.", p->name);
if (p->output_mappings)
PA_IDXSET_FOREACH(m, p->output_mappings, idx)
@ -4848,7 +5167,7 @@ void pa_alsa_profile_set_drop_unsupported(pa_alsa_profile_set *ps) {
PA_HASHMAP_FOREACH(p, ps->profiles, state) {
if (!p->supported)
pa_hashmap_remove_and_free(ps->profiles, p->profile.name);
pa_hashmap_remove_and_free(ps->profiles, p->name);
}
PA_HASHMAP_FOREACH(m, ps->mappings, state) {
@ -4862,7 +5181,7 @@ static pa_device_port* device_port_alsa_init(pa_hashmap *ports, /* card ports */
const char* description,
pa_alsa_path *path,
pa_alsa_setting *setting,
pa_alsa_profile *cp,
pa_card_profile *cp,
pa_hashmap *extra, /* sink/source ports */
pa_core *core) {
@ -4881,12 +5200,12 @@ static pa_device_port* device_port_alsa_init(pa_hashmap *ports, /* card ports */
pa_device_port_new_data_set_description(&port_data, description);
pa_device_port_new_data_set_direction(&port_data, path->direction == PA_ALSA_DIRECTION_OUTPUT ? PA_DIRECTION_OUTPUT : PA_DIRECTION_INPUT);
pa_device_port_new_data_set_type(&port_data, path->device_port_type);
pa_device_port_new_data_set_available_group(&port_data, path->available_group);
pa_device_port_new_data_set_availability_group(&port_data, path->availability_group);
p = pa_device_port_new(core, &port_data, sizeof(pa_alsa_port_data));
pa_device_port_new_data_done(&port_data);
pa_assert(p);
pa_hashmap_put(ports, p->port.name, p);
pa_hashmap_put(ports, p->name, p);
pa_proplist_update(p->proplist, PA_UPDATE_REPLACE, path->proplist);
data = PA_DEVICE_PORT_DATA(p);
@ -4897,10 +5216,10 @@ static pa_device_port* device_port_alsa_init(pa_hashmap *ports, /* card ports */
}
if (cp)
pa_hashmap_put(p->profiles, cp->profile.name, cp);
pa_hashmap_put(p->profiles, cp->name, cp);
if (extra) {
pa_hashmap_put(extra, p->port.name, p);
pa_hashmap_put(extra, p->name, p);
}
return p;
@ -4908,7 +5227,7 @@ static pa_device_port* device_port_alsa_init(pa_hashmap *ports, /* card ports */
void pa_alsa_path_set_add_ports(
pa_alsa_path_set *ps,
pa_alsa_profile *cp,
pa_card_profile *cp,
pa_hashmap *ports, /* card ports */
pa_hashmap *extra, /* sink/source ports */
pa_core *core) {
@ -4927,7 +5246,7 @@ void pa_alsa_path_set_add_ports(
* single entry */
pa_device_port *port = device_port_alsa_init(ports, path->name,
path->description, path, path->settings, cp, extra, core);
port->port.priority = path->priority * 100;
port->priority = path->priority * 100;
} else {
pa_alsa_setting *s;
@ -4943,7 +5262,7 @@ void pa_alsa_path_set_add_ports(
d = pa_xstrdup(path->description);
port = device_port_alsa_init(ports, n, d, path, s, cp, extra, core);
port->port.priority = path->priority * 100 + s->priority;
port->priority = path->priority * 100 + s->priority;
pa_xfree(n);
pa_xfree(d);

View file

@ -37,6 +37,7 @@ typedef struct pa_alsa_decibel_fix pa_alsa_decibel_fix;
typedef struct pa_alsa_profile_set pa_alsa_profile_set;
typedef struct pa_alsa_port_data pa_alsa_port_data;
typedef struct pa_alsa_profile pa_alsa_profile;
typedef struct pa_alsa_profile pa_card_profile;
typedef struct pa_alsa_device pa_alsa_device;
typedef enum pa_alsa_switch_use {
@ -99,8 +100,8 @@ struct pa_alsa_setting {
struct pa_alsa_mixer {
snd_mixer_t *mixer_handle;
int card_index;
bool used_for_probe_only:1;
bool used_for_poll:1;
bool used_for_probe_only:1;
};
/* ALSA mixer element identifier */
@ -207,7 +208,7 @@ struct pa_alsa_path {
char *name;
char *description_key;
char *description;
char *available_group;
char *availability_group;
pa_device_port_type_t device_port_type;
unsigned priority;
bool autodetect_eld_device;
@ -357,6 +358,11 @@ struct pa_alsa_profile {
pa_alsa_profile_set *profile_set;
char *name;
char *description;
char *description_key;
unsigned priority;
char *input_name;
char *output_name;
@ -419,6 +425,18 @@ void pa_alsa_profile_set_drop_unsupported(pa_alsa_profile_set *s);
void pa_alsa_mixer_use_for_poll(pa_hashmap *mixers, snd_mixer_t *mixer_handle);
#if 0
pa_alsa_fdlist *pa_alsa_fdlist_new(void);
void pa_alsa_fdlist_free(pa_alsa_fdlist *fdl);
int pa_alsa_fdlist_set_handle(pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, snd_hctl_t *hctl_handle, pa_mainloop_api* m);
/* Alternative for handling alsa mixer events in io-thread. */
pa_alsa_mixer_pdata *pa_alsa_mixer_pdata_new(void);
void pa_alsa_mixer_pdata_free(pa_alsa_mixer_pdata *pd);
int pa_alsa_set_mixer_rtpoll(struct pa_alsa_mixer_pdata *pd, snd_mixer_t *mixer, pa_rtpoll *rtp);
#endif
/* Data structure for inclusion in pa_device_port for alsa
* sinks/sources. This contains nothing that needs to be freed
* individually */

View file

@ -941,7 +941,7 @@ static void probe_volumes(pa_hashmap *hash, bool is_sink, snd_pcm_t *pcm_handle,
pa_log_warn("Path %s is not a volume control", data->path->name);
pa_hashmap_remove(data->paths, profile);
} else
pa_log_debug("Set up h/w volume using '%s' for %s:%s", path->name, profile, port->port.name);
pa_log_debug("Set up h/w volume using '%s' for %s:%s", path->name, profile, port->name);
}
}
@ -962,7 +962,7 @@ static void ucm_add_port_combination(
pa_alsa_ucm_device **pdevices,
int num,
pa_hashmap *ports,
pa_alsa_profile *cp,
pa_card_profile *cp,
pa_core *core) {
pa_device_port *port;
@ -1050,7 +1050,7 @@ static void ucm_add_port_combination(
pa_device_port_new_data_set_type(&port_data, type);
pa_device_port_new_data_set_direction(&port_data, is_sink ? PA_DIRECTION_OUTPUT : PA_DIRECTION_INPUT);
if (jack)
pa_device_port_new_data_set_available_group(&port_data, jack->name);
pa_device_port_new_data_set_availability_group(&port_data, jack->name);
port = pa_device_port_new(core, &port_data, sizeof(pa_alsa_ucm_port_data));
pa_device_port_new_data_done(&port_data);
@ -1059,8 +1059,8 @@ static void ucm_add_port_combination(
ucm_port_data_init(data, context->ucm, port, pdevices, num);
port->impl_free = ucm_port_data_free;
pa_hashmap_put(ports, port->port.name, port);
pa_log_debug("Add port %s: %s", port->port.name, port->port.description);
pa_hashmap_put(ports, port->name, port);
pa_log_debug("Add port %s: %s", port->name, port->description);
if (num == 1) {
/* To keep things simple and not worry about stacking controls, we only support hardware volumes on non-combination
@ -1093,21 +1093,21 @@ static void ucm_add_port_combination(
}
}
port->port.priority = priority;
port->priority = priority;
pa_xfree(name);
pa_xfree(desc);
direction = is_sink ? "output" : "input";
pa_log_debug("Port %s direction %s, priority %d", port->port.name, direction, priority);
pa_log_debug("Port %s direction %s, priority %d", port->name, direction, priority);
if (cp) {
pa_log_debug("Adding profile %s to port %s.", cp->profile.name, port->port.name);
pa_hashmap_put(port->profiles, cp->profile.name, cp);
pa_log_debug("Adding profile %s to port %s.", cp->name, port->name);
pa_hashmap_put(port->profiles, cp->name, cp);
}
if (hash) {
pa_hashmap_put(hash, port->port.name, port);
pa_hashmap_put(hash, port->name, port);
}
}
@ -1195,7 +1195,7 @@ static void ucm_add_ports_combination(
int dev_num,
uint32_t map_index,
pa_hashmap *ports,
pa_alsa_profile *cp,
pa_card_profile *cp,
pa_core *core) {
pa_alsa_ucm_device *dev;
@ -1252,7 +1252,7 @@ void pa_alsa_ucm_add_ports_combination(
pa_alsa_ucm_mapping_context *context,
bool is_sink,
pa_hashmap *ports,
pa_alsa_profile *cp,
pa_card_profile *cp,
pa_core *core) {
pa_alsa_ucm_device **pdevices;
@ -1382,7 +1382,7 @@ int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *p
PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) {
const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME);
if (ucm_port_contains(port->port.name, dev_name, is_sink))
if (ucm_port_contains(port->name, dev_name, is_sink))
enable_devs[enable_num++] = dev_name;
else {
pa_log_debug("Disable ucm device %s", dev_name);
@ -1723,14 +1723,14 @@ static int ucm_create_profile(
p = pa_xnew0(pa_alsa_profile, 1);
p->profile_set = ps;
p->profile.name = pa_xstrdup(verb_name);
p->profile.description = pa_xstrdup(verb_desc);
p->name = pa_xstrdup(verb_name);
p->description = pa_xstrdup(verb_desc);
p->output_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
p->input_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
p->supported = true;
pa_hashmap_put(ps->profiles, p->profile.name, p);
pa_hashmap_put(ps->profiles, p->name, p);
/* TODO: get profile priority from policy management */
priority = verb->priority;
@ -1751,7 +1751,7 @@ static int ucm_create_profile(
pa_xfree(verb_cmp);
}
p->profile.priority = priority;
p->priority = priority;
PA_LLIST_FOREACH(dev, verb->devices) {
pa_alsa_jack *jack;
@ -1939,10 +1939,10 @@ static void ucm_probe_profile_set(pa_alsa_ucm_config *ucm, pa_alsa_profile_set *
PA_HASHMAP_FOREACH(p, ps->profiles, state) {
/* change verb */
pa_log_info("Set ucm verb to %s", p->profile.name);
pa_log_info("Set ucm verb to %s", p->name);
if ((snd_use_case_set(ucm->ucm_mgr, "_verb", p->profile.name)) < 0) {
pa_log("Failed to set verb %s", p->profile.name);
if ((snd_use_case_set(ucm->ucm_mgr, "_verb", p->name)) < 0) {
pa_log("Failed to set verb %s", p->name);
p->supported = false;
continue;
}
@ -1982,7 +1982,7 @@ static void ucm_probe_profile_set(pa_alsa_ucm_config *ucm, pa_alsa_profile_set *
continue;
}
pa_log_debug("Profile %s supported.", p->profile.name);
pa_log_debug("Profile %s supported.", p->name);
PA_IDXSET_FOREACH(m, p->output_mappings, idx)
if (!PA_UCM_IS_MODIFIER_MAPPING(m))
@ -2345,7 +2345,7 @@ void pa_alsa_ucm_add_ports_combination(
pa_alsa_ucm_mapping_context *context,
bool is_sink,
pa_hashmap *ports,
pa_alsa_card_profile *cp,
pa_card_profile *cp,
pa_core *core) {
}

View file

@ -164,7 +164,7 @@ void pa_alsa_ucm_add_ports_combination(
pa_alsa_ucm_mapping_context *context,
bool is_sink,
pa_hashmap *ports,
pa_alsa_profile *cp,
pa_card_profile *cp,
pa_core *core);
int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port, bool is_sink);

View file

@ -532,7 +532,7 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
if (!pa_channel_map_superset(&m->channel_map, map))
continue;
pa_log_debug("Checking for superset %s (%s)", m->device.name, m->device.device_strings[0]);
pa_log_debug("Checking for superset %s (%s)", m->name, m->device_strings[0]);
pcm_handle = pa_alsa_open_by_device_id_mapping(
dev_id,

View file

@ -51,11 +51,11 @@ void pa_device_port_new_data_set_available(pa_device_port_new_data *data, pa_ava
data->available = available;
}
void pa_device_port_new_data_set_available_group(pa_device_port_new_data *data, const char *group)
void pa_device_port_new_data_set_availability_group(pa_device_port_new_data *data, const char *group)
{
pa_assert(data);
pa_xfree(data->available_group);
data->available_group = pa_xstrdup(group);
pa_xfree(data->availability_group);
data->availability_group = pa_xstrdup(group);
}
void pa_device_port_new_data_set_direction(pa_device_port_new_data *data, pa_direction_t direction)
@ -75,7 +75,7 @@ void pa_device_port_new_data_done(pa_device_port_new_data *data)
pa_assert(data);
pa_xfree(data->name);
pa_xfree(data->description);
pa_xfree(data->available_group);
pa_xfree(data->availability_group);
}
pa_device_port *pa_device_port_new(pa_core *c, pa_device_port_new_data *data, size_t extra)
@ -89,17 +89,20 @@ pa_device_port *pa_device_port_new(pa_core *c, pa_device_port_new_data *data, si
p = calloc(1, sizeof(pa_device_port) + extra);
p->port.name = data->name;
p->port.name = p->name = data->name;
data->name = NULL;
p->port.description = data->description;
p->port.description = p->description = data->description;
data->description = NULL;
p->port.priority = 0;
p->priority = p->port.priority = 0;
p->available = data->available;
p->port.available = (enum acp_available) data->available;
p->port.available_group = data->available_group;
data->available_group = NULL;
p->port.availability_group = p->availability_group = data->availability_group;
data->availability_group = NULL;
p->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
p->direction = data->direction;
p->port.direction = data->direction == PA_DIRECTION_OUTPUT ?
ACP_DIRECTION_PLAYBACK : ACP_DIRECTION_CAPTURE;
p->type = data->type;
p->port.type = (enum acp_port_type) data->type;
p->proplist = pa_proplist_new();
@ -110,15 +113,16 @@ pa_device_port *pa_device_port_new(pa_core *c, pa_device_port_new_data *data, si
void pa_device_port_set_available(pa_device_port *p, pa_available_t status)
{
enum acp_available old = p->port.available;
pa_available_t old = p->available;
if (old == (enum acp_available) status)
if (old == status)
return;
p->available = status;
p->port.available = (enum acp_available) status;
if (p->card && p->card->events && p->card->events->port_available)
p->card->events->port_available(p->card->user_data, p->port.index,
old, (enum acp_available) status);
(enum acp_available)old, p->port.available);
}
bool pa_alsa_device_init_description(pa_proplist *p, pa_card *card) {

View file

@ -65,6 +65,18 @@ struct pa_device_port {
pa_card *card;
char *name;
char *description;
char *preferred_profile;
pa_device_port_type_t type;
unsigned priority;
pa_available_t available; /* PA_AVAILABLE_UNKNOWN, PA_AVAILABLE_NO or PA_AVAILABLE_YES */
char *availability_group; /* a string indentifier which determine the group of devices handling the available state simulteneously */
pa_direction_t direction;
int64_t latency_offset;
pa_proplist *proplist;
pa_hashmap *profiles;
pa_dynarray prof;
@ -81,7 +93,7 @@ typedef struct pa_device_port_new_data {
char *name;
char *description;
pa_available_t available;
char *available_group;
char *availability_group;
pa_direction_t direction;
pa_device_port_type_t type;
} pa_device_port_new_data;
@ -90,7 +102,7 @@ pa_device_port_new_data *pa_device_port_new_data_init(pa_device_port_new_data *d
void pa_device_port_new_data_set_name(pa_device_port_new_data *data, const char *name);
void pa_device_port_new_data_set_description(pa_device_port_new_data *data, const char *description);
void pa_device_port_new_data_set_available(pa_device_port_new_data *data, pa_available_t available);
void pa_device_port_new_data_set_available_group(pa_device_port_new_data *data, const char *group);
void pa_device_port_new_data_set_availability_group(pa_device_port_new_data *data, const char *group);
void pa_device_port_new_data_set_direction(pa_device_port_new_data *data, pa_direction_t direction);
void pa_device_port_new_data_set_type(pa_device_port_new_data *data, pa_device_port_type_t type);
void pa_device_port_new_data_done(pa_device_port_new_data *data);

View file

@ -28,6 +28,9 @@ required-any = any
state.plugged = unknown
state.unplugged = unknown
[Jack Line - Input]
required-any = any
[Element Capture]
switch = mute
volume = merge

View file

@ -29,6 +29,9 @@ required-any = any
state.plugged = unknown
state.unplugged = unknown
[Jack Mic - Input]
required-any = any
[Element Capture]
switch = mute
volume = merge

View file

@ -52,6 +52,9 @@ state.unplugged = unknown
[Jack Headphone Mic]
required-any = any
[Jack Headphone - Output]
required-any = any
[Element Hardware Master]
switch = mute
volume = merge

View file

@ -69,6 +69,9 @@ required-any = any
state.plugged = unknown
state.unplugged = unknown
[Jack Speaker - Output]
required-any = any
[Element Hardware Master]
switch = mute
volume = merge

View file

@ -53,6 +53,8 @@
; [General]
; type = ... # The device type. It's highly recommended to set a type for every path.
; # See parse_type() in alsa-mixer.c for supported values.
; priority = ... # Priority for this path
; description-key = ... # The path description is looked up from a table in path_verify() in
; # src/modules/alsa/alsa-mixer.c. By default the path name (i.e. the file name