]> git.alsa-project.org Git - alsa-lib.git/commitdiff
PCM: Add chmap options to hw and null plugins
authorTakashi Iwai <tiwai@suse.de>
Wed, 12 Sep 2012 12:47:17 +0000 (14:47 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 13 Sep 2012 06:24:58 +0000 (08:24 +0200)
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
src/pcm/pcm_hw.c
src/pcm/pcm_local.h
src/pcm/pcm_null.c

index 9abe37022044ead949a0067c6cfc2dfa530d5c7e..b102c625185e46569f60114edeae206a94c7b834 100644 (file)
@@ -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
  */
index d24949a0f40c491992cc1ccb03e66b4cf7b9f588..514f8ca4be925c6ac8b1d2225036bbbf80864dd4 100644 (file)
@@ -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;
 }
index 83aa39db33743e5f46aa4347f315aa139671b183..726bd6d0da0d67ec92bad0ca002066d51b677278 100644 (file)
@@ -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);
+
index 692254ae6f0411ed940b7c8127acaa13ce91cb0f..223df24a37fcec2c2d18581967a6768325f2741a 100644 (file)
@@ -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);