File 0017-PCM-Add-chmap-options-to-hw-and-null-plugins.patch of Package alsa

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);
openSUSE Build Service is sponsored by