- backport from upstream tree: * lots of patches to support the new chmap API * fix segfault in rate plugin error path * add a couple of test programs * fix inifinte loop in htimestamp of dmix & co OBS-URL: https://build.opensuse.org/request/show/138456 OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa?expand=0&rev=113
250 lines
6.3 KiB
Diff
250 lines
6.3 KiB
Diff
From e1975d20f5d52b370b5e78f5eb5f80a33f55a656 Mon Sep 17 00:00:00 2001
|
|
From: Takashi Iwai <tiwai@suse.de>
|
|
Date: Wed, 12 Sep 2012 14:47:17 +0200
|
|
Subject: [PATCH 17/30] PCM: Add chmap options to hw and null plugins
|
|
|
|
Add a config definition "chmap" to override (or enhance) the channel
|
|
maps. So far, only a single channel map can be provided, and the
|
|
channel count consistency isn't strictly tested at all.
|
|
|
|
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
---
|
|
src/pcm/pcm.c | 29 +++++++++++++++++++++++++++++
|
|
src/pcm/pcm_hw.c | 28 ++++++++++++++++++++++++++++
|
|
src/pcm/pcm_local.h | 5 +++++
|
|
src/pcm/pcm_null.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
|
|
4 files changed, 111 insertions(+), 1 deletion(-)
|
|
|
|
--- a/src/pcm/pcm.c
|
|
+++ b/src/pcm/pcm.c
|
|
@@ -7531,6 +7531,35 @@ snd_pcm_chmap_t *snd_pcm_chmap_parse_str
|
|
return map;
|
|
}
|
|
|
|
+snd_pcm_chmap_query_t **
|
|
+_snd_pcm_make_single_query_chmaps(snd_pcm_chmap_t *src)
|
|
+{
|
|
+ snd_pcm_chmap_query_t **maps;
|
|
+
|
|
+ maps = calloc(2, sizeof(*maps));
|
|
+ if (!maps)
|
|
+ return NULL;
|
|
+ *maps = malloc((src->channels + 2) * sizeof(int));
|
|
+ if (!*maps) {
|
|
+ free(maps);
|
|
+ return NULL;
|
|
+ }
|
|
+ (*maps)->type = SND_CHMAP_TYPE_FIXED;
|
|
+ memcpy(&(*maps)->map, src, (src->channels + 1) * sizeof(int));
|
|
+ return maps;
|
|
+}
|
|
+
|
|
+snd_pcm_chmap_t *_snd_pcm_copy_chmap(snd_pcm_chmap_t *src)
|
|
+{
|
|
+ snd_pcm_chmap_t *map;
|
|
+
|
|
+ map = malloc((src->channels + 1) * sizeof(int));
|
|
+ if (!map)
|
|
+ return NULL;
|
|
+ memcpy(map, src, (src->channels + 1) * sizeof(int));
|
|
+ return map;
|
|
+}
|
|
+
|
|
/*
|
|
* basic helpers
|
|
*/
|
|
--- a/src/pcm/pcm_hw.c
|
|
+++ b/src/pcm/pcm_hw.c
|
|
@@ -107,6 +107,7 @@ typedef struct {
|
|
int channels;
|
|
/* for chmap */
|
|
unsigned int chmap_caps;
|
|
+ snd_pcm_chmap_t *chmap_override;
|
|
} snd_pcm_hw_t;
|
|
|
|
#define SNDRV_FILE_PCM_STREAM_PLAYBACK ALSA_DEVICE_DIRECTORY "pcmC%iD%ip"
|
|
@@ -1144,6 +1145,9 @@ static snd_pcm_chmap_query_t **snd_pcm_h
|
|
snd_pcm_hw_t *hw = pcm->private_data;
|
|
snd_pcm_chmap_query_t **map;
|
|
|
|
+ if (hw->chmap_override)
|
|
+ return _snd_pcm_make_single_query_chmaps(hw->chmap_override);
|
|
+
|
|
if (!chmap_caps(hw, CHMAP_CTL_QUERY))
|
|
return NULL;
|
|
|
|
@@ -1166,6 +1170,9 @@ static snd_pcm_chmap_t *snd_pcm_hw_get_c
|
|
unsigned int i;
|
|
int ret;
|
|
|
|
+ if (hw->chmap_override)
|
|
+ return _snd_pcm_copy_chmap(hw->chmap_override);
|
|
+
|
|
if (!chmap_caps(hw, CHMAP_CTL_GET))
|
|
return NULL;
|
|
|
|
@@ -1220,6 +1227,9 @@ static int snd_pcm_hw_set_chmap(snd_pcm_
|
|
unsigned int i;
|
|
int ret;
|
|
|
|
+ if (hw->chmap_override)
|
|
+ return -ENXIO;
|
|
+
|
|
if (!chmap_caps(hw, CHMAP_CTL_SET))
|
|
return -ENXIO;
|
|
|
|
@@ -1593,6 +1603,7 @@ pcm.name {
|
|
[format STR] # Restrict only to the given format
|
|
[channels INT] # Restrict only to the given channels
|
|
[rate INT] # Restrict only to the given rate
|
|
+ [chmap MAP] # Override channel map
|
|
}
|
|
\endcode
|
|
|
|
@@ -1629,6 +1640,7 @@ int _snd_pcm_hw_open(snd_pcm_t **pcmp, c
|
|
snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
|
|
snd_config_t *n;
|
|
int nonblock = 1; /* non-block per default */
|
|
+ snd_pcm_chmap_t *chmap = NULL;
|
|
snd_pcm_hw_t *hw;
|
|
|
|
/* look for defaults.pcm.nonblock definition */
|
|
@@ -1719,6 +1731,20 @@ int _snd_pcm_hw_open(snd_pcm_t **pcmp, c
|
|
channels = val;
|
|
continue;
|
|
}
|
|
+ if (strcmp(id, "chmap") == 0) {
|
|
+ err = snd_config_get_string(n, &str);
|
|
+ if (err < 0) {
|
|
+ SNDERR("Invalid type for %s", id);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ free(chmap);
|
|
+ chmap = snd_pcm_chmap_parse_string(str);
|
|
+ if (!chmap) {
|
|
+ SNDERR("Invalid channel map for %s", id);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
SNDERR("Unknown field %s", id);
|
|
return -EINVAL;
|
|
}
|
|
@@ -1750,6 +1776,8 @@ int _snd_pcm_hw_open(snd_pcm_t **pcmp, c
|
|
hw->channels = channels;
|
|
if (rate > 0)
|
|
hw->rate = rate;
|
|
+ if (chmap)
|
|
+ hw->chmap_override = chmap;
|
|
|
|
return 0;
|
|
}
|
|
--- a/src/pcm/pcm_local.h
|
|
+++ b/src/pcm/pcm_local.h
|
|
@@ -973,3 +973,8 @@ static inline void gettimestamp(snd_htim
|
|
}
|
|
#endif
|
|
}
|
|
+
|
|
+snd_pcm_chmap_query_t **
|
|
+_snd_pcm_make_single_query_chmaps(snd_pcm_chmap_t *src);
|
|
+snd_pcm_chmap_t *_snd_pcm_copy_chmap(snd_pcm_chmap_t *src);
|
|
+
|
|
--- a/src/pcm/pcm_null.c
|
|
+++ b/src/pcm/pcm_null.c
|
|
@@ -44,6 +44,7 @@ typedef struct {
|
|
snd_pcm_uframes_t appl_ptr;
|
|
snd_pcm_uframes_t hw_ptr;
|
|
int poll_fd;
|
|
+ snd_pcm_chmap_t *chmap;
|
|
} snd_pcm_null_t;
|
|
#endif
|
|
|
|
@@ -268,6 +269,24 @@ static int snd_pcm_null_sw_params(snd_pc
|
|
return 0;
|
|
}
|
|
|
|
+static snd_pcm_chmap_query_t **snd_pcm_null_query_chmaps(snd_pcm_t *pcm)
|
|
+{
|
|
+ snd_pcm_null_t *null = pcm->private_data;
|
|
+
|
|
+ if (null->chmap)
|
|
+ return _snd_pcm_make_single_query_chmaps(null->chmap);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static snd_pcm_chmap_t *snd_pcm_null_get_chmap(snd_pcm_t *pcm)
|
|
+{
|
|
+ snd_pcm_null_t *null = pcm->private_data;
|
|
+
|
|
+ if (null->chmap)
|
|
+ return _snd_pcm_copy_chmap(null->chmap);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
static void snd_pcm_null_dump(snd_pcm_t *pcm, snd_output_t *out)
|
|
{
|
|
snd_output_printf(out, "Null PCM\n");
|
|
@@ -290,6 +309,9 @@ static const snd_pcm_ops_t snd_pcm_null_
|
|
.async = snd_pcm_null_async,
|
|
.mmap = snd_pcm_generic_mmap,
|
|
.munmap = snd_pcm_generic_munmap,
|
|
+ .query_chmaps = snd_pcm_null_query_chmaps,
|
|
+ .get_chmap = snd_pcm_null_get_chmap,
|
|
+ .set_chmap = NULL,
|
|
};
|
|
|
|
static const snd_pcm_fast_ops_t snd_pcm_null_fast_ops = {
|
|
@@ -385,6 +407,7 @@ and /dev/full (capture, must be readable
|
|
\code
|
|
pcm.name {
|
|
type null # Null PCM
|
|
+ [chmap MAP]
|
|
}
|
|
\endcode
|
|
|
|
@@ -415,6 +438,10 @@ int _snd_pcm_null_open(snd_pcm_t **pcmp,
|
|
snd_pcm_stream_t stream, int mode)
|
|
{
|
|
snd_config_iterator_t i, next;
|
|
+ snd_pcm_null_t *null;
|
|
+ snd_pcm_chmap_t *chmap = NULL;
|
|
+ int err;
|
|
+
|
|
snd_config_for_each(i, next, conf) {
|
|
snd_config_t *n = snd_config_iterator_entry(i);
|
|
const char *id;
|
|
@@ -422,10 +449,31 @@ int _snd_pcm_null_open(snd_pcm_t **pcmp,
|
|
continue;
|
|
if (snd_pcm_conf_generic_id(id))
|
|
continue;
|
|
+ if (strcmp(id, "chmap") == 0) {
|
|
+ const char *str;
|
|
+ err = snd_config_get_string(n, &str);
|
|
+ if (err < 0) {
|
|
+ SNDERR("Invalid type for %s", id);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ free(chmap);
|
|
+ chmap = snd_pcm_chmap_parse_string(str);
|
|
+ if (!chmap) {
|
|
+ SNDERR("Invalid channel map for %s", id);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
SNDERR("Unknown field %s", id);
|
|
return -EINVAL;
|
|
}
|
|
- return snd_pcm_null_open(pcmp, name, stream, mode);
|
|
+ err = snd_pcm_null_open(pcmp, name, stream, mode);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ null = (*pcmp)->private_data;
|
|
+ null->chmap = chmap;
|
|
+ return 0;
|
|
}
|
|
#ifndef DOC_HIDDEN
|
|
SND_DLSYM_BUILD_VERSION(_snd_pcm_null_open, SND_PCM_DLSYM_VERSION);
|