]> git.alsa-project.org Git - alsa-lib.git/commitdiff
PCM: Use compounds for overriding / enhancing chmaps
authorTakashi Iwai <tiwai@suse.de>
Wed, 12 Sep 2012 15:13:22 +0000 (17:13 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 13 Sep 2012 06:24:59 +0000 (08:24 +0200)
Instead of a single channel map, multiple channel maps can be provided
in a form of compound (array) to hw and null plugins.  In null
get_chmap, the channel map corresponding to the current channels is
copied from the given channel maps.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
src/conf/cards/Audigy.conf
src/conf/cards/Audigy2.conf
src/conf/cards/EMU10K1.conf
src/pcm/pcm.c
src/pcm/pcm_hw.c
src/pcm/pcm_local.h
src/pcm/pcm_null.c

index e008b6789a6788cf850b277519531b05adf2f58e..4fe38732763359f010a9cce00918ed3a6fedac3f 100644 (file)
@@ -13,7 +13,7 @@ Audigy.pcm.front.0 {
        slave.pcm {
                type hw
                card $CARD
-               chmap "FL,FR"
+               chmap [ "UNKNOWN" "FL,FR" ]
        }
        hooks.0 {
                type ctl_elems
@@ -66,7 +66,7 @@ Audigy.pcm.rear.0 {
        slave.pcm {
                type hw
                card $CARD
-               chmap "RL,RR"
+               chmap [ "UNKNOWN" "RL,RR" ]
        }
        hooks.0 {
                type ctl_elems
@@ -102,7 +102,7 @@ Audigy.pcm.center_lfe.0 {
        slave.pcm {
                type hw
                card $CARD
-               chmap "FC,LFE"
+               chmap [ "UNKNOWN" "FC,LFE" ]
        }
        hooks.0 {
                type ctl_elems
index e34fadcfac1811ae50cc351801a7d7e532d69181..db45776e54c422c2bdb8317c45a65210c92bc499 100644 (file)
@@ -13,7 +13,7 @@ Audigy2.pcm.front.0 {
        slave.pcm {
                type hw
                card $CARD
-               chmap "FL,FR"
+               chmap [ "UNKNOWN" "FL,FR" ]
        }
        hooks.0 {
                type ctl_elems
@@ -66,7 +66,7 @@ Audigy2.pcm.rear.0 {
        slave.pcm {
                type hw
                card $CARD
-               chmap "RL,RR"
+               chmap [ "UNKNOWN" "RL,RR" ]
        }
        hooks.0 {
                type ctl_elems
@@ -102,7 +102,7 @@ Audigy2.pcm.center_lfe.0 {
        slave.pcm {
                type hw
                card $CARD
-               chmap "FC,LFE"
+               chmap [ "UNKNOWN" "FC,LFE" ]
        }
        hooks.0 {
                type ctl_elems
@@ -154,7 +154,7 @@ Audigy2.pcm.side.0 {
        slave.pcm {
                type hw
                card $CARD
-               chmap "SL,SR"
+               chmap [ "UNKNOWN" "SL,SR" ]
        }
        hooks.0 {
                type ctl_elems
index 02a732fb8234de65d896319dc6ed548fa4744a9f..d51f6dc02facc73f33f8da2d91540281ceac05c0 100644 (file)
@@ -15,7 +15,7 @@ EMU10K1.pcm.front.0 {
                slave.pcm {
                        type hw
                        card $CARD
-                       chmap "FL,FR"
+                       chmap [ "UNKNOWN" "FL,FR" ]
                }
                hooks.0 {
                        type ctl_elems
@@ -74,7 +74,7 @@ EMU10K1.pcm.rear.0 {
                slave.pcm {
                        type hw
                        card $CARD
-                       chmap "RL,RR"
+                       chmap [ "UNKNOWN" "RL,RR" ]
                }
                hooks.0 {
                        type ctl_elems
@@ -113,7 +113,7 @@ EMU10K1.pcm.center_lfe.0 {
                slave.pcm {
                        type hw
                        card $CARD
-                       chmap "FC,LFE"
+                       chmap [ "UNKNOWN" "FC,LFE" ]
                }
                hooks.0 {
                        type ctl_elems
index b102c625185e46569f60114edeae206a94c7b834..19a9abe4a5cd005245ba01f9572f415265b7bc69 100644 (file)
@@ -7531,25 +7531,37 @@ snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *str)
        return map;
 }
 
+/* copy a single channel map with the fixed type to chmap_query pointer */
+static int _copy_to_fixed_query_map(snd_pcm_chmap_query_t **dst,
+                                   const snd_pcm_chmap_t *src)
+{
+       *dst = malloc((src->channels + 2) * sizeof(int));
+       if (!*dst)
+               return -ENOMEM;
+       (*dst)->type = SND_CHMAP_TYPE_FIXED;
+       memcpy(&(*dst)->map, src, (src->channels + 1) * sizeof(int));
+       return 0;
+}
+
+#ifndef DOC_HIDDEN
+/* make a chmap_query array from a single channel map */
 snd_pcm_chmap_query_t **
-_snd_pcm_make_single_query_chmaps(snd_pcm_chmap_t *src)
+_snd_pcm_make_single_query_chmaps(const 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) {
+       if (_copy_to_fixed_query_map(maps, src)) {
                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)
+/* make a copy of chmap */
+snd_pcm_chmap_t *_snd_pcm_copy_chmap(const snd_pcm_chmap_t *src)
 {
        snd_pcm_chmap_t *map;
 
@@ -7560,6 +7572,91 @@ snd_pcm_chmap_t *_snd_pcm_copy_chmap(snd_pcm_chmap_t *src)
        return map;
 }
 
+/* make a copy of channel maps */
+snd_pcm_chmap_query_t **
+_snd_pcm_copy_chmap_query(snd_pcm_chmap_query_t * const *src)
+{
+       snd_pcm_chmap_query_t * const *p;
+       snd_pcm_chmap_query_t **maps;
+       int i, nums;
+
+       for (nums = 0, p = src; *p; p++)
+               nums++;
+
+       maps = calloc(nums + 1, sizeof(*maps));
+       if (!maps)
+               return NULL;
+       for (i = 0; i < nums; i++) {
+               maps[i] = malloc((src[i]->map.channels + 2) * sizeof(int));
+               if (!maps[i]) {
+                       snd_pcm_free_chmaps(maps);
+                       return NULL;
+               }
+               memcpy(maps[i], src[i], (src[i]->map.channels + 2) * sizeof(int));
+       }
+       return maps;
+}
+
+/* select the channel map with the current PCM channels and make a copy */
+snd_pcm_chmap_t *
+_snd_pcm_choose_fixed_chmap(snd_pcm_t *pcm, snd_pcm_chmap_query_t * const *maps)
+{
+       snd_pcm_chmap_query_t * const *p;
+
+       for (p = maps; *p; p++) {
+               if ((*p)->map.channels == pcm->channels)
+                       return _snd_pcm_copy_chmap(&(*p)->map);
+       }
+       return NULL;
+}
+
+/* make chmap_query array from the config tree;
+ * conf must be a compound (array)
+ */
+snd_pcm_chmap_query_t **
+_snd_pcm_parse_config_chmaps(snd_config_t *conf)
+{
+       snd_pcm_chmap_t *chmap;
+       snd_pcm_chmap_query_t **maps;
+       snd_config_iterator_t i, next;
+       const char *str;
+       int nums, err;
+
+       if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND)
+               return NULL;
+
+       nums = 0;
+       snd_config_for_each(i, next, conf) {
+               nums++;
+       }
+
+       maps = calloc(nums + 1, sizeof(*maps));
+       if (!maps)
+               return NULL;
+
+       nums = 0;
+       snd_config_for_each(i, next, conf) {
+               snd_config_t *n = snd_config_iterator_entry(i);
+               err = snd_config_get_string(n, &str);
+               if (err < 0)
+                       goto error;
+               chmap = snd_pcm_chmap_parse_string(str);
+               if (!chmap)
+                       goto error;
+               if (_copy_to_fixed_query_map(maps + nums, chmap)) {
+                       free(chmap);
+                       goto error;
+               }
+               nums++;
+       }
+       return maps;
+
+ error:
+       snd_pcm_free_chmaps(maps);
+       return NULL;
+}
+#endif /* DOC_HIDDEN */
+
 /*
  * basic helpers
  */
index 514f8ca4be925c6ac8b1d2225036bbbf80864dd4..649bf9dff92563818d008d270c08cc116e1bd2c5 100644 (file)
@@ -107,7 +107,7 @@ typedef struct {
        int channels;
        /* for chmap */
        unsigned int chmap_caps;
-       snd_pcm_chmap_*chmap_override;
+       snd_pcm_chmap_query_t **chmap_override;
 } snd_pcm_hw_t;
 
 #define SNDRV_FILE_PCM_STREAM_PLAYBACK         ALSA_DEVICE_DIRECTORY "pcmC%iD%ip"
@@ -1146,7 +1146,7 @@ static snd_pcm_chmap_query_t **snd_pcm_hw_query_chmaps(snd_pcm_t *pcm)
        snd_pcm_chmap_query_t **map;
 
        if (hw->chmap_override)
-               return _snd_pcm_make_single_query_chmaps(hw->chmap_override);
+               return _snd_pcm_copy_chmap_query(hw->chmap_override);
 
        if (!chmap_caps(hw, CHMAP_CTL_QUERY))
                return NULL;
@@ -1171,7 +1171,7 @@ static snd_pcm_chmap_t *snd_pcm_hw_get_chmap(snd_pcm_t *pcm)
        int ret;
 
        if (hw->chmap_override)
-               return _snd_pcm_copy_chmap(hw->chmap_override);
+               return _snd_pcm_choose_fixed_chmap(pcm, hw->chmap_override);
 
        if (!chmap_caps(hw, CHMAP_CTL_GET))
                return NULL;
@@ -1603,7 +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
+       [chmap MAP]             # Override channel maps; MAP is a string array
 }
 \endcode
 
@@ -1640,7 +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_*chmap = NULL;
+       snd_pcm_chmap_query_t **chmap = NULL;
        snd_pcm_hw_t *hw;
 
        /* look for defaults.pcm.nonblock definition */
@@ -1732,13 +1732,8 @@ int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
                        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);
+                       snd_pcm_free_chmaps(chmap);
+                       chmap = _snd_pcm_parse_config_chmaps(n);
                        if (!chmap) {
                                SNDERR("Invalid channel map for %s", id);
                                return -EINVAL;
@@ -1746,17 +1741,21 @@ int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
                        continue;
                }
                SNDERR("Unknown field %s", id);
+               snd_pcm_free_chmaps(chmap);
                return -EINVAL;
        }
        if (card < 0) {
                SNDERR("card is not defined");
+               snd_pcm_free_chmaps(chmap);
                return -EINVAL;
        }
        err = snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream,
                              mode | (nonblock ? SND_PCM_NONBLOCK : 0),
                              0, sync_ptr_ioctl);
-       if (err < 0)
+       if (err < 0) {
+               snd_pcm_free_chmaps(chmap);
                return err;
+       }
        if (nonblock && ! (mode & SND_PCM_NONBLOCK)) {
                /* revert to blocking mode for read/write access */
                snd_pcm_hw_nonblock(*pcmp, 0);
index 726bd6d0da0d67ec92bad0ca002066d51b677278..e7798fd0ae115458ab9ed9a640cc4eea8db7ee84 100644 (file)
@@ -975,6 +975,12 @@ static inline void gettimestamp(snd_htimestamp_t *tstamp, int monotonic)
 }
 
 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);
+_snd_pcm_make_single_query_chmaps(const snd_pcm_chmap_t *src);
+snd_pcm_chmap_t *_snd_pcm_copy_chmap(const snd_pcm_chmap_t *src);
+snd_pcm_chmap_query_t **
+_snd_pcm_copy_chmap_query(snd_pcm_chmap_query_t * const *src);
+snd_pcm_chmap_query_t **
+_snd_pcm_parse_config_chmaps(snd_config_t *conf);
+snd_pcm_chmap_t *
+_snd_pcm_choose_fixed_chmap(snd_pcm_t *pcm, snd_pcm_chmap_query_t * const *maps);
 
index 223df24a37fcec2c2d18581967a6768325f2741a..a154a5cddba19d7d19f3c6bcf64e2a308d08fc90 100644 (file)
@@ -44,7 +44,7 @@ typedef struct {
        snd_pcm_uframes_t appl_ptr;
        snd_pcm_uframes_t hw_ptr;
        int poll_fd;
-       snd_pcm_chmap_*chmap;
+       snd_pcm_chmap_query_t **chmap;
 } snd_pcm_null_t;
 #endif
 
@@ -274,7 +274,7 @@ 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 _snd_pcm_copy_chmap_query(null->chmap);
        return NULL;
 }
 
@@ -283,7 +283,7 @@ 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 _snd_pcm_choose_fixed_chmap(pcm, null->chmap);
        return NULL;
 }
 
@@ -407,7 +407,7 @@ and /dev/full (capture, must be readable).
 \code
 pcm.name {
         type null               # Null PCM
-       [chmap MAP]
+       [chmap MAP]             # Provide channel maps; MAP is a string array
 }
 \endcode
 
@@ -439,7 +439,7 @@ int _snd_pcm_null_open(snd_pcm_t **pcmp, const char *name,
 {
        snd_config_iterator_t i, next;
        snd_pcm_null_t *null;
-       snd_pcm_chmap_*chmap = NULL;
+       snd_pcm_chmap_query_t **chmap = NULL;
        int err;
 
        snd_config_for_each(i, next, conf) {
@@ -450,14 +450,8 @@ int _snd_pcm_null_open(snd_pcm_t **pcmp, const char *name,
                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);
+                       snd_pcm_free_chmaps(chmap);
+                       chmap = _snd_pcm_parse_config_chmaps(n);
                        if (!chmap) {
                                SNDERR("Invalid channel map for %s", id);
                                return -EINVAL;
@@ -465,11 +459,14 @@ int _snd_pcm_null_open(snd_pcm_t **pcmp, const char *name,
                        continue;
                }
                SNDERR("Unknown field %s", id);
+               snd_pcm_free_chmaps(chmap);
                return -EINVAL;
        }
        err = snd_pcm_null_open(pcmp, name, stream, mode);
-       if (err < 0)
+       if (err < 0) {
+               snd_pcm_free_chmaps(chmap);
                return err;
+       }
 
        null = (*pcmp)->private_data;
        null->chmap = chmap;