diff --git a/alsa-git.patch b/alsa-git.patch index f88de1b..e69de29 100644 --- a/alsa-git.patch +++ b/alsa-git.patch @@ -1,1916 +0,0 @@ -From 81e7923fbfad45b2f353a4d6e3053af51f5f7d0b Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Tue, 15 Jun 2021 23:21:42 +0200 -Subject: [PATCH 01/20] control: empty - fix the static build - -Reported-by: Jan Palus -Fixes: https://github.com/alsa-project/alsa-lib/issues/157 -Signed-off-by: Jaroslav Kysela ---- - src/control/control_empty.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/control/control_empty.c b/src/control/control_empty.c -index 49d1026c..c9b048c1 100644 ---- a/src/control/control_empty.c -+++ b/src/control/control_empty.c -@@ -30,7 +30,7 @@ - - #ifndef PIC - /* entry for static linking */ --const char *_snd_module_ctl_empty = ""; -+const char *_snd_module_control_empty = ""; - #endif - - /*! \page control_plugins --- -2.31.1 - - -From 5089358aa99d698bd846b05c1890a09613d740b3 Mon Sep 17 00:00:00 2001 -From: Takashi Iwai -Date: Thu, 17 Jun 2021 10:20:25 +0200 -Subject: [PATCH 02/20] pcm: rate: Refactoring temporary buffer allocations - -Introduce common helpers to allocate and release the temporary buffers -and the associated snd_pcm_channel. Now two allocated objects are -used instead of one malloc to be split. - -Also, change the snd_pcm_channel set up to be in interleaved mode. -This will be necessary in the following change in the rate plugin. - -Signed-off-by: Takashi Iwai ---- - src/pcm/pcm_rate.c | 80 ++++++++++++++++++++++++++++------------------ - 1 file changed, 49 insertions(+), 31 deletions(-) - -diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c -index 770aafea..1e996134 100644 ---- a/src/pcm/pcm_rate.c -+++ b/src/pcm/pcm_rate.c -@@ -76,6 +76,45 @@ struct _snd_pcm_rate { - - #endif /* DOC_HIDDEN */ - -+/* allocate a channel area and a temporary buffer for the given size */ -+static snd_pcm_channel_area_t * -+rate_alloc_tmp_buf(snd_pcm_rate_t *rate, snd_pcm_format_t format, -+ unsigned int channels, unsigned int frames) -+{ -+ snd_pcm_channel_area_t *ap; -+ int width = snd_pcm_format_physical_width(format); -+ int i; -+ -+ ap = malloc(sizeof(*ap) * channels); -+ if (!ap) -+ return NULL; -+ ap->addr = malloc(frames * channels * width / 8); -+ if (!ap->addr) { -+ free(ap); -+ return NULL; -+ } -+ -+ /* set up in interleaved format */ -+ for (i = 0; i < channels; i++) { -+ ap[i].addr = ap[0].addr + (i * width) / 8; -+ ap[i].first = 0; -+ ap[i].step = width * channels; -+ } -+ -+ return ap; -+} -+ -+static void rate_free_tmp_buf(snd_pcm_channel_area_t **ptr) -+{ -+ snd_pcm_channel_area_t *c = *ptr; -+ -+ if (c) { -+ free(c->addr); -+ free(c); -+ *ptr = NULL; -+ } -+} -+ - static int snd_pcm_rate_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) - { - snd_pcm_rate_t *rate = pcm->private_data; -@@ -286,28 +325,13 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) - if (err < 0) - return err; - -- rate->pareas = malloc(2 * channels * sizeof(*rate->pareas)); -- if (rate->pareas == NULL) -+ rate->pareas = rate_alloc_tmp_buf(rate, cinfo->format, channels, -+ cinfo->period_size); -+ rate->sareas = rate_alloc_tmp_buf(rate, sinfo->format, channels, -+ sinfo->period_size); -+ if (!rate->pareas || !rate->sareas) - goto error; - -- cwidth = snd_pcm_format_physical_width(cinfo->format); -- swidth = snd_pcm_format_physical_width(sinfo->format); -- rate->pareas[0].addr = malloc(((cwidth * channels * cinfo->period_size) / 8) + -- ((swidth * channels * sinfo->period_size) / 8)); -- if (rate->pareas[0].addr == NULL) -- goto error; -- -- rate->sareas = rate->pareas + channels; -- rate->sareas[0].addr = (char *)rate->pareas[0].addr + ((cwidth * channels * cinfo->period_size) / 8); -- for (chn = 0; chn < channels; chn++) { -- rate->pareas[chn].addr = (char *)rate->pareas[0].addr + (cwidth * chn * cinfo->period_size) / 8; -- rate->pareas[chn].first = 0; -- rate->pareas[chn].step = cwidth; -- rate->sareas[chn].addr = (char *)rate->sareas[0].addr + (swidth * chn * sinfo->period_size) / 8; -- rate->sareas[chn].first = 0; -- rate->sareas[chn].step = swidth; -- } -- - if (rate->ops.convert_s16) { - rate->get_idx = snd_pcm_linear_get_index(rate->info.in.format, SND_PCM_FORMAT_S16); - rate->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, rate->info.out.format); -@@ -322,11 +346,8 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) - return 0; - - error: -- if (rate->pareas) { -- free(rate->pareas[0].addr); -- free(rate->pareas); -- rate->pareas = NULL; -- } -+ rate_free_tmp_buf(&rate->pareas); -+ rate_free_tmp_buf(&rate->sareas); - if (rate->ops.free) - rate->ops.free(rate->obj); - return -ENOMEM; -@@ -335,12 +356,9 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) - static int snd_pcm_rate_hw_free(snd_pcm_t *pcm) - { - snd_pcm_rate_t *rate = pcm->private_data; -- if (rate->pareas) { -- free(rate->pareas[0].addr); -- free(rate->pareas); -- rate->pareas = NULL; -- rate->sareas = NULL; -- } -+ -+ rate_free_tmp_buf(&rate->pareas); -+ rate_free_tmp_buf(&rate->sareas); - if (rate->ops.free) - rate->ops.free(rate->obj); - free(rate->src_buf); --- -2.31.1 - - -From 119d9c1678b1193f8b969a6483cae1f7bf95e609 Mon Sep 17 00:00:00 2001 -From: Takashi Iwai -Date: Thu, 17 Jun 2021 10:03:17 +0200 -Subject: [PATCH 03/20] pcm: rate: Improve the support multiple formats - -This patch extends the PCM rate plugin for allowing its converter -plugin to deal with multiple formats. Currently, the converter plugin -is allowed to take different formats only when convert callback is -defined. And for this way (so far only the standard linear rate -plugin does), all linear formats have to be handled, and it's -cumbersome. - -OTOH, most other rate plugins are implemented with convert_s16 -callback, which accepts only S16 format. This is often not ideal -because many converter engines can handle 32bit formats. Also, the -target format is often 32bit format, hence this would require -additional conversion even if the converter engine can output 32bit -natively. - -In this patch, for addressing the problems above, the rate plugin API -is extended in the following way: - -- The new get_supported_formats callback is added; this stores the bit - masks of the supported input and output formats, as well as the - behavior flags. Currently only linear formats are allowed. -- When the plugin accepts only the interleaved stream, set - SND_PCM_RATE_FLAG_INTERLEAVED flag bit. Otherwise the code has to - handle snd_pcm_channel_area at each call. -- When both input and output formats have to be identical, pass - SND_PCM_RATE_FLAG_SYNC_FORMATS flag bit. -- When the converter wants to process different formats, use convert - callback instead of convert_s16. You can put both in the ops for - compatibility, too. - The input and output formats are found in the info argument of init - callback. -- Now the PCM rate plugin core will skip the temporary buffer - allocation and conversions for pre- and post-process if not needed - (i.e. matching with the requested input or output format). - -The rate plugin API version is bumped to 0x010003. - -Signed-off-by: Takashi Iwai ---- - include/pcm_rate.h | 36 ++++- - src/pcm/pcm_rate.c | 358 +++++++++++++++++++++++++++------------------ - 2 files changed, 251 insertions(+), 143 deletions(-) - -diff --git a/include/pcm_rate.h b/include/pcm_rate.h -index 4171fb9d..48473ed4 100644 ---- a/include/pcm_rate.h -+++ b/include/pcm_rate.h -@@ -38,7 +38,7 @@ extern "C" { - /** - * Protocol version - */ --#define SND_PCM_RATE_PLUGIN_VERSION 0x010002 -+#define SND_PCM_RATE_PLUGIN_VERSION 0x010003 - - /** hw_params information for a single side */ - typedef struct snd_pcm_rate_side_info { -@@ -55,6 +55,11 @@ typedef struct snd_pcm_rate_info { - unsigned int channels; - } snd_pcm_rate_info_t; - -+enum { -+ SND_PCM_RATE_FLAG_INTERLEAVED = (1U << 0), /** only interleaved format */ -+ SND_PCM_RATE_FLAG_SYNC_FORMATS = (1U << 1), /** both input and output formats have to be identical */ -+}; -+ - /** Callback table of rate-converter */ - typedef struct snd_pcm_rate_ops { - /** -@@ -114,6 +119,13 @@ typedef struct snd_pcm_rate_ops { - * new ops since version 0x010002 - */ - void (*dump)(void *obj, snd_output_t *out); -+ /** -+ * get the supported input and output formats (optional); -+ * new ops since version 0x010003 -+ */ -+ int (*get_supported_formats)(void *obj, uint64_t *in_formats, -+ uint64_t *out_formats, -+ unsigned int *flags); - } snd_pcm_rate_ops_t; - - /** open function type */ -@@ -147,6 +159,28 @@ typedef struct snd_pcm_rate_old_ops { - snd_pcm_uframes_t (*input_frames)(void *obj, snd_pcm_uframes_t frames); - snd_pcm_uframes_t (*output_frames)(void *obj, snd_pcm_uframes_t frames); - } snd_pcm_rate_old_ops_t; -+ -+/* old rate_ops for protocol version 0x010002 */ -+typedef struct snd_pcm_rate_v2_ops { -+ void (*close)(void *obj); -+ int (*init)(void *obj, snd_pcm_rate_info_t *info); -+ void (*free)(void *obj); -+ void (*reset)(void *obj); -+ int (*adjust_pitch)(void *obj, snd_pcm_rate_info_t *info); -+ void (*convert)(void *obj, -+ const snd_pcm_channel_area_t *dst_areas, -+ snd_pcm_uframes_t dst_offset, unsigned int dst_frames, -+ const snd_pcm_channel_area_t *src_areas, -+ snd_pcm_uframes_t src_offset, unsigned int src_frames); -+ void (*convert_s16)(void *obj, int16_t *dst, unsigned int dst_frames, -+ const int16_t *src, unsigned int src_frames); -+ snd_pcm_uframes_t (*input_frames)(void *obj, snd_pcm_uframes_t frames); -+ snd_pcm_uframes_t (*output_frames)(void *obj, snd_pcm_uframes_t frames); -+ unsigned int version; -+ int (*get_supported_rates)(void *obj, unsigned int *rate_min, -+ unsigned int *rate_max); -+ void (*dump)(void *obj, snd_output_t *out); -+} snd_pcm_rate_v2_ops_t; - #endif - - #ifdef __cplusplus -diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c -index 1e996134..13111d29 100644 ---- a/src/pcm/pcm_rate.c -+++ b/src/pcm/pcm_rate.c -@@ -62,18 +62,22 @@ struct _snd_pcm_rate { - void *open_func; - void *obj; - snd_pcm_rate_ops_t ops; -- unsigned int get_idx; -- unsigned int put_idx; -- int16_t *src_buf; -- int16_t *dst_buf; -+ unsigned int src_conv_idx; -+ unsigned int dst_conv_idx; -+ snd_pcm_channel_area_t *src_buf; -+ snd_pcm_channel_area_t *dst_buf; - int start_pending; /* start is triggered but not commited to slave */ - snd_htimestamp_t trigger_tstamp; - unsigned int plugin_version; - unsigned int rate_min, rate_max; -+ snd_pcm_format_t orig_in_format; -+ snd_pcm_format_t orig_out_format; -+ uint64_t in_formats; -+ uint64_t out_formats; -+ unsigned int format_flags; - }; - - #define SND_PCM_RATE_PLUGIN_VERSION_OLD 0x010001 /* old rate plugin */ -- - #endif /* DOC_HIDDEN */ - - /* allocate a channel area and a temporary buffer for the given size */ -@@ -274,12 +278,84 @@ static int snd_pcm_rate_hw_refine(snd_pcm_t *pcm, - snd_pcm_generic_hw_refine); - } - -+/* evaluate the best matching available format to the given format */ -+static int get_best_format(uint64_t mask, snd_pcm_format_t orig) -+{ -+ int pwidth = snd_pcm_format_physical_width(orig); -+ int width = snd_pcm_format_width(orig); -+ int signd = snd_pcm_format_signed(orig); -+ int best_score = -1; -+ int match = -1; -+ int f, score; -+ -+ for (f = 0; f <= SND_PCM_FORMAT_LAST; f++) { -+ if (!(mask & (1ULL << f))) -+ continue; -+ score = 0; -+ if (snd_pcm_format_linear(f)) { -+ if (snd_pcm_format_physical_width(f) == pwidth) -+ score++; -+ if (snd_pcm_format_physical_width(f) >= pwidth) -+ score++; -+ if (snd_pcm_format_width(f) == width) -+ score++; -+ if (snd_pcm_format_signed(f) == signd) -+ score++; -+ } -+ if (score > best_score) { -+ match = f; -+ best_score = score; -+ } -+ } -+ -+ return match; -+} -+ -+/* set up the input and output formats from the available lists */ -+static int choose_preferred_format(snd_pcm_rate_t *rate) -+{ -+ uint64_t in_mask = rate->in_formats; -+ uint64_t out_mask = rate->out_formats; -+ int in, out; -+ -+ if (!in_mask || !out_mask) -+ return 0; -+ -+ if (rate->orig_in_format == rate->orig_out_format) -+ if (in_mask & out_mask & (1ULL << rate->orig_in_format)) -+ return 0; /* nothing changed */ -+ -+ repeat: -+ in = get_best_format(in_mask, rate->orig_in_format); -+ out = get_best_format(out_mask, rate->orig_out_format); -+ if (in < 0 || out < 0) -+ return -ENOENT; -+ -+ if ((rate->format_flags & SND_PCM_RATE_FLAG_SYNC_FORMATS) && -+ in != out) { -+ if (out_mask & (1ULL << in)) -+ out = in; -+ else if (in_mask & (1ULL << out)) -+ in = out; -+ else { -+ in_mask &= ~(1ULL << in); -+ out_mask &= ~(1ULL << out); -+ goto repeat; -+ } -+ } -+ -+ rate->info.in.format = in; -+ rate->info.out.format = out; -+ return 0; -+} -+ - static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) - { - snd_pcm_rate_t *rate = pcm->private_data; - snd_pcm_t *slave = rate->gen.slave; - snd_pcm_rate_side_info_t *sinfo, *cinfo; -- unsigned int channels, cwidth, swidth, chn; -+ unsigned int channels, cwidth, swidth, chn, acc; -+ int need_src_buf, need_dst_buf; - int err = snd_pcm_hw_params_slave(pcm, params, - snd_pcm_rate_hw_refine_cchange, - snd_pcm_rate_hw_refine_sprepare, -@@ -308,6 +384,9 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) - if (err < 0) - return err; - err = INTERNAL(snd_pcm_hw_params_get_channels)(params, &channels); -+ if (err < 0) -+ return err; -+ err = INTERNAL(snd_pcm_hw_params_get_access)(params, &acc); - if (err < 0) - return err; - -@@ -321,36 +400,80 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) - SNDMSG("rate plugin already in use"); - return -EBUSY; - } -- err = rate->ops.init(rate->obj, &rate->info); -- if (err < 0) -- return err; - - rate->pareas = rate_alloc_tmp_buf(rate, cinfo->format, channels, - cinfo->period_size); - rate->sareas = rate_alloc_tmp_buf(rate, sinfo->format, channels, - sinfo->period_size); -- if (!rate->pareas || !rate->sareas) -- goto error; -- -- if (rate->ops.convert_s16) { -- rate->get_idx = snd_pcm_linear_get_index(rate->info.in.format, SND_PCM_FORMAT_S16); -- rate->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, rate->info.out.format); -- free(rate->src_buf); -- rate->src_buf = malloc(channels * rate->info.in.period_size * 2); -- free(rate->dst_buf); -- rate->dst_buf = malloc(channels * rate->info.out.period_size * 2); -- if (! rate->src_buf || ! rate->dst_buf) -+ if (!rate->pareas || !rate->sareas) { -+ err = -ENOMEM; -+ goto error_pareas; -+ } -+ -+ rate->orig_in_format = rate->info.in.format; -+ rate->orig_out_format = rate->info.out.format; -+ if (choose_preferred_format(rate) < 0) { -+ SNDERR("No matching format in rate plugin"); -+ err = -EINVAL; -+ goto error_pareas; -+ } -+ -+ err = rate->ops.init(rate->obj, &rate->info); -+ if (err < 0) -+ goto error_init; -+ -+ rate_free_tmp_buf(&rate->src_buf); -+ rate_free_tmp_buf(&rate->dst_buf); -+ -+ need_src_buf = need_dst_buf = 0; -+ -+ if ((rate->format_flags & SND_PCM_RATE_FLAG_INTERLEAVED) && -+ !(acc == SND_PCM_ACCESS_MMAP_INTERLEAVED || -+ acc == SND_PCM_ACCESS_RW_INTERLEAVED)) { -+ need_src_buf = need_dst_buf = 1; -+ } else { -+ if (rate->orig_in_format != rate->info.in.format) -+ need_src_buf = 1; -+ if (rate->orig_out_format != rate->info.out.format) -+ need_dst_buf = 1; -+ } -+ -+ if (need_src_buf) { -+ rate->src_conv_idx = -+ snd_pcm_linear_convert_index(rate->orig_in_format, -+ rate->info.in.format); -+ rate->src_buf = rate_alloc_tmp_buf(rate, rate->info.in.format, -+ channels, rate->info.in.period_size); -+ if (!rate->src_buf) { -+ err = -ENOMEM; - goto error; -+ } -+ } -+ -+ if (need_dst_buf) { -+ rate->dst_conv_idx = -+ snd_pcm_linear_convert_index(rate->info.out.format, -+ rate->orig_out_format); -+ rate->dst_buf = rate_alloc_tmp_buf(rate, rate->info.out.format, -+ channels, rate->info.out.period_size); -+ if (!rate->dst_buf) { -+ err = -ENOMEM; -+ goto error; -+ } - } - - return 0; - - error: -- rate_free_tmp_buf(&rate->pareas); -- rate_free_tmp_buf(&rate->sareas); -+ rate_free_tmp_buf(&rate->src_buf); -+ rate_free_tmp_buf(&rate->dst_buf); -+ error_init: - if (rate->ops.free) - rate->ops.free(rate->obj); -- return -ENOMEM; -+ error_pareas: -+ rate_free_tmp_buf(&rate->pareas); -+ rate_free_tmp_buf(&rate->sareas); -+ return err; - } - - static int snd_pcm_rate_hw_free(snd_pcm_t *pcm) -@@ -361,9 +484,8 @@ static int snd_pcm_rate_hw_free(snd_pcm_t *pcm) - rate_free_tmp_buf(&rate->sareas); - if (rate->ops.free) - rate->ops.free(rate->obj); -- free(rate->src_buf); -- free(rate->dst_buf); -- rate->src_buf = rate->dst_buf = NULL; -+ rate_free_tmp_buf(&rate->src_buf); -+ rate_free_tmp_buf(&rate->dst_buf); - return snd_pcm_hw_free(rate->gen.slave); - } - -@@ -444,82 +566,6 @@ static int snd_pcm_rate_init(snd_pcm_t *pcm) - return 0; - } - --static void convert_to_s16(snd_pcm_rate_t *rate, int16_t *buf, -- const snd_pcm_channel_area_t *areas, -- snd_pcm_uframes_t offset, unsigned int frames, -- unsigned int channels) --{ --#ifndef DOC_HIDDEN --#define GET16_LABELS --#include "plugin_ops.h" --#undef GET16_LABELS --#endif /* DOC_HIDDEN */ -- void *get = get16_labels[rate->get_idx]; -- const char *src; -- int16_t sample; -- const char *srcs[channels]; -- int src_step[channels]; -- unsigned int c; -- -- for (c = 0; c < channels; c++) { -- srcs[c] = snd_pcm_channel_area_addr(areas + c, offset); -- src_step[c] = snd_pcm_channel_area_step(areas + c); -- } -- -- while (frames--) { -- for (c = 0; c < channels; c++) { -- src = srcs[c]; -- goto *get; --#ifndef DOC_HIDDEN --#define GET16_END after_get --#include "plugin_ops.h" --#undef GET16_END --#endif /* DOC_HIDDEN */ -- after_get: -- *buf++ = sample; -- srcs[c] += src_step[c]; -- } -- } --} -- --static void convert_from_s16(snd_pcm_rate_t *rate, const int16_t *buf, -- const snd_pcm_channel_area_t *areas, -- snd_pcm_uframes_t offset, unsigned int frames, -- unsigned int channels) --{ --#ifndef DOC_HIDDEN --#define PUT16_LABELS --#include "plugin_ops.h" --#undef PUT16_LABELS --#endif /* DOC_HIDDEN */ -- void *put = put16_labels[rate->put_idx]; -- char *dst; -- int16_t sample; -- char *dsts[channels]; -- int dst_step[channels]; -- unsigned int c; -- -- for (c = 0; c < channels; c++) { -- dsts[c] = snd_pcm_channel_area_addr(areas + c, offset); -- dst_step[c] = snd_pcm_channel_area_step(areas + c); -- } -- -- while (frames--) { -- for (c = 0; c < channels; c++) { -- dst = dsts[c]; -- sample = *buf++; -- goto *put; --#ifndef DOC_HIDDEN --#define PUT16_END after_put --#include "plugin_ops.h" --#undef PUT16_END --#endif /* DOC_HIDDEN */ -- after_put: -- dsts[c] += dst_step[c]; -- } -- } --} -- - static void do_convert(const snd_pcm_channel_area_t *dst_areas, - snd_pcm_uframes_t dst_offset, unsigned int dst_frames, - const snd_pcm_channel_area_t *src_areas, -@@ -527,28 +573,40 @@ static void do_convert(const snd_pcm_channel_area_t *dst_areas, - unsigned int channels, - snd_pcm_rate_t *rate) - { -- if (rate->ops.convert_s16) { -- const int16_t *src; -- int16_t *dst; -- if (! rate->src_buf) -- src = (int16_t *)src_areas->addr + src_offset * channels; -- else { -- convert_to_s16(rate, rate->src_buf, src_areas, src_offset, -- src_frames, channels); -- src = rate->src_buf; -- } -- if (! rate->dst_buf) -- dst = (int16_t *)dst_areas->addr + dst_offset * channels; -- else -- dst = rate->dst_buf; -- rate->ops.convert_s16(rate->obj, dst, dst_frames, src, src_frames); -- if (dst == rate->dst_buf) -- convert_from_s16(rate, rate->dst_buf, dst_areas, dst_offset, -- dst_frames, channels); -+ const snd_pcm_channel_area_t *out_areas; -+ snd_pcm_uframes_t out_offset; -+ -+ if (rate->dst_buf) { -+ out_areas = rate->dst_buf; -+ out_offset = 0; - } else { -- rate->ops.convert(rate->obj, dst_areas, dst_offset, dst_frames, -- src_areas, src_offset, src_frames); -+ out_areas = dst_areas; -+ out_offset = dst_offset; -+ } -+ -+ if (rate->src_buf) { -+ snd_pcm_linear_convert(rate->src_buf, 0, -+ src_areas, src_offset, -+ channels, src_frames, -+ rate->src_conv_idx); -+ src_areas = rate->src_buf; -+ src_offset = 0; - } -+ -+ if (rate->ops.convert) -+ rate->ops.convert(rate->obj, out_areas, out_offset, dst_frames, -+ src_areas, src_offset, src_frames); -+ else -+ rate->ops.convert_s16(rate->obj, -+ snd_pcm_channel_area_addr(out_areas, out_offset), -+ dst_frames, -+ snd_pcm_channel_area_addr(src_areas, src_offset), -+ src_frames); -+ if (rate->dst_buf) -+ snd_pcm_linear_convert(dst_areas, dst_offset, -+ rate->dst_buf, 0, -+ channels, dst_frames, -+ rate->dst_conv_idx); - } - - static inline void -@@ -1276,6 +1334,30 @@ const snd_config_t *snd_pcm_rate_get_default_converter(snd_config_t *root) - return NULL; - } - -+static void rate_initial_setup(snd_pcm_rate_t *rate) -+{ -+ if (rate->plugin_version == SND_PCM_RATE_PLUGIN_VERSION) -+ rate->plugin_version = rate->ops.version; -+ -+ if (rate->plugin_version >= 0x010002 && -+ rate->ops.get_supported_rates) -+ rate->ops.get_supported_rates(rate->obj, -+ &rate->rate_min, -+ &rate->rate_max); -+ -+ if (rate->plugin_version >= 0x010003 && -+ rate->ops.get_supported_formats) { -+ rate->ops.get_supported_formats(rate->obj, -+ &rate->in_formats, -+ &rate->out_formats, -+ &rate->format_flags); -+ } else if (!rate->ops.convert && rate->ops.convert_s16) { -+ rate->in_formats = rate->out_formats = -+ 1ULL << SND_PCM_FORMAT_S16; -+ rate->format_flags = SND_PCM_RATE_FLAG_INTERLEAVED; -+ } -+} -+ - #ifdef PIC - static int is_builtin_plugin(const char *type) - { -@@ -1301,20 +1383,11 @@ static int rate_open_func(snd_pcm_rate_t *rate, const char *type, const snd_conf - lib = lib_name; - } - -- rate->rate_min = SND_PCM_PLUGIN_RATE_MIN; -- rate->rate_max = SND_PCM_PLUGIN_RATE_MAX; -- rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION; -- - open_conf_func = snd_dlobj_cache_get(lib, open_conf_name, NULL, verbose && converter_conf != NULL); - if (open_conf_func) { - err = open_conf_func(SND_PCM_RATE_PLUGIN_VERSION, - &rate->obj, &rate->ops, converter_conf); - if (!err) { -- rate->plugin_version = rate->ops.version; -- if (rate->ops.get_supported_rates) -- rate->ops.get_supported_rates(rate->obj, -- &rate->rate_min, -- &rate->rate_max); - rate->open_func = open_conf_func; - return 0; - } else { -@@ -1330,23 +1403,18 @@ static int rate_open_func(snd_pcm_rate_t *rate, const char *type, const snd_conf - rate->open_func = open_func; - - err = open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops); -- if (!err) { -- rate->plugin_version = rate->ops.version; -- if (rate->ops.get_supported_rates) -- rate->ops.get_supported_rates(rate->obj, -- &rate->rate_min, -- &rate->rate_max); -+ if (!err) - return 0; -- } - - /* try to open with the old protocol version */ - rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION_OLD; - err = open_func(SND_PCM_RATE_PLUGIN_VERSION_OLD, - &rate->obj, &rate->ops); -- if (err) { -- snd_dlobj_cache_put(open_func); -- rate->open_func = NULL; -- } -+ if (!err) -+ return 0; -+ -+ snd_dlobj_cache_put(open_func); -+ rate->open_func = NULL; - return err; - } - #endif -@@ -1417,6 +1485,10 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, - rate->srate = srate; - rate->sformat = sformat; - -+ rate->rate_min = SND_PCM_PLUGIN_RATE_MIN; -+ rate->rate_max = SND_PCM_PLUGIN_RATE_MAX; -+ rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION; -+ - err = snd_pcm_new(&pcm, SND_PCM_TYPE_RATE, name, slave->stream, slave->mode); - if (err < 0) { - free(rate); -@@ -1496,6 +1568,8 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, - return err; - } - -+ rate_initial_setup(rate); -+ - pcm->ops = &snd_pcm_rate_ops; - pcm->fast_ops = &snd_pcm_rate_fast_ops; - pcm->private_data = rate; --- -2.31.1 - - -From 3f737a2a2c8d20e78dea3ea836997f9d74f602a0 Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Fri, 18 Jun 2021 11:35:30 +0200 -Subject: [PATCH 04/20] pcm: improve docs for snd_pcm_sw_params_get_avail_min() - and snd_pcm_status_get_avail_max() - -Fixes: https://github.com/alsa-project/alsa-lib/issues/44 -Signed-off-by: Jaroslav Kysela ---- - src/pcm/pcm.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c -index 09df0f12..892abf98 100644 ---- a/src/pcm/pcm.c -+++ b/src/pcm/pcm.c -@@ -6500,6 +6500,9 @@ int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, - * \param params Software configuration container - * \param val returned minimum available frames to consider PCM ready - * \return 0 otherwise a negative error code -+ * -+ * This is a threshold value when the PCM stream is considered as ready for -+ * another read/write operation or poll event. - */ - #ifndef DOXYGEN - EXPORT_SYMBOL int INTERNAL(snd_pcm_sw_params_get_avail_min)(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) -@@ -6960,6 +6963,8 @@ snd_pcm_uframes_t snd_pcm_status_get_avail(const snd_pcm_status_t *obj) - /** - * \brief Get maximum number of frames available from a PCM status container after last #snd_pcm_status call - * \return Maximum number of frames ready to be read/written -+ * -+ * This value returns the peak for the available frames between #snd_pcm_status calls. - */ - snd_pcm_uframes_t snd_pcm_status_get_avail_max(const snd_pcm_status_t *obj) - { --- -2.31.1 - - -From 212c6c18c4317af48c007a0866efc029b9c3a593 Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Mon, 21 Jun 2021 09:23:02 +0200 -Subject: [PATCH 05/20] pcm: dmix - use pcm_frame_diff() in - snd_pcm_dmix_sync_ptr0() - -Signed-off-by: Jaroslav Kysela ---- - src/pcm/pcm_dmix.c | 6 +----- - 1 file changed, 1 insertion(+), 5 deletions(-) - -diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c -index 608593f1..0d0d0bff 100644 ---- a/src/pcm/pcm_dmix.c -+++ b/src/pcm/pcm_dmix.c -@@ -393,17 +393,13 @@ static int snd_pcm_dmix_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr - - old_slave_hw_ptr = dmix->slave_hw_ptr; - dmix->slave_hw_ptr = slave_hw_ptr; -- diff = slave_hw_ptr - old_slave_hw_ptr; -+ diff = pcm_frame_diff(slave_hw_ptr, old_slave_hw_ptr, dmix->slave_boundary); - if (diff == 0) /* fast path */ - return 0; - if (dmix->state != SND_PCM_STATE_RUNNING && - dmix->state != SND_PCM_STATE_DRAINING) - /* not really started yet - don't update hw_ptr */ - return 0; -- if (diff < 0) { -- slave_hw_ptr += dmix->slave_boundary; -- diff = slave_hw_ptr - old_slave_hw_ptr; -- } - dmix->hw_ptr += diff; - dmix->hw_ptr %= pcm->boundary; - if (pcm->stop_threshold >= pcm->boundary) /* don't care */ --- -2.31.1 - - -From dd609ef9684987d3ca61d5c5cc3c77589ff9c29f Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Mon, 21 Jun 2021 09:28:41 +0200 -Subject: [PATCH 06/20] pcm: direct plugins - fix hw_ptr in the status callback - -The parent hw_ptr may be in another range (boundary limit). -Set the correct value for the caller. - -BugLink: https://github.com/alsa-project/alsa-lib/issues/155 -Signed-off-by: Jaroslav Kysela ---- - src/pcm/pcm_dmix.c | 1 + - src/pcm/pcm_dshare.c | 1 + - src/pcm/pcm_dsnoop.c | 1 + - 3 files changed, 3 insertions(+) - -diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c -index 0d0d0bff..94dbb1e0 100644 ---- a/src/pcm/pcm_dmix.c -+++ b/src/pcm/pcm_dmix.c -@@ -491,6 +491,7 @@ static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status) - } - - status->state = snd_pcm_dmix_state(pcm); -+ status->hw_ptr = *pcm->hw.ptr; /* boundary may be different */ - status->appl_ptr = *pcm->appl.ptr; /* slave PCM doesn't set appl_ptr */ - status->trigger_tstamp = dmix->trigger_tstamp; - status->avail = snd_pcm_mmap_playback_avail(pcm); -diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c -index a918512b..01814dc8 100644 ---- a/src/pcm/pcm_dshare.c -+++ b/src/pcm/pcm_dshare.c -@@ -243,6 +243,7 @@ static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status) - break; - } - status->state = snd_pcm_dshare_state(pcm); -+ status->hw_ptr = *pcm->hw.ptr; /* boundary may be different */ - status->appl_ptr = *pcm->appl.ptr; /* slave PCM doesn't set appl_ptr */ - status->trigger_tstamp = dshare->trigger_tstamp; - status->avail = snd_pcm_mmap_playback_avail(pcm); -diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c -index 2c3b9f43..3f28df99 100644 ---- a/src/pcm/pcm_dsnoop.c -+++ b/src/pcm/pcm_dsnoop.c -@@ -193,6 +193,7 @@ static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status) - snd_pcm_status(dsnoop->spcm, status); - state = snd_pcm_state(dsnoop->spcm); - status->state = state == SND_PCM_STATE_RUNNING ? dsnoop->state : state; -+ status->hw_ptr = *pcm->hw.ptr; /* boundary may be different */ - status->appl_ptr = *pcm->appl.ptr; /* slave PCM doesn't set appl_ptr */ - status->trigger_tstamp = dsnoop->trigger_tstamp; - status->avail = snd_pcm_mmap_capture_avail(pcm); --- -2.31.1 - - -From a5e11f9a810391777ea7750f04ba66f9c9e624de Mon Sep 17 00:00:00 2001 -From: Takashi Iwai -Date: Mon, 21 Jun 2021 14:21:26 +0200 -Subject: [PATCH 07/20] pcm: Move snd_pcm_channel_area_addr() and _step() to - public header - -Used in the rate plugins commonly. - -Signed-off-by: Takashi Iwai ---- - include/pcm.h | 23 +++++++++++++++++++++++ - src/pcm/pcm_local.h | 13 ------------- - 2 files changed, 23 insertions(+), 13 deletions(-) - -diff --git a/include/pcm.h b/include/pcm.h -index e300b951..b5a514fa 100644 ---- a/include/pcm.h -+++ b/include/pcm.h -@@ -1173,6 +1173,29 @@ int snd_pcm_areas_copy_wrap(const snd_pcm_channel_area_t *dst_channels, - snd_pcm_uframes_t frames, - const snd_pcm_format_t format); - -+/** -+ * \brief get the address of the given PCM channel area -+ * \param area PCM channel area -+ * \param offset Offset in frames -+ * -+ * Returns the pointer corresponding to the given offset on the channel area. -+ */ -+static inline void *snd_pcm_channel_area_addr(const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset) -+{ -+ return (char *)area->addr + (area->first + area->step * offset) / 8; -+} -+ -+/** -+ * \brief get the step size of the given PCM channel area in bytes -+ * \param area PCM channel area -+ * -+ * Returns the step size in bytes from the given channel area. -+ */ -+static inline unsigned int snd_pcm_channel_area_step(const snd_pcm_channel_area_t *area) -+{ -+ return area->step / 8; -+} -+ - /** \} */ - - /** -diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h -index a63f4be0..6f03365c 100644 ---- a/src/pcm/pcm_local.h -+++ b/src/pcm/pcm_local.h -@@ -632,19 +632,6 @@ static inline snd_pcm_sframes_t snd_pcm_mmap_delay(snd_pcm_t *pcm) - return snd_pcm_mmap_capture_delay(pcm); - } - --static inline void *snd_pcm_channel_area_addr(const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset) --{ -- unsigned int bitofs = area->first + area->step * offset; -- assert(bitofs % 8 == 0); -- return (char *) area->addr + bitofs / 8; --} -- --static inline unsigned int snd_pcm_channel_area_step(const snd_pcm_channel_area_t *area) --{ -- assert(area->step % 8 == 0); -- return area->step / 8; --} -- - static inline snd_pcm_sframes_t _snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) - { - /* lock handled in the callback */ --- -2.31.1 - - -From e0e084659083c2ab75d5c894f24227ea2f67010f Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Mon, 21 Jun 2021 15:14:18 +0200 -Subject: [PATCH 08/20] pcm: direct plugins - fix bad memory access when - channel bindings do not match hw - -Fix and cleanup snd_pcm_direct_check_interleave() function. -Add requested / hardware channel check and use goto when the interleaved - -Fixes: https://github.com/alsa-project/alsa-lib/issues/117 -Signed-off-by: Jaroslav Kysela ---- - src/pcm/pcm_direct.c | 40 +++++++++++++++++----------------------- - 1 file changed, 17 insertions(+), 23 deletions(-) - -diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c -index d50503e3..90417b2f 100644 ---- a/src/pcm/pcm_direct.c -+++ b/src/pcm/pcm_direct.c -@@ -1627,43 +1627,37 @@ int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix) - int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm) - { - unsigned int chn, channels; -- int bits, interleaved = 1; -+ int bits; - const snd_pcm_channel_area_t *dst_areas; - const snd_pcm_channel_area_t *src_areas; - - bits = snd_pcm_format_physical_width(pcm->format); - if ((bits % 8) != 0) -- interleaved = 0; -+ goto __nointerleaved; - channels = dmix->channels; -+ if (channels != dmix->spcm->channels) -+ goto __nointerleaved; - dst_areas = snd_pcm_mmap_areas(dmix->spcm); - src_areas = snd_pcm_mmap_areas(pcm); - for (chn = 1; chn < channels; chn++) { -- if (dst_areas[chn-1].addr != dst_areas[chn].addr) { -- interleaved = 0; -- break; -- } -- if (src_areas[chn-1].addr != src_areas[chn].addr) { -- interleaved = 0; -- break; -- } -+ if (dst_areas[chn-1].addr != dst_areas[chn].addr) -+ goto __nointerleaved; -+ if (src_areas[chn-1].addr != src_areas[chn].addr) -+ goto __nointerleaved; - } - for (chn = 0; chn < channels; chn++) { -- if (dmix->bindings && dmix->bindings[chn] != chn) { -- interleaved = 0; -- break; -- } -+ if (dmix->bindings && dmix->bindings[chn] != chn) -+ goto __nointerleaved; - if (dst_areas[chn].first != chn * bits || -- dst_areas[chn].step != channels * bits) { -- interleaved = 0; -- break; -- } -+ dst_areas[chn].step != channels * bits) -+ goto __nointerleaved; - if (src_areas[chn].first != chn * bits || -- src_areas[chn].step != channels * bits) { -- interleaved = 0; -- break; -- } -+ src_areas[chn].step != channels * bits) -+ goto __nointerleaved; - } -- return dmix->interleaved = interleaved; -+ return dmix->interleaved = 1; -+__nointerleaved: -+ return dmix->interleaved = 0; - } - - /* --- -2.31.1 - - -From ccc14ae897d170156f1c2905ea5d18a3295e7b36 Mon Sep 17 00:00:00 2001 -From: "Tanjeff-N. Moos" -Date: Thu, 17 Jun 2021 10:36:38 +0200 -Subject: [PATCH 09/20] control: Add documentation for snd_ctl_card_* and - friends. - -In this patch series, I added a description about control interface -handling and how control interfaces are identified. - -In addition, I added/improved Doxygen documentation for the -snd_ctl_card_info_t type and related corresponding functions, -e.g. snd_ctl_card_info(). I also documented other card-related like -snd_card_next(). - -Along the way I did minor documentation improvements. - -Signed-off-by: Tanjeff-N. Moos -Signed-off-by: Takashi Iwai ---- - include/control.h | 40 +++++++++- - src/control/cards.c | 56 +++++++++----- - src/control/control.c | 175 +++++++++++++++++++++++++++++++----------- - 3 files changed, 202 insertions(+), 69 deletions(-) - -diff --git a/include/control.h b/include/control.h -index ccf906e2..9ebb4905 100644 ---- a/include/control.h -+++ b/include/control.h -@@ -50,7 +50,32 @@ typedef struct snd_aes_iec958 { - unsigned char dig_subframe[4]; /**< AES/IEC958 subframe bits */ - } snd_aes_iec958_t; - --/** CTL card info container */ -+/** \brief CTL card info container. -+ * -+ * This type contains meta information about a sound card, such as the index, -+ * name, longname, etc. -+ * -+ * \par Memory management -+ * -+ * Before using a snd_ctl_card_info_t object, it must be allocated using -+ * snd_ctl_card_info_alloca() or snd_ctl_card_info_malloc(). When using the -+ * latter, it must be freed again using snd_ctl_card_info_free(). -+ * -+ * A card info object can be zeroed out using snd_ctl_card_info_clear(). -+ * -+ * A card info object can be copied to another one using -+ * snd_ctl_card_info_copy(). -+ * -+ * \par Obtaining the Information -+ * -+ * To obtain the card information, it must first be opened using -+ * snd_ctl_open(), and a snd_ctl_card_info_t container must be -+ * allocated. Then, the information can be read using -+ * snd_ctl_card_info_get_card(). -+ * -+ * Thereafter, the card properties can be read using the -+ * snd_ctl_card_info_get_*() functions. -+ */ - typedef struct _snd_ctl_card_info snd_ctl_card_info_t; - - /** CTL element identifier container */ -@@ -442,11 +467,20 @@ void snd_ctl_elem_id_set_name(snd_ctl_elem_id_t *obj, const char *val); - void snd_ctl_elem_id_set_index(snd_ctl_elem_id_t *obj, unsigned int val); - - size_t snd_ctl_card_info_sizeof(void); -+ - /** \hideinitializer -- * \brief allocate an invalid #snd_ctl_card_info_t using standard alloca -- * \param ptr returned pointer -+ * \brief Allocate an invalid #snd_ctl_card_info_t on the stack. -+ * -+ * Allocate space for a card info object on the stack. The allocated -+ * memory need not be freed, because it is on the stack. -+ * -+ * See snd_ctl_card_info_t for details. -+ * -+ * \param ptr Pointer to a snd_ctl_elem_value_t pointer. The address -+ * of the allocated space will returned here. - */ - #define snd_ctl_card_info_alloca(ptr) __snd_alloca(ptr, snd_ctl_card_info) -+ - int snd_ctl_card_info_malloc(snd_ctl_card_info_t **ptr); - void snd_ctl_card_info_free(snd_ctl_card_info_t *obj); - void snd_ctl_card_info_clear(snd_ctl_card_info_t *obj); -diff --git a/src/control/cards.c b/src/control/cards.c -index e57457c2..8226c42d 100644 ---- a/src/control/cards.c -+++ b/src/control/cards.c -@@ -77,8 +77,8 @@ static int snd_card_load1(int card) - - /** - * \brief Try to load the driver for a card. -- * \param card Card number. -- * \return 1 if driver is present, zero if driver is not present -+ * \param card Card index. -+ * \return 1 if driver is present, zero if driver is not present. - */ - int snd_card_load(int card) - { -@@ -86,14 +86,24 @@ int snd_card_load(int card) - } - - /** -- * \brief Try to determine the next card. -- * \param rcard pointer to card number -- * \result zero if success, otherwise a negative error code -+ * \brief Iterate over physical sound cards. -+ * -+ * This function takes the index of a physical sound card and sets it to the -+ * index of the next card. If index is -1, it is set to the index of the first -+ * card. After the last card, the index is set to -1. -+ * -+ * For example, if you have 2 sound cards (with index 0 and 1), the index will -+ * be modified as follows: -+ * -+ * - -1 --> 0 -+ * - 0 --> 1 -+ * - 1 --> -1 -+ * -+ * This does not work for virtual sound cards. - * -- * Tries to determine the next card from given card number. -- * If card number is -1, then the first available card is -- * returned. If the result card number is -1, no more cards -- * are available. -+ * \param rcard Index of current card. The index of the next card is stored -+ * here. -+ * \result zero if success, otherwise a negative error code. - */ - int snd_card_next(int *rcard) - { -@@ -114,13 +124,18 @@ int snd_card_next(int *rcard) - } - - /** -- * \brief Convert card string to an integer value. -- * \param string String containing card identifier -- * \return zero if success, otherwise a negative error code -+ * \brief Convert a card string to the card index. - * -- * The accepted format is an integer value in ASCII representation -- * or the card identifier (the id parameter for sound-card drivers). -- * The control device name like /dev/snd/controlC0 is accepted, too. -+ * This works only for physical sound cards, not for virtual cards. -+ * -+ * \param string A string identifying the card. -+ * \return The index of the card. On error, a a negative error code -+ * is returned. -+ * -+ * The accepted formats for "string" are: -+ * - The index of the card (as listed in /proc/asound/cards), given as string -+ * - The ID of the card (as listed in /proc/asound/cards) -+ * - The control device name (like /dev/snd/controlC0) - */ - int snd_card_get_index(const char *string) - { -@@ -163,8 +178,9 @@ int snd_card_get_index(const char *string) - - /** - * \brief Obtain the card name. -- * \param card Card number -- * \param name Result - card name corresponding to card number -+ * -+ * \param card The index of the card. -+ * \param name Result - card name corresponding to card index. - * \result zero if success, otherwise a negative error code - * - * The value returned in name is allocated with strdup and should be -@@ -193,9 +209,9 @@ int snd_card_get_name(int card, char **name) - - /** - * \brief Obtain the card long name. -- * \param card Card number -- * \param name Result - card long name corresponding to card number -- * \result zero if success, otherwise a negative error code -+ * \param card Index of the card. -+ * \param name Result - card long name corresponding to card index. -+ * \result Zero if success, otherwise a negative error code. - * - * The value returned in name is allocated with strdup and should be - * freed when no longer used. -diff --git a/src/control/control.c b/src/control/control.c -index ed986e54..7cf4decb 100644 ---- a/src/control/control.c -+++ b/src/control/control.c -@@ -33,8 +33,50 @@ -

