1917 lines
62 KiB
Diff
1917 lines
62 KiB
Diff
From 81e7923fbfad45b2f353a4d6e3053af51f5f7d0b Mon Sep 17 00:00:00 2001
|
|
From: Jaroslav Kysela <perex@perex.cz>
|
|
Date: Tue, 15 Jun 2021 23:21:42 +0200
|
|
Subject: [PATCH 01/20] control: empty - fix the static build
|
|
|
|
Reported-by: Jan Palus <atler@pld-linux.org>
|
|
Fixes: https://github.com/alsa-project/alsa-lib/issues/157
|
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
|
---
|
|
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 <tiwai@suse.de>
|
|
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 <tiwai@suse.de>
|
|
---
|
|
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 <tiwai@suse.de>
|
|
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 <tiwai@suse.de>
|
|
---
|
|
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 <perex@perex.cz>
|
|
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 <perex@perex.cz>
|
|
---
|
|
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 <perex@perex.cz>
|
|
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 <perex@perex.cz>
|
|
---
|
|
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 <perex@perex.cz>
|
|
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 <perex@perex.cz>
|
|
---
|
|
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 <tiwai@suse.de>
|
|
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 <tiwai@suse.de>
|
|
---
|
|
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 <perex@perex.cz>
|
|
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 <perex@perex.cz>
|
|
---
|
|
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" <tanjeff@cccmz.de>
|
|
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 <tanjeff@cccmz.de>
|
|
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
---
|
|
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 @@
|
|
<P>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:<index>" (e.g. `hw:2`). The NAME hint - which is
|
|
+"hw:CARD=<ID>" - 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" <tanjeff@cccmz.de>
|
|
Date: Thu, 17 Jun 2021 10:36:39 +0200
|
|
Subject: [PATCH 10/20] control: Minor documentation fixes.
|
|
|
|
Signed-off-by: Tanjeff-N. Moos <tanjeff@cccmz.de>
|
|
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
---
|
|
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 <perex@perex.cz>
|
|
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 <mforney@mforney.org>
|
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
|
---
|
|
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 <perex@perex.cz>
|
|
Date: Mon, 28 Jun 2021 12:11:54 +0200
|
|
Subject: [PATCH 12/20] pcm: rate - fix some gcc warnings
|
|
|
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
|
---
|
|
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 <perex@perex.cz>
|
|
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 <perex@perex.cz>
|
|
---
|
|
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 <perex@perex.cz>
|
|
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 <perex@perex.cz>
|
|
---
|
|
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 <perex@perex.cz>
|
|
Date: Tue, 31 Aug 2021 09:25:12 +0200
|
|
Subject: [PATCH 19/20] ucm: avoid zero card instance number
|
|
|
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
|
---
|
|
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 <perex@perex.cz>
|
|
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 <perex@perex.cz>
|
|
---
|
|
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
|
|
|