diff --git a/spa/plugins/alsa/90-pipewire-alsa.rules b/spa/plugins/alsa/90-pipewire-alsa.rules index 836a31331..d27c63667 100644 --- a/spa/plugins/alsa/90-pipewire-alsa.rules +++ b/spa/plugins/alsa/90-pipewire-alsa.rules @@ -19,6 +19,7 @@ SUBSYSTEM!="sound", GOTO="pulseaudio_end" ACTION!="change", GOTO="pulseaudio_end" KERNEL!="card*", GOTO="pulseaudio_end" SUBSYSTEMS=="usb", GOTO="pulseaudio_check_usb" +SUBSYSTEMS=="pci", GOTO="pulseaudio_check_pci" SUBSYSTEMS=="firewire", GOTO="pulseaudio_firewire_quirk" SUBSYSTEMS=="platform", DRIVERS=="thinkpad_acpi", ENV{PULSE_IGNORE}="1" @@ -121,6 +122,9 @@ ATTRS{idVendor}=="1038", ATTRS{idProduct}=="1730", ENV{PULSE_PROFILE_SET}="usb-g ATTRS{idVendor}=="2f12", ATTRS{idProduct}=="0109", ENV{PULSE_PROFILE_SET}="usb-gaming-headset.conf" # ID 9886:002c is for the Astro A50 Gen4 ATTRS{idVendor}=="9886", ATTRS{idProduct}=="002c", ENV{PULSE_PROFILE_SET}="usb-gaming-headset.conf" +# ID 1532:0520 is for the Razer Kraken Tournament Edition +ATTRS{idVendor}=="1532", ATTRS{idProduct}=="0520", ENV{PULSE_PROFILE_SET}="usb-gaming-headset.conf" + # ID 1038:1250 is for the Arctis 5 # ID 1037:12aa is for the Arctis 5 2019 @@ -143,6 +147,16 @@ ATTRS{idVendor}=="0951", ATTRS{idProduct}=="1703", ENV{ID_ID}="usb-HyperX_Cloud_ GOTO="pulseaudio_end" +LABEL="pulseaudio_check_pci" + +# Creative SoundBlaster Audigy-based cards +# EMU10k2/CA0100/CA0102/CA10200 +ATTRS{vendor}=="0x1102", ATTRS{device}=="0x0004", ENV{PULSE_PROFILE_SET}="audigy.conf" +# CA0108/CA10300 +ATTRS{vendor}=="0x1102", ATTRS{device}=="0x0008", ENV{PULSE_PROFILE_SET}="audigy.conf" + +GOTO="pulseaudio_end" + LABEL="pulseaudio_firewire_quirk" # Focusrite Saffire Pro 10/26 i/o has a quirk to disappear from IEEE 1394 bus when losing connections. diff --git a/spa/plugins/alsa/acp/acp.c b/spa/plugins/alsa/acp/acp.c index 86c49c751..6106bbba8 100644 --- a/spa/plugins/alsa/acp/acp.c +++ b/spa/plugins/alsa/acp/acp.c @@ -1106,6 +1106,7 @@ struct acp_card *acp_card_new(uint32_t index, const struct acp_dict *props) char device_id[16]; bool ignore_dB = false; uint32_t profile_index; + int res; impl = calloc(1, sizeof(*impl)); if (impl == NULL) @@ -1154,15 +1155,22 @@ struct acp_card *acp_card_new(uint32_t index, const struct acp_dict *props) snd_config_update_free_global(); - if (impl->use_ucm && !pa_alsa_ucm_query_profiles(&impl->ucm, card->index)) { + res = impl->use_ucm ? pa_alsa_ucm_query_profiles(&impl->ucm, card->index) : -1; + if (res == -PA_ALSA_ERR_UCM_LINKED) { + res = -ENOENT; + goto error; + } + if (res == 0) { pa_log_info("Found UCM profiles"); impl->profile_set = pa_alsa_ucm_add_profile_set(&impl->ucm, &impl->ucm.default_channel_map); } else { impl->use_ucm = false; impl->profile_set = pa_alsa_profile_set_new(profile_set, &impl->ucm.default_channel_map); } - if (impl->profile_set == NULL) - return NULL; + if (impl->profile_set == NULL) { + res = -ENOTSUP; + goto error; + } impl->profile_set->ignore_dB = ignore_dB; @@ -1197,6 +1205,11 @@ struct acp_card *acp_card_new(uint32_t index, const struct acp_dict *props) init_eld_ctls(impl); return &impl->card; +error: + pa_alsa_refcnt_dec(); + free(impl); + errno = -res; + return NULL; } void acp_card_add_listener(struct acp_card *card, @@ -1209,7 +1222,9 @@ void acp_card_add_listener(struct acp_card *card, void acp_card_destroy(struct acp_card *card) { + pa_card *impl = (pa_card *)card; pa_alsa_refcnt_dec(); + free(impl); } int acp_card_poll_descriptors_count(struct acp_card *card) diff --git a/spa/plugins/alsa/acp/alsa-ucm.c b/spa/plugins/alsa/acp/alsa-ucm.c index 15b96f915..46e3b016a 100644 --- a/spa/plugins/alsa/acp/alsa-ucm.c +++ b/spa/plugins/alsa/acp/alsa-ucm.c @@ -742,13 +742,13 @@ static void append_lost_relationship(pa_alsa_ucm_device *dev) { int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index) { char *card_name; - const char **verb_list; + const char **verb_list, *value; int num_verbs, i, err = 0; /* support multiple card instances, address card directly by index */ card_name = pa_sprintf_malloc("hw:%i", card_index); if (card_name == NULL) - return -ENOMEM; + return -PA_ALSA_ERR_UNSPECIFIED; err = snd_use_case_mgr_open(&ucm->ucm_mgr, card_name); if (err < 0) { /* fallback longname: is UCM available for this card ? */ @@ -756,22 +756,36 @@ int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index) { err = snd_card_get_name(card_index, &card_name); if (err < 0) { pa_log("Card can't get card_name from card_index %d", card_index); + err = -PA_ALSA_ERR_UNSPECIFIED; goto name_fail; } err = snd_use_case_mgr_open(&ucm->ucm_mgr, card_name); if (err < 0) { pa_log_info("UCM not available for card %s", card_name); + err = -PA_ALSA_ERR_UCM_OPEN; goto ucm_mgr_fail; } } + err = snd_use_case_get(ucm->ucm_mgr, "=Linked", &value); + if (err >= 0) { + if (strcasecmp(value, "true") == 0 || strcasecmp(value, "1") == 0) { + free((void *)value); + pa_log_info("Empty (linked) UCM for card %s", card_name); + err = -PA_ALSA_ERR_UCM_LINKED; + goto ucm_verb_fail; + } + free((void *)value); + } + pa_log_info("UCM available for card %s", card_name); /* get a list of all UCM verbs (profiles) for this card */ num_verbs = snd_use_case_verb_list(ucm->ucm_mgr, &verb_list); if (num_verbs < 0) { pa_log("UCM verb list not found for %s", card_name); + err = -PA_ALSA_ERR_UNSPECIFIED; goto ucm_verb_fail; } @@ -791,7 +805,7 @@ int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index) { if (!ucm->verbs) { pa_log("No UCM verb is valid for %s", card_name); - err = -1; + err = -PA_ALSA_ERR_UCM_NO_VERB; } snd_use_case_free_list(verb_list, num_verbs); diff --git a/spa/plugins/alsa/acp/alsa-util.c b/spa/plugins/alsa/acp/alsa-util.c index 0b845b249..82a7c1b67 100644 --- a/spa/plugins/alsa/acp/alsa-util.c +++ b/spa/plugins/alsa/acp/alsa-util.c @@ -1055,6 +1055,293 @@ void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name) { snd_ctl_close(ctl); } + +int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) { + snd_pcm_state_t state; + snd_pcm_hw_params_t *hwparams; + int err; + + pa_assert(pcm); + + if (revents & POLLERR) + pa_log_debug("Got POLLERR from ALSA"); + if (revents & POLLNVAL) + pa_log_warn("Got POLLNVAL from ALSA"); + if (revents & POLLHUP) + pa_log_warn("Got POLLHUP from ALSA"); + if (revents & POLLPRI) + pa_log_warn("Got POLLPRI from ALSA"); + if (revents & POLLIN) + pa_log_debug("Got POLLIN from ALSA"); + if (revents & POLLOUT) + pa_log_debug("Got POLLOUT from ALSA"); + + state = snd_pcm_state(pcm); + pa_log_debug("PCM state is %s", snd_pcm_state_name(state)); + + /* Try to recover from this error */ + + switch (state) { + + case SND_PCM_STATE_DISCONNECTED: + /* Do not try to recover */ + pa_log_info("Device disconnected."); + return -1; + + case SND_PCM_STATE_XRUN: + if ((err = snd_pcm_recover(pcm, -EPIPE, 1)) != 0) { + pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", pa_alsa_strerror(err)); + return -1; + } + break; + + case SND_PCM_STATE_SUSPENDED: + snd_pcm_hw_params_alloca(&hwparams); + + if ((err = snd_pcm_hw_params_any(pcm, hwparams)) < 0) { + pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(err)); + return -1; + } + + if (snd_pcm_hw_params_can_resume(hwparams)) { + /* Retry resume 3 times before giving up, then fallback to restarting the stream. */ + for (int i = 0; i < 3; i++) { + if ((err = snd_pcm_resume(pcm)) == 0) + return 0; + if (err != -EAGAIN) + break; + pa_msleep(25); + } + pa_log_warn("Could not recover alsa device from SUSPENDED state, trying to restart PCM"); + } + /* Fall through */ + + default: + + snd_pcm_drop(pcm); + return 1; + } + + return 0; +} + +pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll) { + int n, err; + struct pollfd *pollfd; + pa_rtpoll_item *item; + + pa_assert(pcm); + + if ((n = snd_pcm_poll_descriptors_count(pcm)) < 0) { + pa_log("snd_pcm_poll_descriptors_count() failed: %s", pa_alsa_strerror(n)); + return NULL; + } + + item = pa_rtpoll_item_new(rtpoll, PA_RTPOLL_NEVER, (unsigned) n); + pollfd = pa_rtpoll_item_get_pollfd(item, NULL); + + if ((err = snd_pcm_poll_descriptors(pcm, pollfd, (unsigned) n)) < 0) { + pa_log("snd_pcm_poll_descriptors() failed: %s", pa_alsa_strerror(err)); + pa_rtpoll_item_free(item); + return NULL; + } + + return item; +} + +snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss) { + snd_pcm_sframes_t n; + size_t k; + + pa_assert(pcm); + pa_assert(hwbuf_size > 0); + pa_assert(ss); + + /* Some ALSA driver expose weird bugs, let's inform the user about + * what is going on */ + + n = snd_pcm_avail(pcm); + + if (n <= 0) + return n; + + k = (size_t) n * pa_frame_size(ss); + + if (PA_UNLIKELY(k >= hwbuf_size * 5 || + 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_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.", + (unsigned long) k), + (unsigned long) k, + (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_ONCE_END; + + /* Mhmm, let's try not to fail completely */ + n = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss)); + } + + return n; +} + +int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_status_t *status, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss, + bool capture) { + ssize_t k; + size_t abs_k; + int err; + snd_pcm_sframes_t avail = 0; +#if (SND_LIB_VERSION >= ((1<<16)|(1<<8)|0)) /* API additions in 1.1.0 */ + snd_pcm_audio_tstamp_config_t tstamp_config; +#endif + + pa_assert(pcm); + pa_assert(delay); + pa_assert(hwbuf_size > 0); + pa_assert(ss); + + /* Some ALSA driver expose weird bugs, let's inform the user about + * what is going on. We're going to get both the avail and delay values so + * that we can compare and check them for capture. + * This is done with snd_pcm_status() which provides + * avail, delay and timestamp values in a single kernel call to improve + * timer-based scheduling */ + +#if (SND_LIB_VERSION >= ((1<<16)|(1<<8)|0)) /* API additions in 1.1.0 */ + + /* The time stamp configuration needs to be set so that the + * ALSA code will use the internal delay reported by the driver. + * The time stamp configuration was introduced in alsa version 1.1.0. */ + tstamp_config.type_requested = 1; /* ALSA default time stamp type */ + tstamp_config.report_delay = 1; + snd_pcm_status_set_audio_htstamp_config(status, &tstamp_config); +#endif + + if ((err = snd_pcm_status(pcm, status)) < 0) + return err; + + avail = snd_pcm_status_get_avail(status); + *delay = snd_pcm_status_get_delay(status); + + k = (ssize_t) *delay * (ssize_t) pa_frame_size(ss); + + abs_k = k >= 0 ? (size_t) k : (size_t) -k; + + if (PA_UNLIKELY(abs_k >= hwbuf_size * 5 || + abs_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_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.", + (signed long) k), + (signed long) k, + k < 0 ? "-" : "", + (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_ONCE_END; + + /* Mhmm, let's try not to fail completely */ + if (k < 0) + *delay = -(snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss)); + else + *delay = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss)); + } + + if (capture) { + abs_k = (size_t) avail * pa_frame_size(ss); + + if (PA_UNLIKELY(abs_k >= hwbuf_size * 5 || + abs_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_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.", + (unsigned long) k), + (unsigned long) k, + (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_ONCE_END; + + /* Mhmm, let's try not to fail completely */ + avail = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss)); + } + + if (PA_UNLIKELY(*delay < avail)) { + PA_ONCE_BEGIN { + char *dn = pa_alsa_get_driver_name_by_pcm(pcm); + pa_log(_("snd_pcm_avail_delay() returned strange values: delay %lu is less than avail %lu.\n" + "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."), + (unsigned long) *delay, + (unsigned long) avail, + pa_strnull(dn)); + pa_xfree(dn); + pa_alsa_dump(PA_LOG_ERROR, pcm); + } PA_ONCE_END; + + /* try to fixup */ + *delay = avail; + } + } + + return 0; +} + +int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames, size_t hwbuf_size, const pa_sample_spec *ss) { + int r; + snd_pcm_uframes_t before; + size_t k; + + pa_assert(pcm); + pa_assert(areas); + pa_assert(offset); + pa_assert(frames); + pa_assert(hwbuf_size > 0); + pa_assert(ss); + + before = *frames; + + r = snd_pcm_mmap_begin(pcm, areas, offset, frames); + + if (r < 0) + return r; + + k = (size_t) *frames * pa_frame_size(ss); + + if (PA_UNLIKELY(*frames > before || + k >= hwbuf_size * 3 || + 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" + "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.", + (unsigned long) k), + (unsigned long) k, + (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_ONCE_END; + + return r; +} #endif char *pa_alsa_get_driver_name(int card) { @@ -1112,9 +1399,7 @@ char *pa_alsa_get_reserve_name(const char *device) { return pa_sprintf_malloc("Audio%i", i); } -#endif -#if 0 unsigned int *pa_alsa_get_supported_rates(snd_pcm_t *pcm, unsigned int fallback_rate) { static unsigned int all_rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, @@ -1165,9 +1450,7 @@ unsigned int *pa_alsa_get_supported_rates(snd_pcm_t *pcm, unsigned int fallback_ return rates; } -#endif -#if 0 pa_sample_format_t *pa_alsa_get_supported_formats(snd_pcm_t *pcm, pa_sample_format_t fallback_format) { static const snd_pcm_format_t format_trans_to_pa[] = { [SND_PCM_FORMAT_U8] = PA_SAMPLE_U8, @@ -1507,6 +1790,24 @@ snd_mixer_t *pa_alsa_open_mixer_for_pcm(pa_hashmap *mixers, snd_pcm_t *pcm, bool return NULL; } +#if 0 +void pa_alsa_mixer_set_fdlist(pa_hashmap *mixers, snd_mixer_t *mixer_handle, pa_mainloop_api *ml) +{ + pa_alsa_mixer *pm; + void *state; + + PA_HASHMAP_FOREACH(pm, mixers, state) + if (pm->mixer_handle == mixer_handle) { + pm->used_for_probe_only = false; + if (!pm->fdl) { + pm->fdl = pa_alsa_fdlist_new(); + if (pm->fdl) + pa_alsa_fdlist_set_handle(pm->fdl, pm->mixer_handle, NULL, ml); + } + } +} +#endif + void pa_alsa_mixer_free(pa_alsa_mixer *mixer) { if (mixer->mixer_handle) diff --git a/spa/plugins/alsa/acp/alsa-util.h b/spa/plugins/alsa/acp/alsa-util.h index 6e6e79365..609e53c66 100644 --- a/spa/plugins/alsa/acp/alsa-util.h +++ b/spa/plugins/alsa/acp/alsa-util.h @@ -29,6 +29,13 @@ #include "alsa-mixer.h" +enum { + PA_ALSA_ERR_UNSPECIFIED = 1, + PA_ALSA_ERR_UCM_OPEN = 1000, + PA_ALSA_ERR_UCM_NO_VERB = 1001, + PA_ALSA_ERR_UCM_LINKED = 1002 +}; + int pa_alsa_set_hw_params( snd_pcm_t *pcm_handle, pa_sample_spec *ss, /* modified at return */ @@ -120,6 +127,16 @@ void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name); #endif bool pa_alsa_init_description(pa_proplist *p, pa_card *card); +#if 0 +int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents); + +pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll); + +snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss); +int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_status_t *status, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss, bool capture); +int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames, size_t hwbuf_size, const pa_sample_spec *ss); +#endif + char *pa_alsa_get_driver_name(int card); char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm); @@ -143,7 +160,9 @@ snd_mixer_elem_t *pa_alsa_mixer_find_pcm(snd_mixer_t *mixer, const char *name, u snd_mixer_t *pa_alsa_open_mixer(pa_hashmap *mixers, int alsa_card_index, bool probe); snd_mixer_t *pa_alsa_open_mixer_by_name(pa_hashmap *mixers, const char *dev, bool probe); snd_mixer_t *pa_alsa_open_mixer_for_pcm(pa_hashmap *mixers, snd_pcm_t *pcm, bool probe); - +#if 0 +void pa_alsa_mixer_set_fdlist(pa_hashmap *mixers, snd_mixer_t *mixer, pa_mainloop_api *ml); +#endif void pa_alsa_mixer_free(pa_alsa_mixer *mixer); typedef struct pa_hdmi_eld pa_hdmi_eld; diff --git a/spa/plugins/alsa/mixer/profile-sets/audigy.conf b/spa/plugins/alsa/mixer/profile-sets/audigy.conf new file mode 100644 index 000000000..043596e30 --- /dev/null +++ b/spa/plugins/alsa/mixer/profile-sets/audigy.conf @@ -0,0 +1,94 @@ +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, see . + +; Creative Sound Blaster Audigy product line +; +; These are just copies of the mappings we find in default.conf, with the +; small change of making analog-stereo and analog-mono non-fallback mappings. +; This is needed because these cards only support duplex profiles with mono +; inputs, and in the default configuration, with stereo being a fallback +; mapping, the mono mapping is never tried. +; +; See default.conf for an explanation on the directives used here. + +[General] +auto-profiles = yes + +# Based on stereo-fallback +[Mapping analog-stereo] +device-strings = hw:%f +channel-map = front-left,front-right +paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 +paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headphone-mic analog-input-headset-mic +priority = 1 + +# Based on mono-fallback +[Mapping analog-mono] +device-strings = hw:%f +channel-map = mono +paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono +paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headset-mic +priority = 1 + +# The rest of these are identical to what's in default.conf +[Mapping analog-surround-21] +device-strings = surround21:%f +channel-map = front-left,front-right,lfe +paths-output = analog-output analog-output-lineout analog-output-speaker +priority = 13 +direction = output + +[Mapping analog-surround-40] +device-strings = surround40:%f +channel-map = front-left,front-right,rear-left,rear-right +paths-output = analog-output analog-output-lineout analog-output-speaker +priority = 12 +direction = output + +[Mapping analog-surround-41] +device-strings = surround41:%f +channel-map = front-left,front-right,rear-left,rear-right,lfe +paths-output = analog-output analog-output-lineout analog-output-speaker +priority = 13 +direction = output + +[Mapping analog-surround-50] +device-strings = surround50:%f +channel-map = front-left,front-right,rear-left,rear-right,front-center +paths-output = analog-output analog-output-lineout analog-output-speaker +priority = 12 +direction = output + +[Mapping analog-surround-51] +device-strings = surround51:%f +channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe +paths-output = analog-output analog-output-lineout analog-output-speaker +priority = 13 +direction = output + +[Mapping analog-surround-71] +device-strings = surround71:%f +channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right +description = Analog Surround 7.1 +paths-output = analog-output analog-output-lineout analog-output-speaker +priority = 12 +direction = output + +[Mapping iec958-stereo] +device-strings = iec958:%f +channel-map = left,right +paths-input = iec958-stereo-input +paths-output = iec958-stereo-output +priority = 5