diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-09-12 14:47:17 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-09-13 08:24:58 +0200 |
commit | e1975d20f5d52b370b5e78f5eb5f80a33f55a656 (patch) | |
tree | 716f30fd4d4c40b43036dc65385e24646e4acb30 | |
parent | 81135aac49c8a3b547181d44f78ffe2594db5dbe (diff) | |
download | alsa-lib-e1975d20f5d52b370b5e78f5eb5f80a33f55a656.tar.gz |
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>
-rw-r--r-- | src/pcm/pcm.c | 29 | ||||
-rw-r--r-- | src/pcm/pcm_hw.c | 28 | ||||
-rw-r--r-- | src/pcm/pcm_local.h | 5 | ||||
-rw-r--r-- | src/pcm/pcm_null.c | 50 |
4 files changed, 111 insertions, 1 deletions
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 9abe3702..b102c625 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -7531,6 +7531,35 @@ snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *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 */ diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index d24949a0..514f8ca4 100644 --- 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_hw_query_chmaps(snd_pcm_t *pcm) 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_chmap(snd_pcm_t *pcm) 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_t *pcm, const snd_pcm_chmap_t *map) 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, const char *name, 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, const char *name, 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, const char *name, hw->channels = channels; if (rate > 0) hw->rate = rate; + if (chmap) + hw->chmap_override = chmap; return 0; } diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 83aa39db..726bd6d0 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -973,3 +973,8 @@ static inline void gettimestamp(snd_htimestamp_t *tstamp, int monotonic) } #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); + diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c index 692254ae..223df24a 100644 --- 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_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_pa 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_ops = { .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, const char *name, 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, const char *name, 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); |