diff --git a/spa/plugins/alsa/acp/acp.c b/spa/plugins/alsa/acp/acp.c index 963c6956b..7ff2350b9 100644 --- a/spa/plugins/alsa/acp/acp.c +++ b/spa/plugins/alsa/acp/acp.c @@ -1206,6 +1206,41 @@ int acp_card_set_profile(struct acp_card *card, uint32_t new_index) return 0; } +static void prune_singleton_availability_groups(pa_hashmap *ports) { + pa_device_port *p; + pa_hashmap *group_counts; + void *state, *count; + const char *group; + + /* Collect groups and erase those that don't have more than 1 path */ + group_counts = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + + PA_HASHMAP_FOREACH(p, ports, state) { + if (p->availability_group) { + count = pa_hashmap_get(group_counts, p->availability_group); + pa_hashmap_remove(group_counts, p->availability_group); + pa_hashmap_put(group_counts, p->availability_group, PA_UINT_TO_PTR(PA_PTR_TO_UINT(count) + 1)); + } + } + + /* Now we have an availability_group -> count map, let's drop all groups + * that have only one member */ + PA_HASHMAP_FOREACH_KV(group, count, group_counts, state) { + if (count == PA_UINT_TO_PTR(1)) + pa_hashmap_remove(group_counts, group); + } + + PA_HASHMAP_FOREACH(p, ports, state) { + if (p->availability_group && !pa_hashmap_get(group_counts, p->availability_group)) { + pa_log_debug("Pruned singleton availability group %s from port %s", p->availability_group, p->name); + pa_xfree(p->availability_group); + p->availability_group = NULL; + } + } + + pa_hashmap_free(group_counts); +} + static const char *acp_dict_lookup(const struct acp_dict *dict, const char *key) { const struct acp_dict_item *it; @@ -1305,6 +1340,7 @@ struct acp_card *acp_card_new(uint32_t index, const struct acp_dict *props) pa_alsa_init_description(impl->proplist, NULL); add_profiles(impl); + prune_singleton_availability_groups(impl->ports); card->n_profiles = pa_dynarray_size(&impl->out.profiles); card->profiles = impl->out.profiles.array.data; diff --git a/spa/plugins/alsa/acp/alsa-mixer.c b/spa/plugins/alsa/acp/alsa-mixer.c index f8935c572..d49e9e54d 100644 --- a/spa/plugins/alsa/acp/alsa-mixer.c +++ b/spa/plugins/alsa/acp/alsa-mixer.c @@ -1768,7 +1768,7 @@ static bool element_probe_volume(pa_alsa_element *e, snd_mixer_elem_t *me) { if (is_mono) { e->n_channels = 1; - if (e->override_map & (1 << (e->n_channels-1))) { + if (!e->override_map) { for (p = PA_CHANNEL_POSITION_FRONT_LEFT; p < PA_CHANNEL_POSITION_MAX; p++) { if (alsa_channel_ids[p] == SND_MIXER_SCHN_UNKNOWN) continue; @@ -1795,24 +1795,24 @@ static bool element_probe_volume(pa_alsa_element *e, snd_mixer_elem_t *me) { alsa_id_str(buf, sizeof(buf), &e->alsa_id); pa_log_warn("Volume element %s with no channels?", buf); return false; - } else if (e->n_channels > 8) { + } else if (e->n_channels > 2) { /* FIXME: In some places code like this is used: * * e->masks[alsa_channel_ids[p]][e->n_channels-1] * * The definition of e->masks is * - * pa_channel_position_mask_t masks[SND_MIXER_SCHN_LAST + 1][8]; + * pa_channel_position_mask_t masks[SND_MIXER_SCHN_LAST + 1][2]; * - * Since the array size is fixed at 8, we obviously - * don't support elements with more than eight + * Since the array size is fixed at 2, we obviously + * don't support elements with more than two * channels... */ alsa_id_str(buf, sizeof(buf), &e->alsa_id); pa_log_warn("Volume element %s has %u channels. That's too much! I can't handle that!", buf, e->n_channels); return false; } - if (!(e->override_map & (1 << (e->n_channels-1)))) { + if (!e->override_map) { for (p = PA_CHANNEL_POSITION_FRONT_LEFT; p < PA_CHANNEL_POSITION_MAX; p++) { bool has_channel; @@ -2464,7 +2464,7 @@ static pa_channel_position_mask_t parse_mask(const char *m) { static int element_parse_override_map(pa_config_parser_state *state) { pa_alsa_path *p; pa_alsa_element *e; - const char *split_state = NULL, *s; + const char *split_state = NULL; unsigned i = 0; char *n; @@ -2490,23 +2490,18 @@ static int element_parse_override_map(pa_config_parser_state *state) { } } - s = strstr(state->lvalue, "."); - if (s) { - int idx; - pa_atoi(s + 1, &idx); - if (idx >= 1 && idx <= 8) { - e->override_map |= (1 << i); - e->masks[i++][idx-1] = m; - } else { - pa_log("[%s:%u] Override map index '%s' invalid in '%s'", state->filename, state->lineno, state->lvalue, state->section); - } - } + if (pa_streq(state->lvalue, "override-map.1")) + e->masks[i++][0] = m; + else + e->masks[i++][1] = m; - /* Later on we might add override-map.9 and so on here ... */ + /* Later on we might add override-map.3 and so on here ... */ pa_xfree(n); } + e->override_map = true; + return 0; } @@ -2811,12 +2806,6 @@ pa_alsa_path* pa_alsa_path_new(const char *paths_dir, const char *fname, pa_alsa { "enumeration", element_parse_enumeration, NULL, NULL }, { "override-map.1", element_parse_override_map, NULL, NULL }, { "override-map.2", element_parse_override_map, NULL, NULL }, - { "override-map.3", element_parse_override_map, NULL, NULL }, - { "override-map.4", element_parse_override_map, NULL, NULL }, - { "override-map.5", element_parse_override_map, NULL, NULL }, - { "override-map.6", element_parse_override_map, NULL, NULL }, - { "override-map.7", element_parse_override_map, NULL, NULL }, - { "override-map.8", element_parse_override_map, NULL, NULL }, /* ... later on we might add override-map.3 and so on here ... */ { "required", element_parse_required, NULL, NULL }, { "required-any", element_parse_required, NULL, NULL }, @@ -3034,7 +3023,6 @@ int pa_alsa_path_probe(pa_alsa_path *p, pa_alsa_mapping *mapping, snd_mixer_t *m double min_dB[PA_CHANNEL_POSITION_MAX], max_dB[PA_CHANNEL_POSITION_MAX]; pa_channel_position_t t; pa_channel_position_mask_t path_volume_channels = 0; - bool min_dB_set, max_dB_set; char buf[64]; pa_assert(p); @@ -3065,7 +3053,7 @@ int pa_alsa_path_probe(pa_alsa_path *p, pa_alsa_mapping *mapping, snd_mixer_t *m pa_log_debug("Probe of element %s failed.", buf); return -1; } - pa_log_debug("Probe of element %s succeeded (volume=%d, switch=%d, enumeration=%d, has_dB=%d).", buf, e->volume_use, e->switch_use, e->enumeration_use, e->has_dB); + pa_log_debug("Probe of element %s succeeded (volume=%d, switch=%d, enumeration=%d).", buf, e->volume_use, e->switch_use, e->enumeration_use); if (ignore_dB) e->has_dB = false; @@ -3077,8 +3065,6 @@ int pa_alsa_path_probe(pa_alsa_path *p, pa_alsa_mapping *mapping, snd_mixer_t *m p->max_volume = e->max_volume; } - pa_log_debug("merge ok, has_volume = %d", p->has_volume); - if (e->has_dB) { if (!p->has_volume) { for (t = 0; t < PA_CHANNEL_POSITION_MAX; t++) @@ -3131,30 +3117,18 @@ int pa_alsa_path_probe(pa_alsa_path *p, pa_alsa_mapping *mapping, snd_mixer_t *m p->supported = true; p->min_dB = INFINITY; - min_dB_set = false; p->max_dB = -INFINITY; - max_dB_set = false; for (t = 0; t < PA_CHANNEL_POSITION_MAX; t++) { if (path_volume_channels & PA_CHANNEL_POSITION_MASK(t)) { - if (p->min_dB > min_dB[t]) { + if (p->min_dB > min_dB[t]) p->min_dB = min_dB[t]; - min_dB_set = true; - } - if (p->max_dB < max_dB[t]) { + if (p->max_dB < max_dB[t]) p->max_dB = max_dB[t]; - max_dB_set = true; - } } } - /* this is probably a wrong prediction, but it should be safe */ - if (!min_dB_set) - p->min_dB = -INFINITY; - if (!max_dB_set) - p->max_dB = 0; - return 0; } @@ -3191,7 +3165,7 @@ void pa_alsa_element_dump(pa_alsa_element *e) { pa_assert(e); alsa_id_str(buf, sizeof(buf), &e->alsa_id); - pa_log_debug("Element %s, direction=%i, switch=%i, volume=%i, volume_limit=%li, enumeration=%i, required=%i, required_any=%i, required_absent=%i, mask=0x%llx, n_channels=%u, override_map=%02x", + pa_log_debug("Element %s, direction=%i, switch=%i, volume=%i, volume_limit=%li, enumeration=%i, required=%i, required_any=%i, required_absent=%i, mask=0x%llx, n_channels=%u, override_map=%s", buf, e->direction, e->switch_use, @@ -3203,7 +3177,7 @@ void pa_alsa_element_dump(pa_alsa_element *e) { e->required_absent, (long long unsigned) e->merged_mask, e->n_channels, - e->override_map); + pa_yes_no(e->override_map)); PA_LLIST_FOREACH(o, e->options) pa_alsa_option_dump(o); @@ -4313,28 +4287,42 @@ fail: } /* the logic is simple: if we see the jack in multiple paths */ -/* assign all those jacks to one availability_group */ -static void mapping_group_available(pa_hashmap *paths) -{ - void *state, *state2; - pa_alsa_path *p, *p2; - pa_alsa_jack *j, *j2; +/* assign all those paths to one availability_group */ +static void profile_set_set_availability_groups(pa_alsa_profile_set *ps) { + pa_dynarray *paths; + pa_alsa_path *p; + void *state; + unsigned idx1; uint32_t num = 1; - PA_HASHMAP_FOREACH(p, paths, state) { + /* Merge ps->input_paths and ps->output_paths into one dynarray. */ + paths = pa_dynarray_new(NULL); + PA_HASHMAP_FOREACH(p, ps->input_paths, state) + pa_dynarray_append(paths, p); + PA_HASHMAP_FOREACH(p, ps->output_paths, state) + pa_dynarray_append(paths, p); + + PA_DYNARRAY_FOREACH(p, paths, idx1) { + pa_alsa_jack *j; const char *found = NULL; bool has_control = false; + PA_LLIST_FOREACH(j, p->jacks) { + pa_alsa_path *p2; + unsigned idx2; + if (!j->has_control || j->state_plugged == PA_AVAILABLE_NO) continue; has_control = true; - PA_HASHMAP_FOREACH(p2, paths, state2) { + PA_DYNARRAY_FOREACH(p2, paths, idx2) { + pa_alsa_jack *j2; + if (p2 == p) - break; + break; PA_LLIST_FOREACH(j2, p2->jacks) { if (!j2->has_control || j2->state_plugged == PA_AVAILABLE_NO) continue; - if (pa_streq(j->name, j2->name)) { + if (pa_streq(j->alsa_name, j2->alsa_name)) { j->state_plugged = PA_AVAILABLE_UNKNOWN; j2->state_plugged = PA_AVAILABLE_UNKNOWN; found = p2->availability_group; @@ -4355,6 +4343,8 @@ static void mapping_group_available(pa_hashmap *paths) if (!found) num++; } + + pa_dynarray_free(paths); } static void mapping_paths_probe(pa_alsa_mapping *m, pa_alsa_profile *profile, @@ -4405,8 +4395,6 @@ static void mapping_paths_probe(pa_alsa_mapping *m, pa_alsa_profile *profile, PA_HASHMAP_FOREACH(p, ps->paths, state) pa_hashmap_put(used_paths, p, p); - mapping_group_available(ps->paths); - pa_log_debug("Available mixer paths (after tidying):"); pa_alsa_path_set_dump(ps); } @@ -4415,6 +4403,8 @@ static int mapping_verify(pa_alsa_mapping *m, const pa_channel_map *bonus) { static const struct description_map well_known_descriptions[] = { { "analog-mono", N_("Analog Mono") }, + { "analog-mono-left", N_("Analog Mono (Left)") }, + { "analog-mono-right", N_("Analog Mono (Right)") }, { "analog-stereo", N_("Analog Stereo") }, { "mono-fallback", N_("Mono") }, { "stereo-fallback", N_("Stereo") }, @@ -4425,6 +4415,8 @@ static int mapping_verify(pa_alsa_mapping *m, const pa_channel_map *bonus) { * multichannel-input and multichannel-output. */ { "analog-stereo-input", N_("Analog Stereo") }, { "analog-stereo-output", N_("Analog Stereo") }, + { "analog-stereo-headset", N_("Headset") }, + { "analog-stereo-speakerphone", N_("Speakerphone") }, { "multichannel-input", N_("Multichannel") }, { "multichannel-output", N_("Multichannel") }, { "analog-surround-21", N_("Analog Surround 2.1") }, @@ -4581,6 +4573,8 @@ static int profile_verify(pa_alsa_profile *p) { static const struct description_map well_known_descriptions[] = { { "output:analog-mono+input:analog-mono", N_("Analog Mono Duplex") }, { "output:analog-stereo+input:analog-stereo", N_("Analog Stereo Duplex") }, + { "output:analog-stereo-headset+input:analog-stereo-headset", N_("Headset") }, + { "output:analog-stereo-speakerphone+input:analog-stereo-speakerphone", N_("Speakerphone") }, { "output:iec958-stereo+input:iec958-stereo", N_("Digital Stereo Duplex (IEC958)") }, { "output:multichannel-output+input:multichannel-input", N_("Multichannel Duplex") }, { "output:unknown-stereo+input:unknown-stereo", N_("Stereo Duplex") }, @@ -5159,6 +5153,8 @@ void pa_alsa_profile_set_probe( pa_hashmap_free(used_paths); pa_xfree(probe_order); + profile_set_set_availability_groups(ps); + ps->probed = true; } diff --git a/spa/plugins/alsa/acp/alsa-util.c b/spa/plugins/alsa/acp/alsa-util.c index 48f553e03..d57251ddd 100644 --- a/spa/plugins/alsa/acp/alsa-util.c +++ b/spa/plugins/alsa/acp/alsa-util.c @@ -1114,7 +1114,7 @@ int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) { } pa_log_warn("Could not recover alsa device from SUSPENDED state, trying to restart PCM"); } - SPA_FALLTHROUGH + /* Fall through */ default: @@ -1172,7 +1172,7 @@ snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa PA_ONCE_BEGIN { char *dn = pa_alsa_get_driver_name_by_pcm(pcm); - pa_log(ngettext("snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu ms).\n" + pa_log_debug(ngettext("snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.", "snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.", @@ -1181,7 +1181,7 @@ snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC), pa_strnull(dn)); pa_xfree(dn); - pa_alsa_dump(PA_LOG_ERROR, pcm); + pa_alsa_dump(PA_LOG_DEBUG, pcm); } PA_ONCE_END; /* Mhmm, let's try not to fail completely */ @@ -1238,7 +1238,7 @@ int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_status_t *status, snd_pcm_sframes PA_ONCE_BEGIN { char *dn = pa_alsa_get_driver_name_by_pcm(pcm); - pa_log(ngettext("snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s%lu ms).\n" + pa_log_debug(ngettext("snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.", "snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.", @@ -1248,7 +1248,7 @@ int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_status_t *status, snd_pcm_sframes (unsigned long) (pa_bytes_to_usec(abs_k, ss) / PA_USEC_PER_MSEC), pa_strnull(dn)); pa_xfree(dn); - pa_alsa_dump(PA_LOG_ERROR, pcm); + pa_alsa_dump(PA_LOG_DEBUG, pcm); } PA_ONCE_END; /* Mhmm, let's try not to fail completely */ @@ -1266,7 +1266,7 @@ int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_status_t *status, snd_pcm_sframes PA_ONCE_BEGIN { char *dn = pa_alsa_get_driver_name_by_pcm(pcm); - pa_log(ngettext("snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu ms).\n" + pa_log_debug(ngettext("snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.", "snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.", @@ -1275,7 +1275,7 @@ int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_status_t *status, snd_pcm_sframes (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC), pa_strnull(dn)); pa_xfree(dn); - pa_alsa_dump(PA_LOG_ERROR, pcm); + pa_alsa_dump(PA_LOG_DEBUG, pcm); } PA_ONCE_END; /* Mhmm, let's try not to fail completely */ @@ -1328,7 +1328,7 @@ int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas k >= pa_bytes_per_second(ss)*10)) PA_ONCE_BEGIN { char *dn = pa_alsa_get_driver_name_by_pcm(pcm); - pa_log(ngettext("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte (%lu ms).\n" + pa_log_debug(ngettext("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte (%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.", "snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.", @@ -1337,7 +1337,7 @@ int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC), pa_strnull(dn)); pa_xfree(dn); - pa_alsa_dump(PA_LOG_ERROR, pcm); + pa_alsa_dump(PA_LOG_DEBUG, pcm); } PA_ONCE_END; return r; diff --git a/spa/plugins/alsa/acp/compat.h b/spa/plugins/alsa/acp/compat.h index e0d418de5..d6c3c4904 100644 --- a/spa/plugins/alsa/acp/compat.h +++ b/spa/plugins/alsa/acp/compat.h @@ -72,6 +72,7 @@ typedef void (*pa_free_cb_t)(void *p); }) #define PA_PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p))) +#define PA_UINT_TO_PTR(u) ((void*) ((uintptr_t) (u))) #include "array.h" #include "llist.h"