Control interface is designed to access primitive controls. There is - also an interface for notifying about control and structure changes. - -+ - \section control_general_overview General overview - -+In Alsa, there are physical sound cards, such as USB headsets, and -+virtual sound cards, such as "pulse", which represents the PulseAudio -+Sound system. Each sound card offers a control interface, making its -+settings (e.g. volume knobs) available. The complete list of available -+control interfaces can be obtained using snd_device_name_hint(), -+giving -1 as card index and "ctl" as interface type. Each returned -+NAME hint identifies a control interface. -+ -+Sound cards have an ID (a string), an index (an int, sometimes called -+the "card number"), a name, a longname, a mixername and a "components" -+property. The file /proc/asound/cards lists most of these properties -+for physical sound cards. Virtual sound cards are not listed in that -+file. The format is: -+ -+\verbatim -+index [ID ] Driver - name -+ longname -+\endverbatim -+ -+Note that the mixername and components are not listed. -+ -+ -+\subsection control_cards_id Identifying and Opening Control Interfaces -+ -+To work with a control interface, is must be opened first, using -+snd_ctl_open(). This function takes the interface name. -+ -+For physical sound cards, the control interface can be identified -+using the string "hw:" (e.g. `hw:2`). The NAME hint - which is -+"hw:CARD=" - can also be used. Further, its device file (something -+like `/dev/snd/controlC0`) is also acceptable. Either of them can be -+given to snd_ctl_open(). -+ -+For virtual sound cards, the NAME hint is given to snd_ctl_open(). -+ -+The functions snd_card_get_index(), snd_card_get_name() and -+snd_card_get_longname() can be used to find an identifying property -+when another one is already known. -+ -+\section control_elements Elements -+ - In ALSA control feature, each sound card can have control elements. The elements - are managed according to below model. - -@@ -65,7 +107,7 @@ are managed according to below model. - of userspace applications and drivers in kernel. - - --\section identifying_elements Identifying Elements -+\subsection identifying_elements Identifying Elements - - Each element has the following identifying properties: - -@@ -84,7 +126,7 @@ but in practice this is rare). The numid can change on each boot. - In case of an USB sound card, the numid can also change when it - is reconnected. The short numid is used to reduce the lookup time. - --\section element_lists Element Lists -+\subsection element_lists Element Lists - - An element list can be used to obtain a list of all elements of the - sound card. The list contains generic information (e.g. how many -@@ -93,7 +135,7 @@ elements the card has), and the identifying properties of the elements - element lists. - - --\section working_with_elements Working with Elements -+\subsection working_with_elements Working with Elements - - It is possible to obtain information about an element using the - snd_ctl_elem_info_*() functions. For enums, the allowed values can be -@@ -108,7 +150,7 @@ actual values or settings. It is also possible to get and set the ID - values (such as the numid or the name). - - --\section element_sets Element Sets -+\subsection element_sets Element Sets - - The type of element set is one of integer, integer64, boolean, enumerators, - bytes and IEC958 structure. This indicates the type of value for each member in -@@ -329,10 +371,15 @@ int snd_ctl_subscribe_events(snd_ctl_t *ctl, int subscribe) - - - /** -- * \brief Get card related information -- * \param ctl CTL handle -- * \param info Card info pointer -- * \return 0 on success otherwise a negative error code -+ * \brief Get information about the sound card. -+ * -+ * Obtain information about the sound card previously opened using -+ * snd_ctl_open(). The object "info" must be allocated prior to calling this -+ * function. See snd_ctl_card_info_t for details. -+ * -+ * \param ctl The CTL handle. -+ * \param info The card information is stored here. -+ * \return 0 on success, otherwise a negative error code. - */ - int snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info) - { -@@ -1508,11 +1555,13 @@ int _snd_ctl_open_named_child(snd_ctl_t **pctl, const char *name, - #endif - - /** -- * \brief Opens a CTL -- * \param ctlp Returned CTL handle -- * \param name ASCII identifier of the CTL handle -- * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC) -- * \return 0 on success otherwise a negative error code -+ * \brief Opens a sound card. -+ * -+ * \param ctlp Returned CTL handle. -+ * \param name A string identifying the card (See \ref control_cards_id). -+ * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC). -+ * -+ * \return 0 on success otherwise a negative error code. - */ - int snd_ctl_open(snd_ctl_t **ctlp, const char *name, int mode) - { -@@ -2027,8 +2076,8 @@ void snd_ctl_elem_id_set_index(snd_ctl_elem_id_t *obj, unsigned int val) - } - - /** -- * \brief get size of #snd_ctl_card_info_t -- * \return size in bytes -+ * \brief get size of #snd_ctl_card_info_t. -+ * \return Size in bytes. - */ - size_t snd_ctl_card_info_sizeof() - { -@@ -2036,9 +2085,16 @@ size_t snd_ctl_card_info_sizeof() - } - - /** -- * \brief allocate an invalid #snd_ctl_card_info_t using standard malloc -- * \param ptr returned pointer -- * \return 0 on success otherwise negative error code -+ * \brief Allocate an invalid #snd_ctl_card_info_t on the heap. -+ * -+ * Allocate space for a card info object on the heap. The allocated memory -+ * must be freed using snd_ctl_card_info_free(). -+ * -+ * See snd_ctl_card_info_t for details. -+ * -+ * \param ptr Pointer to a snd_ctl_card_info_t pointer. The address -+ * of the allocated space will be returned here. -+ * \return 0 on success, otherwise a negative error code. - */ - int snd_ctl_card_info_malloc(snd_ctl_card_info_t **ptr) - { -@@ -2050,8 +2106,10 @@ int snd_ctl_card_info_malloc(snd_ctl_card_info_t **ptr) - } - - /** -- * \brief frees a previously allocated #snd_ctl_card_info_t -- * \param obj pointer to object to free -+ * \brief Free an #snd_ctl_card_info_t previously allocated using -+ * snd_ctl_card_info_malloc(). -+ * -+ * \param obj Pointer to the snd_ctl_card_info_t. - */ - void snd_ctl_card_info_free(snd_ctl_card_info_t *obj) - { -@@ -2059,8 +2117,11 @@ void snd_ctl_card_info_free(snd_ctl_card_info_t *obj) - } - - /** -- * \brief clear given #snd_ctl_card_info_t object -- * \param obj pointer to object to clear -+ * \brief Clear given card info object. -+ * -+ * See snd_ctl_elem_value_t for details. -+ * -+ * \param obj Card info object. - */ - void snd_ctl_card_info_clear(snd_ctl_card_info_t *obj) - { -@@ -2068,9 +2129,10 @@ void snd_ctl_card_info_clear(snd_ctl_card_info_t *obj) - } - - /** -- * \brief copy one #snd_ctl_card_info_t to another -- * \param dst pointer to destination -- * \param src pointer to source -+ * \brief Bitwise copy of a #snd_ctl_card_info_t object. -+ * -+ * \param dst Pointer to destination. -+ * \param src Pointer to source. - */ - void snd_ctl_card_info_copy(snd_ctl_card_info_t *dst, const snd_ctl_card_info_t *src) - { -@@ -2079,9 +2141,12 @@ void snd_ctl_card_info_copy(snd_ctl_card_info_t *dst, const snd_ctl_card_info_t - } - - /** -- * \brief Get card number from a CTL card info -- * \param obj CTL card info -- * \return card number -+ * \brief Get the sound card index from the given info object. -+ * -+ * See snd_ctl_card_info_t for more details. -+ * -+ * \param obj The card info object. -+ * \return Sound card index. - */ - int snd_ctl_card_info_get_card(const snd_ctl_card_info_t *obj) - { -@@ -2090,9 +2155,12 @@ int snd_ctl_card_info_get_card(const snd_ctl_card_info_t *obj) - } - - /** -- * \brief Get card identifier from a CTL card info -- * \param obj CTL card info -- * \return card identifier -+ * \brief Get the sound card ID from the given info object. -+ * -+ * See snd_ctl_card_info_t for more details. -+ * -+ * \param obj The card info object. -+ * \return Sound card ID. - */ - const char *snd_ctl_card_info_get_id(const snd_ctl_card_info_t *obj) - { -@@ -2101,9 +2169,12 @@ const char *snd_ctl_card_info_get_id(const snd_ctl_card_info_t *obj) - } - - /** -- * \brief Get card driver name from a CTL card info -- * \param obj CTL card info -- * \return card driver name -+ * \brief Get the sound card driver from the given info object. -+ * -+ * See snd_ctl_card_info_t for more details. -+ * -+ * \param obj The card info object. -+ * \return The sound card driver. - */ - const char *snd_ctl_card_info_get_driver(const snd_ctl_card_info_t *obj) - { -@@ -2112,9 +2183,12 @@ const char *snd_ctl_card_info_get_driver(const snd_ctl_card_info_t *obj) - } - - /** -- * \brief Get card name from a CTL card info -- * \param obj CTL card info -- * \return card name -+ * \brief Get the sound card name from the given info object. -+ * -+ * See snd_ctl_card_info_t for more details. -+ * -+ * \param obj The card info object. -+ * \return Sound card name. - */ - const char *snd_ctl_card_info_get_name(const snd_ctl_card_info_t *obj) - { -@@ -2123,9 +2197,12 @@ const char *snd_ctl_card_info_get_name(const snd_ctl_card_info_t *obj) - } - - /** -- * \brief Get card long name from a CTL card info -- * \param obj CTL card info -- * \return card long name -+ * \brief Get the sound cards long name from the given info object. -+ * -+ * See snd_ctl_card_info_t for more details. -+ * -+ * \param obj The card info object. -+ * \return Sound cards long name. - */ - const char *snd_ctl_card_info_get_longname(const snd_ctl_card_info_t *obj) - { -@@ -2134,9 +2211,12 @@ const char *snd_ctl_card_info_get_longname(const snd_ctl_card_info_t *obj) - } - - /** -- * \brief Get card mixer name from a CTL card info -- * \param obj CTL card info -- * \return card mixer name -+ * \brief Get the sound card mixer name from the given info object. -+ * -+ * See snd_ctl_card_info_t for more details. -+ * -+ * \param obj The card info object. -+ * \return Sound card mixer name. - */ - const char *snd_ctl_card_info_get_mixername(const snd_ctl_card_info_t *obj) - { -@@ -2145,9 +2225,12 @@ const char *snd_ctl_card_info_get_mixername(const snd_ctl_card_info_t *obj) - } - - /** -- * \brief Get card component list from a CTL card info -- * \param obj CTL card info -- * \return card mixer identifier -+ * \brief Get the sound cards "components" property from the given info object. -+ * -+ * See snd_ctl_card_info_t for more details. -+ * -+ * \param obj The card info object. -+ * \return Sound cards "components" property. - */ - const char *snd_ctl_card_info_get_components(const snd_ctl_card_info_t *obj) - { --- -2.31.1 - - -From 7ba3f888d07cafbad04391b915db23408c663dad Mon Sep 17 00:00:00 2001 -From: "Tanjeff-N. Moos" -Date: Thu, 17 Jun 2021 10:36:39 +0200 -Subject: [PATCH 10/20] control: Minor documentation fixes. - -Signed-off-by: Tanjeff-N. Moos -Signed-off-by: Takashi Iwai ---- - include/control.h | 9 +++++++-- - src/control/cards.c | 5 ++++- - src/control/control.c | 2 +- - 3 files changed, 12 insertions(+), 4 deletions(-) - -diff --git a/include/control.h b/include/control.h -index 9ebb4905..e386ecec 100644 ---- a/include/control.h -+++ b/include/control.h -@@ -155,7 +155,7 @@ typedef struct _snd_ctl_elem_list snd_ctl_elem_list_t; - /** CTL element info container */ - typedef struct _snd_ctl_elem_info snd_ctl_elem_info_t; - --/** CTL element value container -+/** CTL element value container. - * - * Contains the value(s) (i.e. members) of a single element. All - * values of a given element are of the same type. -@@ -167,6 +167,11 @@ typedef struct _snd_ctl_elem_info snd_ctl_elem_info_t; - * using the latter, it must be freed again using - * snd_ctl_elem_value_free(). - * -+ * A value object can be zeroed out using snd_ctl_elem_value_clear(). -+ * -+ * A value object can be copied to another one using -+ * snd_ctl_elem_value_copy(). -+ * - * \par Identifier - * - * Then, the ID must be filled. It is sufficient to fill only the -@@ -621,7 +626,7 @@ size_t snd_ctl_elem_value_sizeof(void); - * \brief Allocate an invalid #snd_ctl_elem_value_t on the stack. - * - * Allocate space for a value object on the stack. The allocated -- * memory need not be freed, because is on the stack. -+ * memory need not be freed, because it is on the stack. - * - * See snd_ctl_elem_value_t for details. - * -diff --git a/src/control/cards.c b/src/control/cards.c -index 8226c42d..6145ebcd 100644 ---- a/src/control/cards.c -+++ b/src/control/cards.c -@@ -147,6 +147,7 @@ int snd_card_get_index(const char *string) - return -EINVAL; - if ((isdigit(*string) && *(string + 1) == 0) || - (isdigit(*string) && isdigit(*(string + 1)) && *(string + 2) == 0)) { -+ /* We got an index */ - if (sscanf(string, "%i", &card) != 1) - return -EINVAL; - if (card < 0 || card >= SND_MAX_CARDS) -@@ -156,8 +157,10 @@ int snd_card_get_index(const char *string) - return card; - return err; - } -- if (string[0] == '/') /* device name */ -+ if (string[0] == '/') -+ /* We got a device name */ - return snd_card_load2(string); -+ /* We got in ID */ - for (card = 0; card < SND_MAX_CARDS; card++) { - #ifdef SUPPORT_ALOAD - if (! snd_card_load(card)) -diff --git a/src/control/control.c b/src/control/control.c -index 7cf4decb..91415b51 100644 ---- a/src/control/control.c -+++ b/src/control/control.c -@@ -3127,7 +3127,7 @@ size_t snd_ctl_elem_value_sizeof() - /** - * \brief Allocate an invalid #snd_ctl_elem_value_t on the heap. - * -- * Allocate space for a value object on the head. The allocated memory -+ * Allocate space for a value object on the heap. The allocated memory - * must be freed using snd_ctl_elem_value_free(). - * - * See snd_ctl_elem_value_t for details. --- -2.31.1 - - -From f4f29d42be8b8ad60ea4c5697374adad4bfe6868 Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Mon, 28 Jun 2021 12:08:53 +0200 -Subject: [PATCH 11/20] fix build with --disable-ucm - -Link: https://mailman.alsa-project.org/pipermail/alsa-devel/2021-June/186729.html -Reported-by: Michael Forney -Signed-off-by: Jaroslav Kysela ---- - include/local.h | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/include/local.h b/include/local.h -index 4e7d88a0..7cfcec53 100644 ---- a/include/local.h -+++ b/include/local.h -@@ -374,6 +374,8 @@ int _snd_config_load_with_include(snd_config_t *config, snd_input_t *in, - void *INTERNAL(snd_dlopen)(const char *name, int mode, char *errbuf, size_t errbuflen); - #endif - -+#ifdef BUILD_UCM -+ - const char *uc_mgr_alibcfg_by_device(snd_config_t **config, const char *name); - - static inline int _snd_is_ucm_device(const char *name) -@@ -381,4 +383,12 @@ static inline int _snd_is_ucm_device(const char *name) - return name && name[0] == '_' && name[1] == 'u' && name[2] == 'c' && name[3] == 'm'; - } - -+#else -+ -+static inline const char *uc_mgr_alibcfg_by_device(snd_config_t **config, const char *name) { return NULL; } -+static inline int _snd_is_ucm_device(const char *name) { return 0; } -+ -+ -+#endif -+ - #endif --- -2.31.1 - - -From 1a1f0fb244c477c430e156da878475ef57d198f9 Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Mon, 28 Jun 2021 12:11:54 +0200 -Subject: [PATCH 12/20] pcm: rate - fix some gcc warnings - -Signed-off-by: Jaroslav Kysela ---- - src/pcm/pcm_rate.c | 14 +++++++------- - 1 file changed, 7 insertions(+), 7 deletions(-) - -diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c -index 13111d29..c45895a9 100644 ---- a/src/pcm/pcm_rate.c -+++ b/src/pcm/pcm_rate.c -@@ -82,12 +82,12 @@ struct _snd_pcm_rate { - - /* allocate a channel area and a temporary buffer for the given size */ - static snd_pcm_channel_area_t * --rate_alloc_tmp_buf(snd_pcm_rate_t *rate, snd_pcm_format_t format, -+rate_alloc_tmp_buf(snd_pcm_format_t format, - unsigned int channels, unsigned int frames) - { - snd_pcm_channel_area_t *ap; - int width = snd_pcm_format_physical_width(format); -- int i; -+ unsigned int i; - - ap = malloc(sizeof(*ap) * channels); - if (!ap) -@@ -354,7 +354,7 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) - snd_pcm_rate_t *rate = pcm->private_data; - snd_pcm_t *slave = rate->gen.slave; - snd_pcm_rate_side_info_t *sinfo, *cinfo; -- unsigned int channels, cwidth, swidth, chn, acc; -+ unsigned int channels, acc; - int need_src_buf, need_dst_buf; - int err = snd_pcm_hw_params_slave(pcm, params, - snd_pcm_rate_hw_refine_cchange, -@@ -401,9 +401,9 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) - return -EBUSY; - } - -- rate->pareas = rate_alloc_tmp_buf(rate, cinfo->format, channels, -+ rate->pareas = rate_alloc_tmp_buf(cinfo->format, channels, - cinfo->period_size); -- rate->sareas = rate_alloc_tmp_buf(rate, sinfo->format, channels, -+ rate->sareas = rate_alloc_tmp_buf(sinfo->format, channels, - sinfo->period_size); - if (!rate->pareas || !rate->sareas) { - err = -ENOMEM; -@@ -442,7 +442,7 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) - rate->src_conv_idx = - snd_pcm_linear_convert_index(rate->orig_in_format, - rate->info.in.format); -- rate->src_buf = rate_alloc_tmp_buf(rate, rate->info.in.format, -+ rate->src_buf = rate_alloc_tmp_buf(rate->info.in.format, - channels, rate->info.in.period_size); - if (!rate->src_buf) { - err = -ENOMEM; -@@ -454,7 +454,7 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) - rate->dst_conv_idx = - snd_pcm_linear_convert_index(rate->info.out.format, - rate->orig_out_format); -- rate->dst_buf = rate_alloc_tmp_buf(rate, rate->info.out.format, -+ rate->dst_buf = rate_alloc_tmp_buf(rate->info.out.format, - channels, rate->info.out.period_size); - if (!rate->dst_buf) { - err = -ENOMEM; --- -2.31.1 - - -From e47c11822d6b459a9b3704b3ee6a4a5c9a1b85be Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Tue, 29 Jun 2021 18:02:27 +0200 -Subject: [PATCH 13/20] control: remap - assign right name to the child handle - for no-op - -Fixes: https://github.com/alsa-project/alsa-utils/issues/100 -Signed-off-by: Jaroslav Kysela ---- - src/control/control_remap.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/control/control_remap.c b/src/control/control_remap.c -index a85c1725..81524014 100644 ---- a/src/control/control_remap.c -+++ b/src/control/control_remap.c -@@ -1173,6 +1173,10 @@ int snd_ctl_remap_open(snd_ctl_t **handlep, const char *name, snd_config_t *rema - /* no-op check, remove the plugin */ - if (priv->map_items == 0 && priv->remap_items == 0) { - remap_free(priv); -+ free(child->name); -+ child->name = name ? strdup(name) : NULL; -+ if (name && !child->name) -+ return -ENOMEM; - *handlep = child; - return 0; - } --- -2.31.1 - - -From 23a191a82c693456e61431ab699cddc1e5782a26 Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Tue, 29 Jun 2021 19:31:28 +0200 -Subject: [PATCH 14/20] control: remap - assign right name to the child handle - for no-op (2nd case) - -Fixes: https://github.com/alsa-project/alsa-utils/issues/100 -Signed-off-by: Jaroslav Kysela ---- - src/control/control_remap.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/src/control/control_remap.c b/src/control/control_remap.c -index 81524014..4914f960 100644 ---- a/src/control/control_remap.c -+++ b/src/control/control_remap.c -@@ -1154,6 +1154,10 @@ int snd_ctl_remap_open(snd_ctl_t **handlep, const char *name, snd_config_t *rema - snd_ctl_t *ctl; - int result, err; - -+ /* no-op, remove the plugin */ -+ if (!remap && !map) -+ goto _noop; -+ - priv = calloc(1, sizeof(*priv)); - if (priv == NULL) - return -ENOMEM; -@@ -1173,6 +1177,7 @@ int snd_ctl_remap_open(snd_ctl_t **handlep, const char *name, snd_config_t *rema - /* no-op check, remove the plugin */ - if (priv->map_items == 0 && priv->remap_items == 0) { - remap_free(priv); -+ _noop: - free(child->name); - child->name = name ? strdup(name) : NULL; - if (name && !child->name) -@@ -1316,11 +1321,6 @@ int _snd_ctl_remap_open(snd_ctl_t **handlep, char *name, snd_config_t *root, snd - err = _snd_ctl_open_child(&cctl, root, child, mode, conf); - if (err < 0) - return err; -- /* no-op, remove the plugin */ -- if (!remap && !map) { -- *handlep = cctl; -- return 0; -- } - err = snd_ctl_remap_open(handlep, name, remap, map, cctl, mode); - if (err < 0) - snd_ctl_close(cctl); --- -2.31.1 - - -From 7d40a76ef5494e08af00fa4e7bfefbd43aba4827 Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Tue, 31 Aug 2021 09:25:12 +0200 -Subject: [PATCH 19/20] ucm: avoid zero card instance number - -Signed-off-by: Jaroslav Kysela ---- - src/ucm/utils.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/ucm/utils.c b/src/ucm/utils.c -index f3a8c9ba..10b21c34 100644 ---- a/src/ucm/utils.c -+++ b/src/ucm/utils.c -@@ -780,6 +780,9 @@ int uc_mgr_card_open(snd_use_case_mgr_t *uc_mgr) - while (uc_mgr_card_find(ucm_card_assign)) { - ucm_card_assign++; - ucm_card_assign &= 0xffff; -+ /* avoid zero card instance number */ -+ if (ucm_card_assign == 0) -+ ucm_card_assign++; - if (ucm_card_assign == prev) { - pthread_mutex_unlock(&ucm_cards_mutex); - return -ENOMEM; --- -2.31.1 - - -From 4a52ae4c329ae17117375a4b85b80f37994a4044 Mon Sep 17 00:00:00 2001 -From: Jaroslav Kysela -Date: Tue, 31 Aug 2021 09:40:42 +0200 -Subject: [PATCH 20/20] ucm: fix the parsing of the hexadecimal prefix - -The safe_strtol() function use strtol() which expects -to have the '0x' prefix for the hexadecimal number (when -base argument is zero). - -BugLink: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/1553 -Signed-off-by: Jaroslav Kysela ---- - src/ucm/utils.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/src/ucm/utils.c b/src/ucm/utils.c -index 10b21c34..2fbc4c8c 100644 ---- a/src/ucm/utils.c -+++ b/src/ucm/utils.c -@@ -811,7 +811,7 @@ void uc_mgr_card_close(snd_use_case_mgr_t *uc_mgr) - */ - const char *uc_mgr_alibcfg_by_device(snd_config_t **top, const char *name) - { -- char buf[5]; -+ char buf[7]; - long card_num; - snd_config_t *config; - snd_use_case_mgr_t *uc_mgr; -@@ -819,8 +819,10 @@ const char *uc_mgr_alibcfg_by_device(snd_config_t **top, const char *name) - - if (strncmp(name, "_ucm", 4) || strlen(name) < 12 || name[8] != '.') - return NULL; -- strncpy(buf, name + 4, 4); -- buf[4] = '\0'; -+ buf[0] = '0'; -+ buf[1] = 'x'; -+ strncpy(buf + 2, name + 4, 4); -+ buf[6] = '\0'; - err = safe_strtol(buf, &card_num); - if (err < 0 || card_num < 0 || card_num > 0xffff) - return NULL; --- -2.31.1 - diff --git a/alsa-lib.spec b/alsa-lib.spec index 5493e3c..e5448f5 100644 --- a/alsa-lib.spec +++ b/alsa-lib.spec @@ -2,14 +2,14 @@ #define prever_dot .rc3 #define postver a -%define version_alsa_lib 1.2.5.1 -%define version_alsa_ucm 1.2.5.1 +%define version_alsa_lib 1.2.6 +%define version_alsa_ucm 1.2.6 %define version_alsa_tplg 1.2.5 Summary: The Advanced Linux Sound Architecture (ALSA) library Name: alsa-lib Version: %{version_alsa_lib} -Release: 4%{?prever_dot}%{?dist} +Release: 1%{?prever_dot}%{?dist} License: LGPLv2+ URL: http://www.alsa-project.org/ @@ -167,6 +167,9 @@ rm %{buildroot}/%{_includedir}/asoundlib.h %{_datadir}/alsa/topology %changelog +* Mon Dec 6 2021 Jaroslav Kysela - 1.2.6-1 +- update to 1.2.6 + * Sat Nov 13 2021 Peter Robinson - 1.2.5.1-4 - Add Rockchip ES8316 support diff --git a/alsa-ucm-conf.patch b/alsa-ucm-conf.patch index 0ceffd8..e69de29 100644 --- a/alsa-ucm-conf.patch +++ b/alsa-ucm-conf.patch @@ -1,147 +0,0 @@ -From 85eea19783cfccaccd859e303fda62adb63c219d Mon Sep 17 00:00:00 2001 -From: Jian-Hong Pan -Date: Tue, 7 Sep 2021 11:38:14 +0800 -Subject: [PATCH] ucm2: Add UCM support for rockchip_es8316 on Pinebook Pro - -Add UCM config files for Pinebook Pro's audio. The config files are -transformed and tuned from Manjaro ARM's packages: -* pinebookpro-post-install's asound.state [1] -* pinebookpro-audio's audio_jack_plugged_in.sh [2] - -By the way, with these config files, the Speaker and Headphones will be -switched according to the (un)plugged state automatically. - -[1] https://gitlab.manjaro.org/manjaro-arm/packages/community/pinebookpro-post-install/-/blob/4b4206c57b21044bf9c00848bd1f8b6f710d19eb/asound.state -[2] https://gitlab.manjaro.org/manjaro-arm/packages/community/pinebookpro-audio/-/blob/1f567db09495acc3beb5405c9ef85c3c07b86785/audio_jack_plugged_in.sh - -Fixes: https://github.com/alsa-project/alsa-ucm-conf/issues/110 -Fixes: https://github.com/alsa-project/alsa-ucm-conf/pull/112 -Signed-off-by: Jian-Hong Pan -Signed-off-by: Jaroslav Kysela ---- - ucm2/Rockchip/es8316/HiFi.conf | 66 +++++++++++++++++++ - ucm2/Rockchip/es8316/es8316.conf | 29 ++++++++ - .../rockchip_es8316/rockchip_es8316.conf | 1 + - 3 files changed, 96 insertions(+) - create mode 100644 ucm2/Rockchip/es8316/HiFi.conf - create mode 100644 ucm2/Rockchip/es8316/es8316.conf - create mode 120000 ucm2/conf.d/rockchip_es8316/rockchip_es8316.conf - -diff --git a/ucm2/Rockchip/es8316/HiFi.conf b/ucm2/Rockchip/es8316/HiFi.conf -new file mode 100644 -index 0000000..2124ded ---- /dev/null -+++ b/ucm2/Rockchip/es8316/HiFi.conf -@@ -0,0 +1,66 @@ -+# Reference: -+# https://gitlab.manjaro.org/manjaro-arm/packages/community/pinebookpro-post-install/-/blob/4b4206c57b21044bf9c00848bd1f8b6f710d19eb/asound.state -+# https://gitlab.manjaro.org/manjaro-arm/packages/community/pinebookpro-audio/-/blob/1f567db09495acc3beb5405c9ef85c3c07b86785/audio_jack_plugged_in.sh -+ -+SectionDevice."Speaker" { -+ Comment "Speaker" -+ -+ ConflictingDevice [ -+ "Headphones" -+ ] -+ -+ EnableSequence [ -+ cset "name='Playback Polarity' 'R Invert'" -+ cset "name='Speaker Switch' on" -+ ] -+ -+ DisableSequence [ -+ cset "name='Speaker Switch' off" -+ ] -+ -+ Value { -+ PlaybackPriority 100 -+ PlaybackPCM "hw:${CardId}" -+ PlaybackMixerElem "Headphone Mixer" -+ PlaybackMasterElem "DAC" -+ } -+} -+ -+SectionDevice."Mic" { -+ Comment "Internal Microphone" -+ -+ EnableSequence [ -+ cset "name='Differential Mux' lin1-rin1" -+ ] -+ -+ Value { -+ CapturePriority 100 -+ CapturePCM "hw:${CardId}" -+ CaptureMixerElem "ADC PGA Gain" -+ CaptureMasterElem "ADC" -+ } -+} -+ -+SectionDevice."Headphones" { -+ Comment "Headphones" -+ -+ ConflictingDevice [ -+ "Speaker" -+ ] -+ -+ EnableSequence [ -+ cset "name='Playback Polarity' 'Normal'" -+ ] -+ DisableSequence [ -+ cset "name='Playback Polarity' 'R Invert'" -+ ] -+ -+ Value { -+ PlaybackPriority 200 -+ PlaybackPCM "hw:${CardId}" -+ PlaybackMixerElem "Headphone Mixer" -+ PlaybackMasterElem "DAC" -+ JackControl "Headphones Jack" -+ JackHWMute "Speaker" -+ } -+} -diff --git a/ucm2/Rockchip/es8316/es8316.conf b/ucm2/Rockchip/es8316/es8316.conf -new file mode 100644 -index 0000000..62044e6 ---- /dev/null -+++ b/ucm2/Rockchip/es8316/es8316.conf -@@ -0,0 +1,29 @@ -+Syntax 3 -+ -+SectionUseCase."HiFi" { -+ File "/Rockchip/es8316/HiFi.conf" -+ Comment "Play HiFi quality Music" -+} -+ -+BootSequence [ -+ # Disable all outputs -+ cset "name='Speaker Switch' off" -+ -+ # Set HP vol to 0 dB (3/3) -+ cset "name='Headphone Playback Volume' 3" -+ # Set HP mixer vol to 0 dB -+ cset "name='Headphone Mixer Volume' 11" -+ # Set DAC vol to 0 dB (192/192) -+ cset "name='DAC Playback Volume' 192" -+ -+ # Disable Auto Level Control -+ cset "name='ALC Capture Switch' off" -+ # Set ADC vol to 0 dB (192/192) -+ cset "name='ADC Capture Volume' 192" -+ # Set Mic amplifier to +16 dB -+ cset "name='ADC PGA Gain Volume' 7" -+ -+ # Setup muxes / switches -+ cset "name='Left Headphone Mixer Left DAC Switch' on" -+ cset "name='Right Headphone Mixer Right DAC Switch' on" -+] -diff --git a/ucm2/conf.d/rockchip_es8316/rockchip_es8316.conf b/ucm2/conf.d/rockchip_es8316/rockchip_es8316.conf -new file mode 120000 -index 0000000..6d1864f ---- /dev/null -+++ b/ucm2/conf.d/rockchip_es8316/rockchip_es8316.conf -@@ -0,0 +1 @@ -+../../Rockchip/es8316/es8316.conf -\ No newline at end of file --- -2.33.1 - diff --git a/sources b/sources index ddf88ed..07eab63 100644 --- a/sources +++ b/sources @@ -1,3 +1,3 @@ -SHA512 (alsa-lib-1.2.5.1.tar.bz2) = 01998ffa449e925ff552c13aea47f9540903afdc533086067c78dcaba4d239c347180d3d28bb0000e6d19b7779c7249fcc77a30057930ca22d18ba55e163fa1c +SHA512 (alsa-lib-1.2.6.tar.bz2) = ae95718813abf62811fe44c6df2a8de5a1227da4b022c4dd97dd8e7c1001f48307ba36bf04208bdbe24e8a8eebf4ed5a59f40ee6750dcbe976678071c3f2f5b7 +SHA512 (alsa-ucm-conf-1.2.6.tar.bz2) = 5fe85643b60c8defeafcdfcf97e61b5d05e6db28cef2466a70f63b8fffba22bdd50b83a5ca88806a6350de6e9d802dd3c2240b293190b9d05daea515c03d4397 SHA512 (alsa-topology-conf-1.2.5.tar.bz2) = 2eb4d8baf2dcbf0b631dd11dbf15bffc51694d9cc6931619e51787f3ba58d1a091d266e6721a3b737c040ec74a28270b93f39fb97f30a3227cf340dd646e5d51 -SHA512 (alsa-ucm-conf-1.2.5.1.tar.bz2) = 774d6da1a0ee6fb1fcd764c1d4b3eb5812a35508cf27db71f6c82784f125eca207992da9081d25783fecb31e548d8b34124d4b3b3d506e33215b76ea48f71012