Accepting request 138457 from multimedia:libs

- 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 (forwarded request 138456 from tiwai)

OBS-URL: https://build.opensuse.org/request/show/138457
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/alsa?expand=0&rev=126
This commit is contained in:
Stephan Kulow 2012-10-18 13:00:06 +00:00 committed by Git OBS Bridge
commit 28f46132ad
31 changed files with 4931 additions and 0 deletions

View File

@ -0,0 +1,685 @@
From 3c4a22ea49a881cdbfe2d50eef94b17e38104734 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 25 Jul 2012 15:05:15 +0200
Subject: [PATCH 01/30] Implement the channel mapping API
Added new channel-mapping API functions.
Not all plugins are covered, especially the route, multi and external
plugins don't work yet.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/control.h | 7 +
include/pcm.h | 12 +++
include/sound/asound.h | 25 ++++++
src/pcm/pcm.c | 55 ++++++++++++++
src/pcm/pcm_adpcm.c | 3
src/pcm/pcm_alaw.c | 3
src/pcm/pcm_copy.c | 3
src/pcm/pcm_direct.c | 18 ++++
src/pcm/pcm_direct.h | 10 ++
src/pcm/pcm_dmix.c | 3
src/pcm/pcm_dshare.c | 2
src/pcm/pcm_dsnoop.c | 3
src/pcm/pcm_file.c | 3
src/pcm/pcm_generic.c | 18 ++++
src/pcm/pcm_generic.h | 11 ++
src/pcm/pcm_hooks.c | 3
src/pcm/pcm_hw.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++
src/pcm/pcm_iec958.c | 3
src/pcm/pcm_ladspa.c | 3
src/pcm/pcm_lfloat.c | 3
src/pcm/pcm_linear.c | 3
src/pcm/pcm_local.h | 3
src/pcm/pcm_meter.c | 3
src/pcm/pcm_mmap_emul.c | 3
src/pcm/pcm_mulaw.c | 2
src/pcm/pcm_rate.c | 3
src/pcm/pcm_softvol.c | 3
27 files changed, 386 insertions(+)
--- a/include/control.h
+++ b/include/control.h
@@ -182,6 +182,13 @@ typedef enum _snd_ctl_event_type {
/** Mute state */
#define SND_CTL_TLV_DB_GAIN_MUTE -9999999
+/** TLV type - fixed channel map positions */
+#define SND_CTL_TLVT_CHMAP_FIXED 0x00101
+/** TLV type - freely swappable channel map positions */
+#define SND_CTL_TLVT_CHMAP_VAR 0x00102
+/** TLV type - pair-wise swappable channel map positions */
+#define SND_CTL_TLVT_CHMAP_PAIRED 0x00103
+
/** CTL type */
typedef enum _snd_ctl_type {
/** Kernel level CTL */
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -474,6 +474,18 @@ int snd_pcm_wait(snd_pcm_t *pcm, int tim
int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2);
int snd_pcm_unlink(snd_pcm_t *pcm);
+enum {
+ SND_CHMAP_NONE = 0, /** unspecified channel position */
+ SND_CHMAP_FIXED, /** fixed channel position */
+ SND_CHMAP_VAR, /** freely swappable channel position */
+ SND_CHMAP_PAIRED, /** pair-wise swappable channel position */
+};
+
+int **snd_pcm_query_chmaps(snd_pcm_t *pcm);
+void snd_pcm_free_chmaps(int **maps);
+int *snd_pcm_get_chmap(snd_pcm_t *pcm);
+int snd_pcm_set_chmap(snd_pcm_t *pcm, const int *map);
+
//int snd_pcm_mixer_element(snd_pcm_t *pcm, snd_mixer_t *mixer, snd_mixer_elem_t **elem);
/*
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -477,6 +477,31 @@ enum {
SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
};
+/* channel positions */
+enum {
+ SNDRV_CHMAP_UNKNOWN = 0,
+ SNDRV_CHMAP_FL, /* front left */
+ SNDRV_CHMAP_FC, /* front center */
+ SNDRV_CHMAP_FR, /* front right */
+ SNDRV_CHMAP_FLC, /* front left center */
+ SNDRV_CHMAP_FRC, /* front right center */
+ SNDRV_CHMAP_RL, /* rear left */
+ SNDRV_CHMAP_RC, /* rear center */
+ SNDRV_CHMAP_RR, /* rear right */
+ SNDRV_CHMAP_RLC, /* rear left center */
+ SNDRV_CHMAP_RRC, /* rear right center */
+ SNDRV_CHMAP_SL, /* side left */
+ SNDRV_CHMAP_SR, /* side right */
+ SNDRV_CHMAP_LFE, /* LFE */
+ SNDRV_CHMAP_FLW, /* front left wide */
+ SNDRV_CHMAP_FRW, /* front right wide */
+ SNDRV_CHMAP_FLH, /* front left high */
+ SNDRV_CHMAP_FCH, /* front center high */
+ SNDRV_CHMAP_FRH, /* front right high */
+ SNDRV_CHMAP_TC, /* top center */
+ SNDRV_CHMAP_LAST = SNDRV_CHMAP_TC,
+};
+
enum {
SNDRV_PCM_IOCTL_PVERSION = _IOR('A', 0x00, int),
SNDRV_PCM_IOCTL_INFO = _IOR('A', 0x01, struct sndrv_pcm_info),
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -7302,6 +7302,61 @@ OBSOLETE1(snd_pcm_sw_params_get_silence_
#endif /* DOC_HIDDEN */
+/**
+ * \!brief Query the available channel maps
+ * \param pcm PCM handle to query
+ * \return the NULL-terminated array of integer pointers, each of
+ * which contains the channel map. A channel map is represented by an
+ * integer array, beginning with the channel map type, followed by the
+ * number of channels, and the position of each channel.
+ */
+int **snd_pcm_query_chmaps(snd_pcm_t *pcm)
+{
+ if (!pcm->ops->query_chmaps)
+ return NULL;
+ return pcm->ops->query_chmaps(pcm);
+}
+
+/**
+ * \!brief Release the channel map array allocated via #snd_pcm_query_chmaps
+ * \param maps the array pointer to release
+ */
+void snd_pcm_free_chmaps(int **maps)
+{
+ int **p;
+ if (!maps)
+ return;
+ for (p = maps; *p; p++)
+ free(*p);
+ free(maps);
+}
+
+/**
+ * \!brief Get the current channel map
+ * \param pcm PCM instance
+ * \return the current channel map, or NULL if error
+ */
+int *snd_pcm_get_chmap(snd_pcm_t *pcm)
+{
+ if (!pcm->ops->get_chmap)
+ return NULL;
+ return pcm->ops->get_chmap(pcm);
+}
+
+/**
+ * \!brief Configure the current channel map
+ * \param pcm PCM instance
+ * \param map the channel map to write
+ * \return zero if succeeded, or a negative error code
+ */
+int snd_pcm_set_chmap(snd_pcm_t *pcm, const int *map)
+{
+ if (!pcm->ops->set_chmap)
+ return -ENXIO;
+ return pcm->ops->set_chmap(pcm, map);
+}
+
+
/*
* basic helpers
*/
--- a/src/pcm/pcm_adpcm.c
+++ b/src/pcm/pcm_adpcm.c
@@ -531,6 +531,9 @@ static const snd_pcm_ops_t snd_pcm_adpcm
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
/**
--- a/src/pcm/pcm_alaw.c
+++ b/src/pcm/pcm_alaw.c
@@ -404,6 +404,9 @@ static const snd_pcm_ops_t snd_pcm_alaw_
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
/**
--- a/src/pcm/pcm_copy.c
+++ b/src/pcm/pcm_copy.c
@@ -165,6 +165,9 @@ static const snd_pcm_ops_t snd_pcm_copy_
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
/**
--- a/src/pcm/pcm_direct.c
+++ b/src/pcm/pcm_direct.c
@@ -789,6 +789,24 @@ int snd_pcm_direct_munmap(snd_pcm_t *pcm
return 0;
}
+int **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm)
+{
+ snd_pcm_direct_t *dmix = pcm->private_data;
+ return snd_pcm_query_chmaps(dmix->spcm);
+}
+
+int *snd_pcm_direct_get_chmap(snd_pcm_t *pcm)
+{
+ snd_pcm_direct_t *dmix = pcm->private_data;
+ return snd_pcm_get_chmap(dmix->spcm);
+}
+
+int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const int *map)
+{
+ snd_pcm_direct_t *dmix = pcm->private_data;
+ return snd_pcm_set_chmap(dmix->spcm, map);
+}
+
int snd_pcm_direct_resume(snd_pcm_t *pcm)
{
snd_pcm_direct_t *dmix = pcm->private_data;
--- a/src/pcm/pcm_direct.h
+++ b/src/pcm/pcm_direct.h
@@ -235,6 +235,12 @@ struct snd_pcm_direct {
snd1_pcm_direct_open_secondary_client
#define snd_pcm_direct_parse_open_conf \
snd1_pcm_direct_parse_open_conf
+#define snd_pcm_direct_query_chmaps \
+ snd1_pcm_direct_query_chmaps
+#define snd_pcm_direct_get_chmap \
+ snd1_pcm_direct_get_chmap
+#define snd_pcm_direct_set_chmap \
+ snd1_pcm_direct_set_chmap
int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix);
@@ -290,6 +296,10 @@ void snd_pcm_direct_clear_timer_queue(sn
int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix);
int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name);
+int **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm);
+int *snd_pcm_direct_get_chmap(snd_pcm_t *pcm);
+int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const int *map);
+
int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);
--- a/src/pcm/pcm_dmix.c
+++ b/src/pcm/pcm_dmix.c
@@ -892,6 +892,9 @@ static const snd_pcm_ops_t snd_pcm_dmix_
.async = snd_pcm_direct_async,
.mmap = snd_pcm_direct_mmap,
.munmap = snd_pcm_direct_munmap,
+ .query_chmaps = snd_pcm_direct_query_chmaps,
+ .get_chmap = snd_pcm_direct_get_chmap,
+ .set_chmap = snd_pcm_direct_set_chmap,
};
static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
--- a/src/pcm/pcm_dshare.c
+++ b/src/pcm/pcm_dshare.c
@@ -573,6 +573,8 @@ static const snd_pcm_ops_t snd_pcm_dshar
.async = snd_pcm_direct_async,
.mmap = snd_pcm_direct_mmap,
.munmap = snd_pcm_direct_munmap,
+ .get_chmap = snd_pcm_direct_get_chmap,
+ .set_chmap = snd_pcm_direct_set_chmap,
};
static const snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = {
--- a/src/pcm/pcm_dsnoop.c
+++ b/src/pcm/pcm_dsnoop.c
@@ -488,6 +488,9 @@ static const snd_pcm_ops_t snd_pcm_dsnoo
.async = snd_pcm_direct_async,
.mmap = snd_pcm_direct_mmap,
.munmap = snd_pcm_direct_munmap,
+ .query_chmaps = snd_pcm_direct_query_chmaps,
+ .get_chmap = snd_pcm_direct_get_chmap,
+ .set_chmap = snd_pcm_direct_set_chmap,
};
static const snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -669,6 +669,9 @@ static const snd_pcm_ops_t snd_pcm_file_
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
static const snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
--- a/src/pcm/pcm_generic.c
+++ b/src/pcm/pcm_generic.c
@@ -323,4 +323,22 @@ int snd_pcm_generic_munmap(snd_pcm_t *pc
return 0;
}
+int **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm)
+{
+ snd_pcm_generic_t *generic = pcm->private_data;
+ return snd_pcm_query_chmaps(generic->slave);
+}
+
+int *snd_pcm_generic_get_chmap(snd_pcm_t *pcm)
+{
+ snd_pcm_generic_t *generic = pcm->private_data;
+ return snd_pcm_get_chmap(generic->slave);
+}
+
+int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const int *map)
+{
+ snd_pcm_generic_t *generic = pcm->private_data;
+ return snd_pcm_set_chmap(generic->slave, map);
+}
+
#endif /* DOC_HIDDEN */
--- a/src/pcm/pcm_generic.h
+++ b/src/pcm/pcm_generic.h
@@ -103,6 +103,12 @@ typedef struct {
snd1_pcm_generic_mmap
#define snd_pcm_generic_munmap \
snd1_pcm_generic_munmap
+#define snd_pcm_generic_query_chmaps \
+ snd1_pcm_generic_query_chmaps
+#define snd_pcm_generic_get_chmap \
+ snd1_pcm_generic_get_chmap
+#define snd_pcm_generic_set_chmap \
+ snd1_pcm_generic_set_chmap
int snd_pcm_generic_close(snd_pcm_t *pcm);
int snd_pcm_generic_nonblock(snd_pcm_t *pcm, int nonblock);
@@ -149,3 +155,8 @@ int snd_pcm_generic_real_htimestamp(snd_
snd_htimestamp_t *tstamp);
int snd_pcm_generic_mmap(snd_pcm_t *pcm);
int snd_pcm_generic_munmap(snd_pcm_t *pcm);
+int **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm);
+int *snd_pcm_generic_get_chmap(snd_pcm_t *pcm);
+int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const int *map);
+
+
--- a/src/pcm/pcm_hooks.c
+++ b/src/pcm/pcm_hooks.c
@@ -165,6 +165,9 @@ static const snd_pcm_ops_t snd_pcm_hooks
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
static const snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = {
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -1004,6 +1004,181 @@ static int snd_pcm_hw_htimestamp(snd_pcm
return 0;
}
+static void fill_chmap_ctl_id(snd_pcm_t *pcm, snd_ctl_elem_id_t *id)
+{
+ snd_pcm_hw_t *hw = pcm->private_data;
+ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM);
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ snd_ctl_elem_id_set_name(id, "Playback Channel Map");
+ else
+ snd_ctl_elem_id_set_name(id, "Capture Channel Map");
+ snd_ctl_elem_id_set_device(id, hw->device);
+ snd_ctl_elem_id_set_index(id, hw->subdevice);
+}
+
+static int is_chmap_type(int type)
+{
+ return (type >= SND_CTL_TLVT_CHMAP_FIXED &&
+ type <= SND_CTL_TLVT_CHMAP_PAIRED);
+}
+
+static int **snd_pcm_hw_query_chmaps(snd_pcm_t *pcm)
+{
+ snd_pcm_hw_t *hw = pcm->private_data;
+ snd_ctl_t *ctl;
+ snd_ctl_elem_id_t *id;
+ unsigned int tlv[256], *start;
+ int **map;
+ int i, ret, nums;
+
+ ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0);
+ if (ret < 0) {
+ SYSMSG("Cannot open the associated CTL\n");
+ return NULL;
+ }
+
+ snd_ctl_elem_id_alloca(&id);
+ fill_chmap_ctl_id(pcm, id);
+ ret = snd_ctl_elem_tlv_read(ctl, id, tlv, sizeof(tlv));
+ snd_ctl_close(ctl);
+ if (ret < 0) {
+ SYSMSG("Cannot read Channel Map TLV\n");
+ return NULL;
+ }
+
+#if 0
+ for (i = 0; i < 32; i++)
+ fprintf(stderr, "%02x: %08x\n", i, tlv[i]);
+#endif
+ if (tlv[0] != SND_CTL_TLVT_CONTAINER) {
+ if (!is_chmap_type(tlv[0])) {
+ SYSMSG("Invalid TLV type %d\n", tlv[0]);
+ return NULL;
+ }
+ start = tlv;
+ nums = 1;
+ } else {
+ unsigned int *p;
+ int size;
+ start = tlv + 2;
+ size = tlv[1];
+ nums = 0;
+ for (p = start; size > 0; ) {
+ if (!is_chmap_type(p[0])) {
+ SYSMSG("Invalid TLV type %d\n", p[0]);
+ return NULL;
+ }
+ nums++;
+ size -= p[1] + 8;
+ p += p[1] / 4 + 2;
+ }
+ }
+ map = calloc(nums + 1, sizeof(int *));
+ if (!map)
+ return NULL;
+ for (i = 0; i < nums; i++) {
+ map[i] = malloc(start[1] + 8);
+ if (!map[i])
+ goto nomem;
+ map[i][0] = start[0] - 0x100;
+ map[i][1] = start[1] / 4;
+ memcpy(map[i] + 2, start + 2, start[1]);
+ start += start[1] / 4 + 2;
+ }
+ return map;
+
+ nomem:
+ for (; i >= 0; i--)
+ free(map[i]);
+ free(map);
+ return NULL;
+}
+
+static int *snd_pcm_hw_get_chmap(snd_pcm_t *pcm)
+{
+ snd_pcm_hw_t *hw = pcm->private_data;
+ int *map;
+ snd_ctl_t *ctl;
+ snd_ctl_elem_id_t *id;
+ snd_ctl_elem_value_t *val;
+ unsigned int i;
+ int ret;
+
+ switch (FAST_PCM_STATE(hw)) {
+ case SNDRV_PCM_STATE_PREPARED:
+ case SNDRV_PCM_STATE_RUNNING:
+ case SNDRV_PCM_STATE_XRUN:
+ case SNDRV_PCM_STATE_DRAINING:
+ case SNDRV_PCM_STATE_PAUSED:
+ case SNDRV_PCM_STATE_SUSPENDED:
+ break;
+ default:
+ SYSMSG("Invalid PCM state for chmap_get: %s\n",
+ snd_pcm_state_name(FAST_PCM_STATE(hw)));
+ return NULL;
+ }
+ map = malloc(pcm->channels + 1);
+ if (!map)
+ return NULL;
+ *map = pcm->channels;
+ ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0);
+ if (ret < 0) {
+ free(map);
+ SYSMSG("Cannot open the associated CTL\n");
+ return NULL;
+ }
+ snd_ctl_elem_value_alloca(&val);
+ snd_ctl_elem_id_alloca(&id);
+ fill_chmap_ctl_id(pcm, id);
+ snd_ctl_elem_value_set_id(val, id);
+ ret = snd_ctl_elem_read(ctl, val);
+ if (ret < 0) {
+ snd_ctl_close(ctl);
+ free(map);
+ SYSMSG("Cannot read Channel Map ctl\n");
+ return NULL;
+ }
+ for (i = 0; i < pcm->channels; i++)
+ map[i + 1] = snd_ctl_elem_value_get_integer(val, i);
+ snd_ctl_close(ctl);
+ return map;
+}
+
+static int snd_pcm_hw_set_chmap(snd_pcm_t *pcm, const int *map)
+{
+ snd_pcm_hw_t *hw = pcm->private_data;
+ snd_ctl_t *ctl;
+ snd_ctl_elem_id_t *id;
+ snd_ctl_elem_value_t *val;
+ int i, ret;
+
+ if (*map < 0 || *map > 128) {
+ SYSMSG("Invalid number of channels %d\n", *map);
+ return -EINVAL;
+ }
+ if (FAST_PCM_STATE(hw) != SNDRV_PCM_STATE_PREPARED) {
+ SYSMSG("Invalid PCM state for chmap_set: %s\n",
+ snd_pcm_state_name(FAST_PCM_STATE(hw)));
+ return -EBADFD;
+ }
+ ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0);
+ if (ret < 0) {
+ SYSMSG("Cannot open the associated CTL\n");
+ return ret;
+ }
+ snd_ctl_elem_id_alloca(&id);
+ snd_ctl_elem_value_alloca(&val);
+ fill_chmap_ctl_id(pcm, id);
+ snd_ctl_elem_value_set_id(val, id);
+ for (i = 0; i < *map; i++)
+ snd_ctl_elem_value_set_integer(val, i, map[i + 1]);
+ ret = snd_ctl_elem_write(ctl, val);
+ snd_ctl_close(ctl);
+ if (ret < 0)
+ SYSMSG("Cannot write Channel Map ctl\n");
+ return ret;
+}
+
static void snd_pcm_hw_dump(snd_pcm_t *pcm, snd_output_t *out)
{
snd_pcm_hw_t *hw = pcm->private_data;
@@ -1037,6 +1212,9 @@ static const snd_pcm_ops_t snd_pcm_hw_op
.async = snd_pcm_hw_async,
.mmap = snd_pcm_hw_mmap,
.munmap = snd_pcm_hw_munmap,
+ .query_chmaps = snd_pcm_hw_query_chmaps,
+ .get_chmap = snd_pcm_hw_get_chmap,
+ .set_chmap = snd_pcm_hw_set_chmap,
};
static const snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = {
--- a/src/pcm/pcm_iec958.c
+++ b/src/pcm/pcm_iec958.c
@@ -429,6 +429,9 @@ static const snd_pcm_ops_t snd_pcm_iec95
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
/**
--- a/src/pcm/pcm_ladspa.c
+++ b/src/pcm/pcm_ladspa.c
@@ -1084,6 +1084,9 @@ static const snd_pcm_ops_t snd_pcm_ladsp
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
static int snd_pcm_ladspa_check_file(snd_pcm_ladspa_plugin_t * const plugin,
--- a/src/pcm/pcm_lfloat.c
+++ b/src/pcm/pcm_lfloat.c
@@ -363,6 +363,9 @@ static const snd_pcm_ops_t snd_pcm_lfloa
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
/**
--- a/src/pcm/pcm_linear.c
+++ b/src/pcm/pcm_linear.c
@@ -435,6 +435,9 @@ static const snd_pcm_ops_t snd_pcm_linea
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -143,6 +143,9 @@ typedef struct {
void (*dump)(snd_pcm_t *pcm, snd_output_t *out);
int (*mmap)(snd_pcm_t *pcm);
int (*munmap)(snd_pcm_t *pcm);
+ int **(*query_chmaps)(snd_pcm_t *pcm);
+ int *(*get_chmap)(snd_pcm_t *pcm);
+ int (*set_chmap)(snd_pcm_t *pcm, const int *map);
} snd_pcm_ops_t;
typedef struct {
--- a/src/pcm/pcm_meter.c
+++ b/src/pcm/pcm_meter.c
@@ -514,6 +514,9 @@ static const snd_pcm_ops_t snd_pcm_meter
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
static const snd_pcm_fast_ops_t snd_pcm_meter_fast_ops = {
--- a/src/pcm/pcm_mmap_emul.c
+++ b/src/pcm/pcm_mmap_emul.c
@@ -368,6 +368,9 @@ static const snd_pcm_ops_t snd_pcm_mmap_
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
static const snd_pcm_fast_ops_t snd_pcm_mmap_emul_fast_ops = {
--- a/src/pcm/pcm_mulaw.c
+++ b/src/pcm/pcm_mulaw.c
@@ -419,6 +419,8 @@ static const snd_pcm_ops_t snd_pcm_mulaw
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
/**
--- a/src/pcm/pcm_rate.c
+++ b/src/pcm/pcm_rate.c
@@ -1249,6 +1249,9 @@ static const snd_pcm_ops_t snd_pcm_rate_
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
/**
--- a/src/pcm/pcm_softvol.c
+++ b/src/pcm/pcm_softvol.c
@@ -818,6 +818,9 @@ static const snd_pcm_ops_t snd_pcm_softv
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
/**

View File

@ -0,0 +1,150 @@
From 3fb013065fee01ba7ac7c64fa48149f0e124fe26 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 25 Jul 2012 15:36:16 +0200
Subject: [PATCH 02/30] Implement get_chmap/set_chmap for PCM plug, route and
multi plugins
Still incomplete implementations. The query and set ops are missing
for route and multi plugins.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
src/pcm/pcm_multi.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/pcm/pcm_plug.c | 3 ++
src/pcm/pcm_route.c | 30 ++++++++++++++++++++++++++
3 files changed, 93 insertions(+)
--- a/src/pcm/pcm_multi.c
+++ b/src/pcm/pcm_multi.c
@@ -739,6 +739,63 @@ static int snd_pcm_multi_mmap(snd_pcm_t
return 0;
}
+static int *snd_pcm_multi_get_chmap(snd_pcm_t *pcm)
+{
+ snd_pcm_multi_t *multi = pcm->private_data;
+ int *map;
+ unsigned int i, idx;
+
+ map = malloc(pcm->channels + 4);
+ if (!map)
+ return NULL;
+ idx = 0;
+ for (i = 0; i < multi->slaves_count; ++i) {
+ int c, *slave_map;
+ slave_map = snd_pcm_get_chmap(multi->slaves[i].pcm);
+ if (!slave_map) {
+ free(map);
+ return NULL;
+ }
+ for (c = 0; c < *slave_map; c++) {
+ if (idx >= pcm->channels)
+ break;
+ map[idx++] = slave_map[c + 1];
+ }
+ free(slave_map);
+ }
+ return map;
+}
+
+static int snd_pcm_multi_set_chmap(snd_pcm_t *pcm, const int *map)
+{
+ snd_pcm_multi_t *multi = pcm->private_data;
+ unsigned int i, idx, chs;
+ int err;
+
+ chs = *map;
+ if (chs != pcm->channels)
+ return -EINVAL;
+ map++;
+ for (i = 0; i < multi->slaves_count; ++i) {
+ int *slave_map;
+ unsigned int slave_chs;
+ slave_chs = multi->slaves[i].channels_count;
+ if (idx + slave_chs > chs)
+ break;
+ slave_map = malloc(slave_chs * 4 + 4);
+ if (!slave_map)
+ return -ENOMEM;
+ *slave_map = slave_chs;
+ memcpy(slave_map, map + idx, slave_chs * 4);
+ err = snd_pcm_set_chmap(multi->slaves[i].pcm, slave_map);
+ free(slave_map);
+ if (err < 0)
+ return err;
+ idx += slave_chs;
+ }
+ return 0;
+}
+
static void snd_pcm_multi_dump(snd_pcm_t *pcm, snd_output_t *out)
{
snd_pcm_multi_t *multi = pcm->private_data;
@@ -775,6 +832,9 @@ static const snd_pcm_ops_t snd_pcm_multi
.async = snd_pcm_multi_async,
.mmap = snd_pcm_multi_mmap,
.munmap = snd_pcm_multi_munmap,
+ .query_chmaps = NULL, /* NYI */
+ .get_chmap = snd_pcm_multi_get_chmap,
+ .set_chmap = snd_pcm_multi_set_chmap,
};
static const snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = {
--- a/src/pcm/pcm_plug.c
+++ b/src/pcm/pcm_plug.c
@@ -1084,6 +1084,9 @@ static const snd_pcm_ops_t snd_pcm_plug_
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_generic_query_chmaps,
+ .get_chmap = snd_pcm_generic_get_chmap,
+ .set_chmap = snd_pcm_generic_set_chmap,
};
/**
--- a/src/pcm/pcm_route.c
+++ b/src/pcm/pcm_route.c
@@ -703,6 +703,33 @@ snd_pcm_route_read_areas(snd_pcm_t *pcm,
return size;
}
+static int *snd_pcm_route_get_chmap(snd_pcm_t *pcm)
+{
+ snd_pcm_route_t *route = pcm->private_data;
+ int *map, *slave_map;
+ unsigned int src, dst;
+
+ slave_map = snd_pcm_generic_get_chmap(pcm);
+ if (!slave_map)
+ return NULL;
+ map = calloc(4, route->schannels + 1);
+ if (!map) {
+ free(slave_map);
+ return NULL;
+ }
+ *map = route->schannels;
+ for (dst = 0; dst < route->params.ndsts; dst++) {
+ snd_pcm_route_ttable_dst_t *d = &route->params.dsts[dst];
+ for (src = 0; src < d->nsrcs; src++) {
+ int c = d->srcs[src].channel;
+ if (c < route->schannels && !map[c + 1])
+ map[c + 1] = slave_map[dst + 1];
+ }
+ }
+ free(slave_map);
+ return map;
+}
+
static void snd_pcm_route_dump(snd_pcm_t *pcm, snd_output_t *out)
{
snd_pcm_route_t *route = pcm->private_data;
@@ -760,6 +787,9 @@ static const snd_pcm_ops_t snd_pcm_route
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = NULL, /* NYI */
+ .get_chmap = snd_pcm_route_get_chmap,
+ .set_chmap = NULL, /* NYI */
};
static int route_load_ttable(snd_pcm_route_params_t *params, snd_pcm_stream_t stream,

View File

@ -0,0 +1,179 @@
From 662f79d4ec6b52bbaab28d5a9b60cc8bcdf042f9 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 25 Jul 2012 15:54:45 +0200
Subject: [PATCH 03/30] Implement get_chmap/set_chmap for PCM extplug/ioplug
plugins
Added the new ops for both external plugins, so the protocol numbers
are incremented.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/pcm_extplug.h | 14 +++++++++++++-
include/pcm_ioplug.h | 16 ++++++++++++++--
src/pcm/pcm_extplug.c | 33 +++++++++++++++++++++++++++++++++
src/pcm/pcm_ioplug.c | 33 +++++++++++++++++++++++++++++++++
4 files changed, 93 insertions(+), 3 deletions(-)
--- a/include/pcm_extplug.h
+++ b/include/pcm_extplug.h
@@ -55,7 +55,7 @@ typedef struct snd_pcm_extplug_callback
*/
#define SND_PCM_EXTPLUG_VERSION_MAJOR 1 /**< Protocol major version */
#define SND_PCM_EXTPLUG_VERSION_MINOR 0 /**< Protocol minor version */
-#define SND_PCM_EXTPLUG_VERSION_TINY 1 /**< Protocol tiny version */
+#define SND_PCM_EXTPLUG_VERSION_TINY 2 /**< Protocol tiny version */
/**
* Filter-plugin protocol version
*/
@@ -151,6 +151,18 @@ struct snd_pcm_extplug_callback {
* init; optional initialization called at prepare or reset
*/
int (*init)(snd_pcm_extplug_t *ext);
+ /**
+ * query the channel maps; optional; since v1.0.2
+ */
+ int **(*query_chmaps)(snd_pcm_extplug_t *ext);
+ /**
+ * get the channel map; optional; since v1.0.2
+ */
+ int *(*get_chmap)(snd_pcm_extplug_t *ext);
+ /**
+ * set the channel map; optional; since v1.0.2
+ */
+ int (*set_chmap)(snd_pcm_extplug_t *ext, const int *map);
};
--- a/include/pcm_ioplug.h
+++ b/include/pcm_ioplug.h
@@ -66,7 +66,7 @@ typedef struct snd_pcm_ioplug_callback s
*/
#define SND_PCM_IOPLUG_VERSION_MAJOR 1 /**< Protocol major version */
#define SND_PCM_IOPLUG_VERSION_MINOR 0 /**< Protocol minor version */
-#define SND_PCM_IOPLUG_VERSION_TINY 1 /**< Protocol tiny version */
+#define SND_PCM_IOPLUG_VERSION_TINY 2 /**< Protocol tiny version */
/**
* IO-plugin protocol version
*/
@@ -186,9 +186,21 @@ struct snd_pcm_ioplug_callback {
*/
void (*dump)(snd_pcm_ioplug_t *io, snd_output_t *out);
/**
- * get the delay for the running PCM; optional
+ * get the delay for the running PCM; optional; since v1.0.1
*/
int (*delay)(snd_pcm_ioplug_t *io, snd_pcm_sframes_t *delayp);
+ /**
+ * query the channel maps; optional; since v1.0.2
+ */
+ int **(*query_chmaps)(snd_pcm_ioplug_t *io);
+ /**
+ * get the channel map; optional; since v1.0.2
+ */
+ int *(*get_chmap)(snd_pcm_ioplug_t *io);
+ /**
+ * set the channel map; optional; since v1.0.2
+ */
+ int (*set_chmap)(snd_pcm_ioplug_t *io, const int *map);
};
--- a/src/pcm/pcm_extplug.c
+++ b/src/pcm/pcm_extplug.c
@@ -425,6 +425,36 @@ static int snd_pcm_extplug_close(snd_pcm
return 0;
}
+static int **snd_pcm_extplug_query_chmaps(snd_pcm_t *pcm)
+{
+ extplug_priv_t *ext = pcm->private_data;
+
+ if (ext->data->version >= 0x010002 &&
+ ext->data->callback->query_chmaps)
+ return ext->data->callback->query_chmaps(ext->data);
+ return snd_pcm_generic_query_chmaps(pcm);
+}
+
+static int *snd_pcm_extplug_get_chmap(snd_pcm_t *pcm)
+{
+ extplug_priv_t *ext = pcm->private_data;
+
+ if (ext->data->version >= 0x010002 &&
+ ext->data->callback->get_chmap)
+ return ext->data->callback->get_chmap(ext->data);
+ return snd_pcm_generic_get_chmap(pcm);
+}
+
+static int snd_pcm_extplug_set_chmap(snd_pcm_t *pcm, const int *map)
+{
+ extplug_priv_t *ext = pcm->private_data;
+
+ if (ext->data->version >= 0x010002 &&
+ ext->data->callback->set_chmap)
+ return ext->data->callback->set_chmap(ext->data, map);
+ return snd_pcm_generic_set_chmap(pcm, map);
+}
+
static const snd_pcm_ops_t snd_pcm_extplug_ops = {
.close = snd_pcm_extplug_close,
.info = snd_pcm_generic_info,
@@ -438,6 +468,9 @@ static const snd_pcm_ops_t snd_pcm_extpl
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
+ .query_chmaps = snd_pcm_extplug_query_chmaps,
+ .get_chmap = snd_pcm_extplug_get_chmap,
+ .set_chmap = snd_pcm_extplug_set_chmap,
};
#endif /* !DOC_HIDDEN */
--- a/src/pcm/pcm_ioplug.c
+++ b/src/pcm/pcm_ioplug.c
@@ -710,6 +710,36 @@ static int snd_pcm_ioplug_munmap(snd_pcm
return 0;
}
+static int **snd_pcm_ioplug_query_chmaps(snd_pcm_t *pcm)
+{
+ ioplug_priv_t *io = pcm->private_data;
+
+ if (io->data->version >= 0x010002 &&
+ io->data->callback->query_chmaps)
+ return io->data->callback->query_chmaps(io->data);
+ return NULL;
+}
+
+static int *snd_pcm_ioplug_get_chmap(snd_pcm_t *pcm)
+{
+ ioplug_priv_t *io = pcm->private_data;
+
+ if (io->data->version >= 0x010002 &&
+ io->data->callback->get_chmap)
+ return io->data->callback->get_chmap(io->data);
+ return NULL;
+}
+
+static int snd_pcm_ioplug_set_chmap(snd_pcm_t *pcm, const int *map)
+{
+ ioplug_priv_t *io = pcm->private_data;
+
+ if (io->data->version >= 0x010002 &&
+ io->data->callback->set_chmap)
+ return io->data->callback->set_chmap(io->data, map);
+ return -ENXIO;
+}
+
static void snd_pcm_ioplug_dump(snd_pcm_t *pcm, snd_output_t *out)
{
ioplug_priv_t *io = pcm->private_data;
@@ -760,6 +790,9 @@ static const snd_pcm_ops_t snd_pcm_ioplu
.dump = snd_pcm_ioplug_dump,
.mmap = snd_pcm_ioplug_mmap,
.munmap = snd_pcm_ioplug_munmap,
+ .query_chmaps = snd_pcm_ioplug_query_chmaps,
+ .get_chmap = snd_pcm_ioplug_get_chmap,
+ .set_chmap = snd_pcm_ioplug_set_chmap,
};
static const snd_pcm_fast_ops_t snd_pcm_ioplug_fast_ops = {

View File

@ -0,0 +1,288 @@
From 3fc13d6f5b08edee49b106cd711d51bf3aef6ab7 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 30 Jul 2012 15:50:44 +0200
Subject: [PATCH 04/30] Add test/chmap program
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
test/Makefile.am | 3
test/chmap.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 256 insertions(+), 1 deletion(-)
create mode 100644 test/chmap.c
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -2,7 +2,7 @@ SUBDIRS=. lsb
check_PROGRAMS=control pcm pcm_min latency seq \
playmidi1 timer rawmidi midiloop \
- oldapi queue_timer namehint client_event_filter
+ oldapi queue_timer namehint client_event_filter chmap
control_LDADD=../src/libasound.la
pcm_LDADD=../src/libasound.la
@@ -18,6 +18,7 @@ queue_timer_LDADD=../src/libasound.la
namehint_LDADD=../src/libasound.la
client_event_filter_LDADD=../src/libasound.la
code_CFLAGS=-Wall -pipe -g -O2
+chmap_LDADD=../src/libasound.la
INCLUDES=-I$(top_srcdir)/include
AM_CFLAGS=-Wall -pipe -g
--- /dev/null
+++ b/test/chmap.c
@@ -0,0 +1,254 @@
+/*
+ * channel mapping API test program
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <getopt.h>
+#include "../include/asoundlib.h"
+
+static void usage(void)
+{
+ printf("usage: chmap [options] query\n"
+ " chmap [options] get\n"
+ " chmap [options] set CH0 CH1 CH2...\n"
+ "options:\n"
+ " -D device Specify PCM device to handle\n"
+ " -f format PCM format\n"
+ " -c channels Channels\n"
+ " -r rate Sample rate\n");
+}
+
+static const char * const chname[] = {
+ "Unknown",
+ "FL", "FC", "FR",
+ "FLC", "FRC", "RL", "RC", "RR",
+ "RLC", "RRC", "SL", "SR", "LFE",
+ "FLW", "FRW", "FLH",
+ "FCH", "FCH", "FRH",
+ "TC"
+};
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+static void print_channels(int channels, int *map)
+{
+ int i;
+ printf(" ");
+ for (i = 0; i < channels; i++) {
+ unsigned int c = *map++;
+ if (c >= ARRAY_SIZE(chname))
+ printf(" Ch%d", c);
+ else
+ printf(" %s", chname[c]);
+ }
+ printf("\n");
+}
+
+static int to_channel(const char *name)
+{
+ unsigned int i;
+
+ if (isdigit(*name))
+ return atoi(name);
+ for (i = 0; i < ARRAY_SIZE(chname); i++)
+ if (!strcmp(chname[i], name))
+ return i;
+ return 0;
+}
+
+static const char *chmap_type(int type)
+{
+ switch (type) {
+ case SND_CHMAP_NONE:
+ return "None";
+ case SND_CHMAP_FIXED:
+ return "Fixed";
+ case SND_CHMAP_VAR:
+ return "Variable";
+ case SND_CHMAP_PAIRED:
+ return "Paired";
+ default:
+ return "Unknown";
+ }
+}
+
+static int query_chmaps(snd_pcm_t *pcm)
+{
+ int **maps = snd_pcm_query_chmaps(pcm);
+ int **p, *v;
+
+ if (!maps) {
+ printf("Cannot query maps\n");
+ return 1;
+ }
+ for (p = maps; (v = *p) != NULL; p++) {
+ printf("Type = %s, Channels = %d\n", chmap_type(v[0]), v[1]);
+ print_channels(v[1], v + 2);
+ }
+ snd_pcm_free_chmaps(maps);
+ return 0;
+}
+
+static int setup_pcm(snd_pcm_t *pcm, int format, int channels, int rate)
+{
+ snd_pcm_hw_params_t *params;
+
+ snd_pcm_hw_params_alloca(&params);
+ if (snd_pcm_hw_params_any(pcm, params) < 0) {
+ printf("Cannot init hw_params\n");
+ return -1;
+ }
+ if (format != SND_PCM_FORMAT_UNKNOWN) {
+ if (snd_pcm_hw_params_set_format(pcm, params, format) < 0) {
+ printf("Cannot set format %s\n",
+ snd_pcm_format_name(format));
+ return -1;
+ }
+ }
+ if (channels > 0) {
+ if (snd_pcm_hw_params_set_channels(pcm, params, channels) < 0) {
+ printf("Cannot set channels %d\n", channels);
+ return -1;
+ }
+ }
+ if (rate > 0) {
+ if (snd_pcm_hw_params_set_rate_near(pcm, params, (unsigned int *)&rate, 0) < 0) {
+ printf("Cannot set rate %d\n", rate);
+ return -1;
+ }
+ }
+ if (snd_pcm_hw_params(pcm, params) < 0) {
+ printf("Cannot set hw_params\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int get_chmap(snd_pcm_t *pcm, int format, int channels, int rate)
+{
+ int *map;
+
+ if (setup_pcm(pcm, format, channels, rate))
+ return 1;
+ map = snd_pcm_get_chmap(pcm);
+ if (!map) {
+ printf("Cannot get chmap\n");
+ return 1;
+ }
+ printf("Channels = %d\n", *map);
+ print_channels(*map, map + 1);
+ free(map);
+ return 0;
+}
+
+static int set_chmap(snd_pcm_t *pcm, int format, int channels, int rate,
+ int nargs, char **arg)
+{
+ int i;
+ int *map;
+
+ if (channels && channels != nargs) {
+ printf("Inconsistent channels %d vs %d\n", channels, nargs);
+ return 1;
+ }
+ if (!channels) {
+ if (!nargs) {
+ printf("No channels are given\n");
+ return 1;
+ }
+ channels = nargs;
+ }
+ if (setup_pcm(pcm, format, channels, rate))
+ return 1;
+ map = malloc(sizeof(int) * channels + 1);
+ if (!map) {
+ printf("cannot malloc\n");
+ return 1;
+ }
+ *map = channels;
+ for (i = 0; i < channels; i++)
+ map[i + 1] = to_channel(arg[i]);
+ if (snd_pcm_set_chmap(pcm, map) < 0) {
+ printf("Cannot set chmap\n");
+ return 1;
+ }
+ free(map);
+
+ map = snd_pcm_get_chmap(pcm);
+ if (!map) {
+ printf("Cannot get chmap\n");
+ return 1;
+ }
+ printf("Get channels = %d\n", *map);
+ print_channels(*map, map + 1);
+ free(map);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ char *device = NULL;
+ int stream = SND_PCM_STREAM_PLAYBACK;
+ int format = SND_PCM_FORMAT_UNKNOWN;
+ int channels = 0;
+ int rate = 0;
+ snd_pcm_t *pcm;
+ int c;
+
+ while ((c = getopt(argc, argv, "D:s:f:c:r:")) != -1) {
+ switch (c) {
+ case 'D':
+ device = optarg;
+ break;
+ case 's':
+ if (*optarg == 'c' || *optarg == 'C')
+ stream = SND_PCM_STREAM_CAPTURE;
+ else
+ stream = SND_PCM_STREAM_PLAYBACK;
+ break;
+ case 'f':
+ format = snd_pcm_format_value(optarg);
+ break;
+ case 'c':
+ channels = atoi(optarg);
+ break;
+ case 'r':
+ rate = atoi(optarg);
+ break;
+ default:
+ usage();
+ return 1;
+ }
+ }
+
+ if (argc <= optind) {
+ usage();
+ return 1;
+ }
+
+ if (!device) {
+ printf("No device is specified\n");
+ return 1;
+ }
+
+ if (snd_pcm_open(&pcm, device, stream, SND_PCM_NONBLOCK) < 0) {
+ printf("Cannot open PCM stream %s for %s\n", device,
+ snd_pcm_stream_name(stream));
+ return 1;
+ }
+
+ switch (*argv[optind]) {
+ case 'q':
+ return query_chmaps(pcm);
+ case 'g':
+ return get_chmap(pcm, format, channels, rate);
+ case 's':
+ return set_chmap(pcm, format, channels, rate,
+ argc - optind - 1, argv + optind + 1);
+ }
+ usage();
+ return 1;
+}

View File

@ -0,0 +1,188 @@
From 34f6545520de73be55ee6c29a7ebd3c016fa9f06 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 30 Jul 2012 18:21:43 +0200
Subject: [PATCH 05/30] Cache the chmap operation errors
... not to retry the same error again.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
src/pcm/pcm_hw.c | 66 +++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 54 insertions(+), 12 deletions(-)
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -105,6 +105,8 @@ typedef struct {
snd_pcm_format_t format;
int rate;
int channels;
+ /* for chmap */
+ unsigned int chmap_caps;
} snd_pcm_hw_t;
#define SNDRV_FILE_PCM_STREAM_PLAYBACK ALSA_DEVICE_DIRECTORY "pcmC%iD%ip"
@@ -1022,6 +1024,27 @@ static int is_chmap_type(int type)
type <= SND_CTL_TLVT_CHMAP_PAIRED);
}
+enum { CHMAP_CTL_QUERY, CHMAP_CTL_GET, CHMAP_CTL_SET };
+
+static int chmap_caps(snd_pcm_hw_t *hw, int type)
+{
+ if (hw->chmap_caps & (1 << type))
+ return 1;
+ if (hw->chmap_caps & (1 << (type + 8)))
+ return 0;
+ return 1;
+}
+
+static void chmap_caps_set_ok(snd_pcm_hw_t *hw, int type)
+{
+ hw->chmap_caps |= (1 << type);
+}
+
+static void chmap_caps_set_error(snd_pcm_hw_t *hw, int type)
+{
+ hw->chmap_caps |= (1 << (type + 8));
+}
+
static int **snd_pcm_hw_query_chmaps(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private_data;
@@ -1031,10 +1054,13 @@ static int **snd_pcm_hw_query_chmaps(snd
int **map;
int i, ret, nums;
+ if (!chmap_caps(hw, CHMAP_CTL_QUERY))
+ return NULL;
+
ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0);
if (ret < 0) {
SYSMSG("Cannot open the associated CTL\n");
- return NULL;
+ goto error;
}
snd_ctl_elem_id_alloca(&id);
@@ -1043,7 +1069,7 @@ static int **snd_pcm_hw_query_chmaps(snd
snd_ctl_close(ctl);
if (ret < 0) {
SYSMSG("Cannot read Channel Map TLV\n");
- return NULL;
+ goto error;
}
#if 0
@@ -1053,7 +1079,7 @@ static int **snd_pcm_hw_query_chmaps(snd
if (tlv[0] != SND_CTL_TLVT_CONTAINER) {
if (!is_chmap_type(tlv[0])) {
SYSMSG("Invalid TLV type %d\n", tlv[0]);
- return NULL;
+ goto error;
}
start = tlv;
nums = 1;
@@ -1066,7 +1092,7 @@ static int **snd_pcm_hw_query_chmaps(snd
for (p = start; size > 0; ) {
if (!is_chmap_type(p[0])) {
SYSMSG("Invalid TLV type %d\n", p[0]);
- return NULL;
+ goto error;
}
nums++;
size -= p[1] + 8;
@@ -1078,19 +1104,20 @@ static int **snd_pcm_hw_query_chmaps(snd
return NULL;
for (i = 0; i < nums; i++) {
map[i] = malloc(start[1] + 8);
- if (!map[i])
- goto nomem;
+ if (!map[i]) {
+ snd_pcm_free_chmaps(map);
+ return NULL;
+ }
map[i][0] = start[0] - 0x100;
map[i][1] = start[1] / 4;
memcpy(map[i] + 2, start + 2, start[1]);
start += start[1] / 4 + 2;
}
+ chmap_caps_set_ok(hw, CHMAP_CTL_QUERY);
return map;
- nomem:
- for (; i >= 0; i--)
- free(map[i]);
- free(map);
+ error:
+ chmap_caps_set_error(hw, CHMAP_CTL_QUERY);
return NULL;
}
@@ -1104,6 +1131,9 @@ static int *snd_pcm_hw_get_chmap(snd_pcm
unsigned int i;
int ret;
+ if (!chmap_caps(hw, CHMAP_CTL_GET))
+ return NULL;
+
switch (FAST_PCM_STATE(hw)) {
case SNDRV_PCM_STATE_PREPARED:
case SNDRV_PCM_STATE_RUNNING:
@@ -1125,6 +1155,7 @@ static int *snd_pcm_hw_get_chmap(snd_pcm
if (ret < 0) {
free(map);
SYSMSG("Cannot open the associated CTL\n");
+ chmap_caps_set_error(hw, CHMAP_CTL_GET);
return NULL;
}
snd_ctl_elem_value_alloca(&val);
@@ -1132,15 +1163,16 @@ static int *snd_pcm_hw_get_chmap(snd_pcm
fill_chmap_ctl_id(pcm, id);
snd_ctl_elem_value_set_id(val, id);
ret = snd_ctl_elem_read(ctl, val);
+ snd_ctl_close(ctl);
if (ret < 0) {
- snd_ctl_close(ctl);
free(map);
SYSMSG("Cannot read Channel Map ctl\n");
+ chmap_caps_set_error(hw, CHMAP_CTL_GET);
return NULL;
}
for (i = 0; i < pcm->channels; i++)
map[i + 1] = snd_ctl_elem_value_get_integer(val, i);
- snd_ctl_close(ctl);
+ chmap_caps_set_ok(hw, CHMAP_CTL_GET);
return map;
}
@@ -1152,6 +1184,9 @@ static int snd_pcm_hw_set_chmap(snd_pcm_
snd_ctl_elem_value_t *val;
int i, ret;
+ if (!chmap_caps(hw, CHMAP_CTL_SET))
+ return -ENXIO;
+
if (*map < 0 || *map > 128) {
SYSMSG("Invalid number of channels %d\n", *map);
return -EINVAL;
@@ -1164,6 +1199,7 @@ static int snd_pcm_hw_set_chmap(snd_pcm_
ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0);
if (ret < 0) {
SYSMSG("Cannot open the associated CTL\n");
+ chmap_caps_set_error(hw, CHMAP_CTL_SET);
return ret;
}
snd_ctl_elem_id_alloca(&id);
@@ -1174,6 +1210,12 @@ static int snd_pcm_hw_set_chmap(snd_pcm_
snd_ctl_elem_value_set_integer(val, i, map[i + 1]);
ret = snd_ctl_elem_write(ctl, val);
snd_ctl_close(ctl);
+ if (ret >= 0)
+ chmap_caps_set_ok(hw, CHMAP_CTL_SET);
+ else if (ret == -ENOENT || ret == -EPERM || ret == -ENXIO) {
+ chmap_caps_set_error(hw, CHMAP_CTL_SET);
+ ret = -ENXIO;
+ }
if (ret < 0)
SYSMSG("Cannot write Channel Map ctl\n");
return ret;

View File

@ -0,0 +1,56 @@
From 915b26bfe8af876d467a37c336c6bf22d5e370fe Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Tue, 21 Aug 2012 12:16:39 +0200
Subject: [PATCH 06/30] Define channel map position enum in pcm.h
The original definition is in sound/asound.h, but we need to export to
alsa-lib users, too.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/pcm.h | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -474,13 +474,39 @@ int snd_pcm_wait(snd_pcm_t *pcm, int tim
int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2);
int snd_pcm_unlink(snd_pcm_t *pcm);
-enum {
+/** channel map list type */
+enum snd_pcm_chmap_type {
SND_CHMAP_NONE = 0, /** unspecified channel position */
SND_CHMAP_FIXED, /** fixed channel position */
SND_CHMAP_VAR, /** freely swappable channel position */
SND_CHMAP_PAIRED, /** pair-wise swappable channel position */
};
+/** channel positions */
+enum snd_pcm_chmap_position {
+ SND_CHMAP_UNKNOWN = 0, /** unspecified */
+ SND_CHMAP_FL, /** front left */
+ SND_CHMAP_FC, /** front center */
+ SND_CHMAP_FR, /** front right */
+ SND_CHMAP_FLC, /** front left center */
+ SND_CHMAP_FRC, /* front right center */
+ SND_CHMAP_RL, /** rear left */
+ SND_CHMAP_RC, /** rear center */
+ SND_CHMAP_RR, /** rear right */
+ SND_CHMAP_RLC, /** rear left center */
+ SND_CHMAP_RRC, /** rear right center */
+ SND_CHMAP_SL, /** side left */
+ SND_CHMAP_SR, /** side right */
+ SND_CHMAP_LFE, /** LFE */
+ SND_CHMAP_FLW, /** front left wide */
+ SND_CHMAP_FRW, /** front right wide */
+ SND_CHMAP_FLH, /** front left high */
+ SND_CHMAP_FCH, /** front center high */
+ SND_CHMAP_FRH, /** front right high */
+ SND_CHMAP_TC, /** top center */
+ SND_CHMAP_LAST = SND_CHMAP_TC, /** last entry */
+};
+
int **snd_pcm_query_chmaps(snd_pcm_t *pcm);
void snd_pcm_free_chmaps(int **maps);
int *snd_pcm_get_chmap(snd_pcm_t *pcm);

View File

@ -0,0 +1,110 @@
From 0f36270dd315b9baf3a93f5586776b91c0bcf589 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Tue, 21 Aug 2012 15:07:44 +0200
Subject: [PATCH 07/30] Follow channel position definitions to mixer channel
in mixer.h
mixer.h already contains some channel position definitions.
To be more consistent over all systems, better to follow the same
order for the new channel map, too. But since UNKNOWN channel must be
zero but the definition in mixer.h contains -1 as UNKNOWN, simply
shift the value with 1.
If the conversion is required between SND_CHMAP and SND_MIXER_SCHN,
just increment/decrement 1. Eventually I'll provide helper functions
for that...
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/pcm.h | 14 +++++++-------
include/sound/asound.h | 16 +++++++++-------
test/chmap.c | 11 ++++-------
3 files changed, 20 insertions(+), 21 deletions(-)
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -486,18 +486,18 @@ enum snd_pcm_chmap_type {
enum snd_pcm_chmap_position {
SND_CHMAP_UNKNOWN = 0, /** unspecified */
SND_CHMAP_FL, /** front left */
- SND_CHMAP_FC, /** front center */
SND_CHMAP_FR, /** front right */
- SND_CHMAP_FLC, /** front left center */
- SND_CHMAP_FRC, /* front right center */
SND_CHMAP_RL, /** rear left */
- SND_CHMAP_RC, /** rear center */
SND_CHMAP_RR, /** rear right */
- SND_CHMAP_RLC, /** rear left center */
- SND_CHMAP_RRC, /** rear right center */
+ SND_CHMAP_FC, /** front center */
+ SND_CHMAP_LFE, /** LFE */
SND_CHMAP_SL, /** side left */
SND_CHMAP_SR, /** side right */
- SND_CHMAP_LFE, /** LFE */
+ SND_CHMAP_RC, /** rear center */
+ SND_CHMAP_FLC, /** front left center */
+ SND_CHMAP_FRC, /** front right center */
+ SND_CHMAP_RLC, /** rear left center */
+ SND_CHMAP_RRC, /** rear right center */
SND_CHMAP_FLW, /** front left wide */
SND_CHMAP_FRW, /** front right wide */
SND_CHMAP_FLH, /** front left high */
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -479,20 +479,22 @@ enum {
/* channel positions */
enum {
+ /* this follows the alsa-lib mixer channel value + 1*/
SNDRV_CHMAP_UNKNOWN = 0,
SNDRV_CHMAP_FL, /* front left */
- SNDRV_CHMAP_FC, /* front center */
SNDRV_CHMAP_FR, /* front right */
- SNDRV_CHMAP_FLC, /* front left center */
- SNDRV_CHMAP_FRC, /* front right center */
SNDRV_CHMAP_RL, /* rear left */
- SNDRV_CHMAP_RC, /* rear center */
SNDRV_CHMAP_RR, /* rear right */
- SNDRV_CHMAP_RLC, /* rear left center */
- SNDRV_CHMAP_RRC, /* rear right center */
+ SNDRV_CHMAP_FC, /* front center */
+ SNDRV_CHMAP_LFE, /* LFE */
SNDRV_CHMAP_SL, /* side left */
SNDRV_CHMAP_SR, /* side right */
- SNDRV_CHMAP_LFE, /* LFE */
+ SNDRV_CHMAP_RC, /* rear center */
+ /* new definitions */
+ SNDRV_CHMAP_FLC, /* front left center */
+ SNDRV_CHMAP_FRC, /* front right center */
+ SNDRV_CHMAP_RLC, /* rear left center */
+ SNDRV_CHMAP_RRC, /* rear right center */
SNDRV_CHMAP_FLW, /* front left wide */
SNDRV_CHMAP_FRW, /* front right wide */
SNDRV_CHMAP_FLH, /* front left high */
--- a/test/chmap.c
+++ b/test/chmap.c
@@ -23,12 +23,9 @@ static void usage(void)
static const char * const chname[] = {
"Unknown",
- "FL", "FC", "FR",
- "FLC", "FRC", "RL", "RC", "RR",
- "RLC", "RRC", "SL", "SR", "LFE",
- "FLW", "FRW", "FLH",
- "FCH", "FCH", "FRH",
- "TC"
+ "FL", "FR", "RL", "RR", "FC", "LFE", "SL", "SR", "RC",
+ "FLC", "FRC", "RLC", "RRC", "FLW", "FRW", "FLH",
+ "FCH", "FCH", "FRH", "TC"
};
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
@@ -56,7 +53,7 @@ static int to_channel(const char *name)
for (i = 0; i < ARRAY_SIZE(chname); i++)
if (!strcmp(chname[i], name))
return i;
- return 0;
+ return SND_CHMAP_UNKNOWN;
}
static const char *chmap_type(int type)

View File

@ -0,0 +1,88 @@
From 48c2c90f19f07d02082d9fb84fb36ac1fcfa84e1 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Fri, 31 Aug 2012 13:53:22 -0700
Subject: [PATCH 08/30] Add SND_CHMAP_NA and bit flag definitions
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/pcm.h | 7 ++++++-
include/sound/asound.h | 9 +++++++--
test/chmap.c | 14 ++++++++++----
3 files changed, 23 insertions(+), 7 deletions(-)
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -504,9 +504,14 @@ enum snd_pcm_chmap_position {
SND_CHMAP_FCH, /** front center high */
SND_CHMAP_FRH, /** front right high */
SND_CHMAP_TC, /** top center */
- SND_CHMAP_LAST = SND_CHMAP_TC, /** last entry */
+ SND_CHMAP_NA, /** N/A, silent */
+ SND_CHMAP_LAST = SND_CHMAP_NA, /** last entry */
};
+#define SND_CHMAP_POSITION_MASK 0xffff /** bitmask for channel position */
+#define SND_CHMAP_PHASE_INVERSE (0x01 << 16) /* the channel is phase inverted */
+#define SND_CHMAP_DRIVER_SPEC (0x02 << 16) /* non-standard channel value */
+
int **snd_pcm_query_chmaps(snd_pcm_t *pcm);
void snd_pcm_free_chmaps(int **maps);
int *snd_pcm_get_chmap(snd_pcm_t *pcm);
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -479,7 +479,7 @@ enum {
/* channel positions */
enum {
- /* this follows the alsa-lib mixer channel value + 1*/
+ /* this follows the alsa-lib mixer channel value + 1 */
SNDRV_CHMAP_UNKNOWN = 0,
SNDRV_CHMAP_FL, /* front left */
SNDRV_CHMAP_FR, /* front right */
@@ -501,9 +501,14 @@ enum {
SNDRV_CHMAP_FCH, /* front center high */
SNDRV_CHMAP_FRH, /* front right high */
SNDRV_CHMAP_TC, /* top center */
- SNDRV_CHMAP_LAST = SNDRV_CHMAP_TC,
+ SNDRV_CHMAP_NA, /* N/A, silent */
+ SNDRV_CHMAP_LAST = SNDRV_CHMAP_NA,
};
+#define SNDRV_CHMAP_POSITION_MASK 0xffff
+#define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16)
+#define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16)
+
enum {
SNDRV_PCM_IOCTL_PVERSION = _IOR('A', 0x00, int),
SNDRV_PCM_IOCTL_INFO = _IOR('A', 0x01, struct sndrv_pcm_info),
--- a/test/chmap.c
+++ b/test/chmap.c
@@ -25,7 +25,8 @@ static const char * const chname[] = {
"Unknown",
"FL", "FR", "RL", "RR", "FC", "LFE", "SL", "SR", "RC",
"FLC", "FRC", "RLC", "RRC", "FLW", "FRW", "FLH",
- "FCH", "FCH", "FRH", "TC"
+ "FCH", "FCH", "FRH", "TC",
+ "N/A",
};
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
@@ -36,10 +37,15 @@ static void print_channels(int channels,
printf(" ");
for (i = 0; i < channels; i++) {
unsigned int c = *map++;
- if (c >= ARRAY_SIZE(chname))
- printf(" Ch%d", c);
+ unsigned int pos = c & SND_CHMAP_POSITION_MASK;
+ if (c & SND_CHMAP_DRIVER_SPEC)
+ printf(" %d", p);
+ else if (p >= ARRAY_SIZE(chname))
+ printf(" Ch%d", p);
else
- printf(" %s", chname[c]);
+ printf(" %s", chname[p]);
+ if (c & SND_CHMAP_PHASE_INVERSE)
+ printf("[INV]");
}
printf("\n");
}

View File

@ -0,0 +1,587 @@
From 9c1a0ce72d71e4728d45dcd3986dd0ef0201dd67 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Tue, 4 Sep 2012 17:26:43 +0200
Subject: [PATCH 09/30] PCM: Introduce snd_pcm_chmap_t and
snd_pcm_chmap_query_t
Instead of passing ambiguous integer array, define snd_pcm_chmap_t and
snd_pcm_chmap_query_t so that user can understand more easily which
element is for what.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/pcm.h | 21 +++++++++++++++++----
include/pcm_extplug.h | 6 +++---
include/pcm_ioplug.h | 6 +++---
src/pcm/pcm.c | 10 +++++-----
src/pcm/pcm_direct.c | 6 +++---
src/pcm/pcm_direct.h | 6 +++---
src/pcm/pcm_extplug.c | 6 +++---
src/pcm/pcm_generic.c | 6 +++---
src/pcm/pcm_generic.h | 6 +++---
src/pcm/pcm_hw.c | 31 ++++++++++++++++---------------
src/pcm/pcm_ioplug.c | 6 +++---
src/pcm/pcm_local.h | 6 +++---
src/pcm/pcm_multi.c | 25 ++++++++++++++-----------
src/pcm/pcm_route.c | 10 +++++-----
test/chmap.c | 35 ++++++++++++++++++-----------------
15 files changed, 102 insertions(+), 84 deletions(-)
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -512,10 +512,23 @@ enum snd_pcm_chmap_position {
#define SND_CHMAP_PHASE_INVERSE (0x01 << 16) /* the channel is phase inverted */
#define SND_CHMAP_DRIVER_SPEC (0x02 << 16) /* non-standard channel value */
-int **snd_pcm_query_chmaps(snd_pcm_t *pcm);
-void snd_pcm_free_chmaps(int **maps);
-int *snd_pcm_get_chmap(snd_pcm_t *pcm);
-int snd_pcm_set_chmap(snd_pcm_t *pcm, const int *map);
+/** the channel map header */
+typedef struct snd_pcm_chmap {
+ unsigned int channels;
+ unsigned int pos[0];
+} snd_pcm_chmap_t;
+
+/** the header of array items returned from snd_pcm_query_chmaps() */
+typedef struct snd_pcm_chmap_query {
+ enum snd_pcm_chmap_type type;
+ snd_pcm_chmap_t map;
+} snd_pcm_chmap_query_t;
+
+
+snd_pcm_chmap_query_t **snd_pcm_query_chmaps(snd_pcm_t *pcm);
+void snd_pcm_free_chmaps(snd_pcm_chmap_query_t **maps);
+snd_pcm_chmap_t *snd_pcm_get_chmap(snd_pcm_t *pcm);
+int snd_pcm_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map);
//int snd_pcm_mixer_element(snd_pcm_t *pcm, snd_mixer_t *mixer, snd_mixer_elem_t **elem);
--- a/include/pcm_extplug.h
+++ b/include/pcm_extplug.h
@@ -154,15 +154,15 @@ struct snd_pcm_extplug_callback {
/**
* query the channel maps; optional; since v1.0.2
*/
- int **(*query_chmaps)(snd_pcm_extplug_t *ext);
+ snd_pcm_chmap_query_t **(*query_chmaps)(snd_pcm_extplug_t *ext);
/**
* get the channel map; optional; since v1.0.2
*/
- int *(*get_chmap)(snd_pcm_extplug_t *ext);
+ snd_pcm_chmap_t *(*get_chmap)(snd_pcm_extplug_t *ext);
/**
* set the channel map; optional; since v1.0.2
*/
- int (*set_chmap)(snd_pcm_extplug_t *ext, const int *map);
+ int (*set_chmap)(snd_pcm_extplug_t *ext, const snd_pcm_chmap_t *map);
};
--- a/include/pcm_ioplug.h
+++ b/include/pcm_ioplug.h
@@ -192,15 +192,15 @@ struct snd_pcm_ioplug_callback {
/**
* query the channel maps; optional; since v1.0.2
*/
- int **(*query_chmaps)(snd_pcm_ioplug_t *io);
+ snd_pcm_chmap_query_t **(*query_chmaps)(snd_pcm_ioplug_t *io);
/**
* get the channel map; optional; since v1.0.2
*/
- int *(*get_chmap)(snd_pcm_ioplug_t *io);
+ snd_pcm_chmap_t *(*get_chmap)(snd_pcm_ioplug_t *io);
/**
* set the channel map; optional; since v1.0.2
*/
- int (*set_chmap)(snd_pcm_ioplug_t *io, const int *map);
+ int (*set_chmap)(snd_pcm_ioplug_t *io, const snd_pcm_chmap_t *map);
};
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -7310,7 +7310,7 @@ OBSOLETE1(snd_pcm_sw_params_get_silence_
* integer array, beginning with the channel map type, followed by the
* number of channels, and the position of each channel.
*/
-int **snd_pcm_query_chmaps(snd_pcm_t *pcm)
+snd_pcm_chmap_query_t **snd_pcm_query_chmaps(snd_pcm_t *pcm)
{
if (!pcm->ops->query_chmaps)
return NULL;
@@ -7321,9 +7321,9 @@ int **snd_pcm_query_chmaps(snd_pcm_t *pc
* \!brief Release the channel map array allocated via #snd_pcm_query_chmaps
* \param maps the array pointer to release
*/
-void snd_pcm_free_chmaps(int **maps)
+void snd_pcm_free_chmaps(snd_pcm_chmap_query_t **maps)
{
- int **p;
+ snd_pcm_chmap_query_t **p = maps;
if (!maps)
return;
for (p = maps; *p; p++)
@@ -7336,7 +7336,7 @@ void snd_pcm_free_chmaps(int **maps)
* \param pcm PCM instance
* \return the current channel map, or NULL if error
*/
-int *snd_pcm_get_chmap(snd_pcm_t *pcm)
+snd_pcm_chmap_t *snd_pcm_get_chmap(snd_pcm_t *pcm)
{
if (!pcm->ops->get_chmap)
return NULL;
@@ -7349,7 +7349,7 @@ int *snd_pcm_get_chmap(snd_pcm_t *pcm)
* \param map the channel map to write
* \return zero if succeeded, or a negative error code
*/
-int snd_pcm_set_chmap(snd_pcm_t *pcm, const int *map)
+int snd_pcm_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
{
if (!pcm->ops->set_chmap)
return -ENXIO;
--- a/src/pcm/pcm_direct.c
+++ b/src/pcm/pcm_direct.c
@@ -789,19 +789,19 @@ int snd_pcm_direct_munmap(snd_pcm_t *pcm
return 0;
}
-int **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm)
+snd_pcm_chmap_query_t **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm)
{
snd_pcm_direct_t *dmix = pcm->private_data;
return snd_pcm_query_chmaps(dmix->spcm);
}
-int *snd_pcm_direct_get_chmap(snd_pcm_t *pcm)
+snd_pcm_chmap_t *snd_pcm_direct_get_chmap(snd_pcm_t *pcm)
{
snd_pcm_direct_t *dmix = pcm->private_data;
return snd_pcm_get_chmap(dmix->spcm);
}
-int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const int *map)
+int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
{
snd_pcm_direct_t *dmix = pcm->private_data;
return snd_pcm_set_chmap(dmix->spcm, map);
--- a/src/pcm/pcm_direct.h
+++ b/src/pcm/pcm_direct.h
@@ -296,9 +296,9 @@ void snd_pcm_direct_clear_timer_queue(sn
int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix);
int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name);
-int **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm);
-int *snd_pcm_direct_get_chmap(snd_pcm_t *pcm);
-int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const int *map);
+snd_pcm_chmap_query_t **snd_pcm_direct_query_chmaps(snd_pcm_t *pcm);
+snd_pcm_chmap_t *snd_pcm_direct_get_chmap(snd_pcm_t *pcm);
+int snd_pcm_direct_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map);
int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);
--- a/src/pcm/pcm_extplug.c
+++ b/src/pcm/pcm_extplug.c
@@ -425,7 +425,7 @@ static int snd_pcm_extplug_close(snd_pcm
return 0;
}
-static int **snd_pcm_extplug_query_chmaps(snd_pcm_t *pcm)
+static snd_pcm_chmap_query_t **snd_pcm_extplug_query_chmaps(snd_pcm_t *pcm)
{
extplug_priv_t *ext = pcm->private_data;
@@ -435,7 +435,7 @@ static int **snd_pcm_extplug_query_chmap
return snd_pcm_generic_query_chmaps(pcm);
}
-static int *snd_pcm_extplug_get_chmap(snd_pcm_t *pcm)
+static snd_pcm_chmap_t *snd_pcm_extplug_get_chmap(snd_pcm_t *pcm)
{
extplug_priv_t *ext = pcm->private_data;
@@ -445,7 +445,7 @@ static int *snd_pcm_extplug_get_chmap(sn
return snd_pcm_generic_get_chmap(pcm);
}
-static int snd_pcm_extplug_set_chmap(snd_pcm_t *pcm, const int *map)
+static int snd_pcm_extplug_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
{
extplug_priv_t *ext = pcm->private_data;
--- a/src/pcm/pcm_generic.c
+++ b/src/pcm/pcm_generic.c
@@ -323,19 +323,19 @@ int snd_pcm_generic_munmap(snd_pcm_t *pc
return 0;
}
-int **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm)
+snd_pcm_chmap_query_t **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm)
{
snd_pcm_generic_t *generic = pcm->private_data;
return snd_pcm_query_chmaps(generic->slave);
}
-int *snd_pcm_generic_get_chmap(snd_pcm_t *pcm)
+snd_pcm_chmap_t *snd_pcm_generic_get_chmap(snd_pcm_t *pcm)
{
snd_pcm_generic_t *generic = pcm->private_data;
return snd_pcm_get_chmap(generic->slave);
}
-int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const int *map)
+int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
{
snd_pcm_generic_t *generic = pcm->private_data;
return snd_pcm_set_chmap(generic->slave, map);
--- a/src/pcm/pcm_generic.h
+++ b/src/pcm/pcm_generic.h
@@ -155,8 +155,8 @@ int snd_pcm_generic_real_htimestamp(snd_
snd_htimestamp_t *tstamp);
int snd_pcm_generic_mmap(snd_pcm_t *pcm);
int snd_pcm_generic_munmap(snd_pcm_t *pcm);
-int **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm);
-int *snd_pcm_generic_get_chmap(snd_pcm_t *pcm);
-int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const int *map);
+snd_pcm_chmap_query_t **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm);
+snd_pcm_chmap_t *snd_pcm_generic_get_chmap(snd_pcm_t *pcm);
+int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map);
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -1045,13 +1045,13 @@ static void chmap_caps_set_error(snd_pcm
hw->chmap_caps |= (1 << (type + 8));
}
-static int **snd_pcm_hw_query_chmaps(snd_pcm_t *pcm)
+static snd_pcm_chmap_query_t **snd_pcm_hw_query_chmaps(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private_data;
snd_ctl_t *ctl;
snd_ctl_elem_id_t *id;
unsigned int tlv[256], *start;
- int **map;
+ snd_pcm_chmap_query_t **map;
int i, ret, nums;
if (!chmap_caps(hw, CHMAP_CTL_QUERY))
@@ -1108,9 +1108,9 @@ static int **snd_pcm_hw_query_chmaps(snd
snd_pcm_free_chmaps(map);
return NULL;
}
- map[i][0] = start[0] - 0x100;
- map[i][1] = start[1] / 4;
- memcpy(map[i] + 2, start + 2, start[1]);
+ map[i]->type = start[0] - 0x100;
+ map[i]->map.channels = start[1] / 4;
+ memcpy(map[i]->map.pos, start + 2, start[1]);
start += start[1] / 4 + 2;
}
chmap_caps_set_ok(hw, CHMAP_CTL_QUERY);
@@ -1121,10 +1121,10 @@ static int **snd_pcm_hw_query_chmaps(snd
return NULL;
}
-static int *snd_pcm_hw_get_chmap(snd_pcm_t *pcm)
+static snd_pcm_chmap_t *snd_pcm_hw_get_chmap(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private_data;
- int *map;
+ snd_pcm_chmap_t *map;
snd_ctl_t *ctl;
snd_ctl_elem_id_t *id;
snd_ctl_elem_value_t *val;
@@ -1150,7 +1150,7 @@ static int *snd_pcm_hw_get_chmap(snd_pcm
map = malloc(pcm->channels + 1);
if (!map)
return NULL;
- *map = pcm->channels;
+ map->channels = pcm->channels;
ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0);
if (ret < 0) {
free(map);
@@ -1171,24 +1171,25 @@ static int *snd_pcm_hw_get_chmap(snd_pcm
return NULL;
}
for (i = 0; i < pcm->channels; i++)
- map[i + 1] = snd_ctl_elem_value_get_integer(val, i);
+ map->pos[i] = snd_ctl_elem_value_get_integer(val, i);
chmap_caps_set_ok(hw, CHMAP_CTL_GET);
return map;
}
-static int snd_pcm_hw_set_chmap(snd_pcm_t *pcm, const int *map)
+static int snd_pcm_hw_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
{
snd_pcm_hw_t *hw = pcm->private_data;
snd_ctl_t *ctl;
snd_ctl_elem_id_t *id;
snd_ctl_elem_value_t *val;
- int i, ret;
+ unsigned int i;
+ int ret;
if (!chmap_caps(hw, CHMAP_CTL_SET))
return -ENXIO;
- if (*map < 0 || *map > 128) {
- SYSMSG("Invalid number of channels %d\n", *map);
+ if (map->channels > 128) {
+ SYSMSG("Invalid number of channels %d\n", map->channels);
return -EINVAL;
}
if (FAST_PCM_STATE(hw) != SNDRV_PCM_STATE_PREPARED) {
@@ -1206,8 +1207,8 @@ static int snd_pcm_hw_set_chmap(snd_pcm_
snd_ctl_elem_value_alloca(&val);
fill_chmap_ctl_id(pcm, id);
snd_ctl_elem_value_set_id(val, id);
- for (i = 0; i < *map; i++)
- snd_ctl_elem_value_set_integer(val, i, map[i + 1]);
+ for (i = 0; i < map->channels; i++)
+ snd_ctl_elem_value_set_integer(val, i, map->pos[i]);
ret = snd_ctl_elem_write(ctl, val);
snd_ctl_close(ctl);
if (ret >= 0)
--- a/src/pcm/pcm_ioplug.c
+++ b/src/pcm/pcm_ioplug.c
@@ -710,7 +710,7 @@ static int snd_pcm_ioplug_munmap(snd_pcm
return 0;
}
-static int **snd_pcm_ioplug_query_chmaps(snd_pcm_t *pcm)
+static snd_pcm_chmap_query_t **snd_pcm_ioplug_query_chmaps(snd_pcm_t *pcm)
{
ioplug_priv_t *io = pcm->private_data;
@@ -720,7 +720,7 @@ static int **snd_pcm_ioplug_query_chmaps
return NULL;
}
-static int *snd_pcm_ioplug_get_chmap(snd_pcm_t *pcm)
+static snd_pcm_chmap_t *snd_pcm_ioplug_get_chmap(snd_pcm_t *pcm)
{
ioplug_priv_t *io = pcm->private_data;
@@ -730,7 +730,7 @@ static int *snd_pcm_ioplug_get_chmap(snd
return NULL;
}
-static int snd_pcm_ioplug_set_chmap(snd_pcm_t *pcm, const int *map)
+static int snd_pcm_ioplug_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
{
ioplug_priv_t *io = pcm->private_data;
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -143,9 +143,9 @@ typedef struct {
void (*dump)(snd_pcm_t *pcm, snd_output_t *out);
int (*mmap)(snd_pcm_t *pcm);
int (*munmap)(snd_pcm_t *pcm);
- int **(*query_chmaps)(snd_pcm_t *pcm);
- int *(*get_chmap)(snd_pcm_t *pcm);
- int (*set_chmap)(snd_pcm_t *pcm, const int *map);
+ snd_pcm_chmap_query_t **(*query_chmaps)(snd_pcm_t *pcm);
+ snd_pcm_chmap_t *(*get_chmap)(snd_pcm_t *pcm);
+ int (*set_chmap)(snd_pcm_t *pcm, const snd_pcm_chmap_t *map);
} snd_pcm_ops_t;
typedef struct {
--- a/src/pcm/pcm_multi.c
+++ b/src/pcm/pcm_multi.c
@@ -739,10 +739,10 @@ static int snd_pcm_multi_mmap(snd_pcm_t
return 0;
}
-static int *snd_pcm_multi_get_chmap(snd_pcm_t *pcm)
+static snd_pcm_chmap_t *snd_pcm_multi_get_chmap(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private_data;
- int *map;
+ snd_pcm_chmap_t *map;
unsigned int i, idx;
map = malloc(pcm->channels + 4);
@@ -750,34 +750,37 @@ static int *snd_pcm_multi_get_chmap(snd_
return NULL;
idx = 0;
for (i = 0; i < multi->slaves_count; ++i) {
- int c, *slave_map;
+ unsigned int c;
+ snd_pcm_chmap_t *slave_map;
slave_map = snd_pcm_get_chmap(multi->slaves[i].pcm);
if (!slave_map) {
free(map);
return NULL;
}
- for (c = 0; c < *slave_map; c++) {
+ for (c = 0; c < slave_map->channels; c++) {
if (idx >= pcm->channels)
break;
- map[idx++] = slave_map[c + 1];
+ map->pos[idx++] = slave_map->pos[c];
}
free(slave_map);
}
return map;
}
-static int snd_pcm_multi_set_chmap(snd_pcm_t *pcm, const int *map)
+static int snd_pcm_multi_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
{
snd_pcm_multi_t *multi = pcm->private_data;
+ const unsigned int *pos;
unsigned int i, idx, chs;
int err;
- chs = *map;
+ chs = map->channels;
if (chs != pcm->channels)
return -EINVAL;
- map++;
+ pos = map->pos;
+ idx = 0;
for (i = 0; i < multi->slaves_count; ++i) {
- int *slave_map;
+ snd_pcm_chmap_t *slave_map;
unsigned int slave_chs;
slave_chs = multi->slaves[i].channels_count;
if (idx + slave_chs > chs)
@@ -785,8 +788,8 @@ static int snd_pcm_multi_set_chmap(snd_p
slave_map = malloc(slave_chs * 4 + 4);
if (!slave_map)
return -ENOMEM;
- *slave_map = slave_chs;
- memcpy(slave_map, map + idx, slave_chs * 4);
+ slave_map->channels = slave_chs;
+ memcpy(slave_map->pos, pos + idx, slave_chs * 4);
err = snd_pcm_set_chmap(multi->slaves[i].pcm, slave_map);
free(slave_map);
if (err < 0)
--- a/src/pcm/pcm_route.c
+++ b/src/pcm/pcm_route.c
@@ -703,10 +703,10 @@ snd_pcm_route_read_areas(snd_pcm_t *pcm,
return size;
}
-static int *snd_pcm_route_get_chmap(snd_pcm_t *pcm)
+static snd_pcm_chmap_t *snd_pcm_route_get_chmap(snd_pcm_t *pcm)
{
snd_pcm_route_t *route = pcm->private_data;
- int *map, *slave_map;
+ snd_pcm_chmap_t *map, *slave_map;
unsigned int src, dst;
slave_map = snd_pcm_generic_get_chmap(pcm);
@@ -717,13 +717,13 @@ static int *snd_pcm_route_get_chmap(snd_
free(slave_map);
return NULL;
}
- *map = route->schannels;
+ map->channels = route->schannels;
for (dst = 0; dst < route->params.ndsts; dst++) {
snd_pcm_route_ttable_dst_t *d = &route->params.dsts[dst];
for (src = 0; src < d->nsrcs; src++) {
int c = d->srcs[src].channel;
- if (c < route->schannels && !map[c + 1])
- map[c + 1] = slave_map[dst + 1];
+ if (c < route->schannels && !map->pos[c])
+ map->pos[c] = slave_map->pos[dst];
}
}
free(slave_map);
--- a/test/chmap.c
+++ b/test/chmap.c
@@ -31,13 +31,14 @@ static const char * const chname[] = {
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
-static void print_channels(int channels, int *map)
+static void print_channels(const snd_pcm_chmap_t *map)
{
- int i;
+ unsigned int i;
+
printf(" ");
- for (i = 0; i < channels; i++) {
- unsigned int c = *map++;
- unsigned int pos = c & SND_CHMAP_POSITION_MASK;
+ for (i = 0; i < map->channels; i++) {
+ unsigned int c = map->pos[i];
+ unsigned int p = c & SND_CHMAP_POSITION_MASK;
if (c & SND_CHMAP_DRIVER_SPEC)
printf(" %d", p);
else if (p >= ARRAY_SIZE(chname))
@@ -80,16 +81,16 @@ static const char *chmap_type(int type)
static int query_chmaps(snd_pcm_t *pcm)
{
- int **maps = snd_pcm_query_chmaps(pcm);
- int **p, *v;
+ snd_pcm_chmap_query_t **maps = snd_pcm_query_chmaps(pcm);
+ snd_pcm_chmap_query_t **p, *v;
if (!maps) {
printf("Cannot query maps\n");
return 1;
}
for (p = maps; (v = *p) != NULL; p++) {
- printf("Type = %s, Channels = %d\n", chmap_type(v[0]), v[1]);
- print_channels(v[1], v + 2);
+ printf("Type = %s, Channels = %d\n", chmap_type(v->type), v->map.channels);
+ print_channels(&v->map);
}
snd_pcm_free_chmaps(maps);
return 0;
@@ -132,7 +133,7 @@ static int setup_pcm(snd_pcm_t *pcm, int
static int get_chmap(snd_pcm_t *pcm, int format, int channels, int rate)
{
- int *map;
+ snd_pcm_chmap_t *map;
if (setup_pcm(pcm, format, channels, rate))
return 1;
@@ -141,8 +142,8 @@ static int get_chmap(snd_pcm_t *pcm, int
printf("Cannot get chmap\n");
return 1;
}
- printf("Channels = %d\n", *map);
- print_channels(*map, map + 1);
+ printf("Channels = %d\n", map->channels);
+ print_channels(map);
free(map);
return 0;
}
@@ -151,7 +152,7 @@ static int set_chmap(snd_pcm_t *pcm, int
int nargs, char **arg)
{
int i;
- int *map;
+ snd_pcm_chmap_t *map;
if (channels && channels != nargs) {
printf("Inconsistent channels %d vs %d\n", channels, nargs);
@@ -171,9 +172,9 @@ static int set_chmap(snd_pcm_t *pcm, int
printf("cannot malloc\n");
return 1;
}
- *map = channels;
+ map->channels = channels;
for (i = 0; i < channels; i++)
- map[i + 1] = to_channel(arg[i]);
+ map->pos[i] = to_channel(arg[i]);
if (snd_pcm_set_chmap(pcm, map) < 0) {
printf("Cannot set chmap\n");
return 1;
@@ -185,8 +186,8 @@ static int set_chmap(snd_pcm_t *pcm, int
printf("Cannot get chmap\n");
return 1;
}
- printf("Get channels = %d\n", *map);
- print_channels(*map, map + 1);
+ printf("Get channels = %d\n", map->channels);
+ print_channels(map);
free(map);
return 0;
}

View File

@ -0,0 +1,207 @@
From 01dc0e6825b5620510faaefaef40ff8cfb692b6e Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Fri, 7 Sep 2012 14:15:04 +0200
Subject: [PATCH 10/30] PCM: Implement snd_pcm_query_chmaps_from_hw()
This is a function similar like snd_pcm_query_chmaps() but performs
the query without a PCM handle. The card, device and substream
numbers are passed as well as stream direction.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/pcm.h | 3 +
src/pcm/pcm_hw.c | 117 +++++++++++++++++++++++++++++++++++--------------------
2 files changed, 79 insertions(+), 41 deletions(-)
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -526,6 +526,9 @@ typedef struct snd_pcm_chmap_query {
snd_pcm_chmap_query_t **snd_pcm_query_chmaps(snd_pcm_t *pcm);
+snd_pcm_chmap_query_t **snd_pcm_query_chmaps_from_hw(int card, int dev,
+ int subdev,
+ snd_pcm_stream_t stream);
void snd_pcm_free_chmaps(snd_pcm_chmap_query_t **maps);
snd_pcm_chmap_t *snd_pcm_get_chmap(snd_pcm_t *pcm);
int snd_pcm_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map);
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -1006,80 +1006,82 @@ static int snd_pcm_hw_htimestamp(snd_pcm
return 0;
}
-static void fill_chmap_ctl_id(snd_pcm_t *pcm, snd_ctl_elem_id_t *id)
+static void __fill_chmap_ctl_id(snd_ctl_elem_id_t *id, int dev, int subdev,
+ int stream)
{
- snd_pcm_hw_t *hw = pcm->private_data;
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM);
- if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ if (stream == SND_PCM_STREAM_PLAYBACK)
snd_ctl_elem_id_set_name(id, "Playback Channel Map");
else
snd_ctl_elem_id_set_name(id, "Capture Channel Map");
- snd_ctl_elem_id_set_device(id, hw->device);
- snd_ctl_elem_id_set_index(id, hw->subdevice);
-}
-
-static int is_chmap_type(int type)
-{
- return (type >= SND_CTL_TLVT_CHMAP_FIXED &&
- type <= SND_CTL_TLVT_CHMAP_PAIRED);
-}
-
-enum { CHMAP_CTL_QUERY, CHMAP_CTL_GET, CHMAP_CTL_SET };
-
-static int chmap_caps(snd_pcm_hw_t *hw, int type)
-{
- if (hw->chmap_caps & (1 << type))
- return 1;
- if (hw->chmap_caps & (1 << (type + 8)))
- return 0;
- return 1;
+ snd_ctl_elem_id_set_device(id, dev);
+ snd_ctl_elem_id_set_index(id, subdev);
}
-static void chmap_caps_set_ok(snd_pcm_hw_t *hw, int type)
+static void fill_chmap_ctl_id(snd_pcm_t *pcm, snd_ctl_elem_id_t *id)
{
- hw->chmap_caps |= (1 << type);
+ snd_pcm_hw_t *hw = pcm->private_data;
+ return __fill_chmap_ctl_id(id, hw->device, hw->subdevice, pcm->stream);
}
-static void chmap_caps_set_error(snd_pcm_hw_t *hw, int type)
+static int is_chmap_type(int type)
{
- hw->chmap_caps |= (1 << (type + 8));
+ return (type >= SND_CTL_TLVT_CHMAP_FIXED &&
+ type <= SND_CTL_TLVT_CHMAP_PAIRED);
}
-static snd_pcm_chmap_query_t **snd_pcm_hw_query_chmaps(snd_pcm_t *pcm)
+/**
+ * \!brief Query the available channel maps
+ * \param card the card number
+ * \param dev the PCM device number
+ * \param subdev the PCM substream index
+ * \param stream the direction of PCM stream
+ * \return the NULL-terminated array of integer pointers, or NULL at error.
+ *
+ * This function works like snd_pcm_query_chmaps() but it takes the card,
+ * device, substream and stream numbers instead of the already opened
+ * snd_pcm_t instance, so that you can query available channel maps of
+ * a PCM before actually opening it.
+ *
+ * As the parameters stand, the query is performed only to the hw PCM
+ * devices, not the abstracted PCM object in alsa-lib.
+ */
+snd_pcm_chmap_query_t **
+snd_pcm_query_chmaps_from_hw(int card, int dev, int subdev,
+ snd_pcm_stream_t stream)
{
- snd_pcm_hw_t *hw = pcm->private_data;
snd_ctl_t *ctl;
snd_ctl_elem_id_t *id;
unsigned int tlv[256], *start;
snd_pcm_chmap_query_t **map;
int i, ret, nums;
- if (!chmap_caps(hw, CHMAP_CTL_QUERY))
- return NULL;
-
- ret = snd_ctl_hw_open(&ctl, NULL, hw->card, 0);
+ ret = snd_ctl_hw_open(&ctl, NULL, card, 0);
if (ret < 0) {
SYSMSG("Cannot open the associated CTL\n");
- goto error;
+ return NULL;
}
snd_ctl_elem_id_alloca(&id);
- fill_chmap_ctl_id(pcm, id);
+ __fill_chmap_ctl_id(id, dev, subdev, stream);
ret = snd_ctl_elem_tlv_read(ctl, id, tlv, sizeof(tlv));
snd_ctl_close(ctl);
if (ret < 0) {
SYSMSG("Cannot read Channel Map TLV\n");
- goto error;
+ return NULL;
}
#if 0
for (i = 0; i < 32; i++)
fprintf(stderr, "%02x: %08x\n", i, tlv[i]);
#endif
+ /* FIXME: the parser below assumes that the TLV only contains
+ * chmap-related blocks
+ */
if (tlv[0] != SND_CTL_TLVT_CONTAINER) {
if (!is_chmap_type(tlv[0])) {
SYSMSG("Invalid TLV type %d\n", tlv[0]);
- goto error;
+ return NULL;
}
start = tlv;
nums = 1;
@@ -1092,7 +1094,7 @@ static snd_pcm_chmap_query_t **snd_pcm_h
for (p = start; size > 0; ) {
if (!is_chmap_type(p[0])) {
SYSMSG("Invalid TLV type %d\n", p[0]);
- goto error;
+ return NULL;
}
nums++;
size -= p[1] + 8;
@@ -1113,12 +1115,45 @@ static snd_pcm_chmap_query_t **snd_pcm_h
memcpy(map[i]->map.pos, start + 2, start[1]);
start += start[1] / 4 + 2;
}
- chmap_caps_set_ok(hw, CHMAP_CTL_QUERY);
return map;
+}
+
+enum { CHMAP_CTL_QUERY, CHMAP_CTL_GET, CHMAP_CTL_SET };
+
+static int chmap_caps(snd_pcm_hw_t *hw, int type)
+{
+ if (hw->chmap_caps & (1 << type))
+ return 1;
+ if (hw->chmap_caps & (1 << (type + 8)))
+ return 0;
+ return 1;
+}
+
+static void chmap_caps_set_ok(snd_pcm_hw_t *hw, int type)
+{
+ hw->chmap_caps |= (1 << type);
+}
- error:
- chmap_caps_set_error(hw, CHMAP_CTL_QUERY);
- return NULL;
+static void chmap_caps_set_error(snd_pcm_hw_t *hw, int type)
+{
+ hw->chmap_caps |= (1 << (type + 8));
+}
+
+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 (!chmap_caps(hw, CHMAP_CTL_QUERY))
+ return NULL;
+
+ map = snd_pcm_query_chmaps_from_hw(hw->card, hw->device,
+ hw->subdevice, pcm->stream);
+ if (map)
+ chmap_caps_set_ok(hw, CHMAP_CTL_QUERY);
+ else
+ chmap_caps_set_error(hw, CHMAP_CTL_QUERY);
+ return map;
}
static snd_pcm_chmap_t *snd_pcm_hw_get_chmap(snd_pcm_t *pcm)

View File

@ -0,0 +1,21 @@
From ec96740d9919b5e0c050a4b91aebee4b1dbb8298 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Fri, 7 Sep 2012 14:31:39 +0200
Subject: [PATCH 11/30] Fix duplicated channel entry in test/chmap.c
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
test/chmap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/test/chmap.c
+++ b/test/chmap.c
@@ -25,7 +25,7 @@ static const char * const chname[] = {
"Unknown",
"FL", "FR", "RL", "RR", "FC", "LFE", "SL", "SR", "RC",
"FLC", "FRC", "RLC", "RRC", "FLW", "FRW", "FLH",
- "FCH", "FCH", "FRH", "TC",
+ "FCH", "FRH", "TC",
"N/A",
};

View File

@ -0,0 +1,32 @@
From 6950a1030c4f878b51104268e3cd13401d56bf60 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 10 Sep 2012 16:59:36 +0200
Subject: [PATCH 12/30] PCM: Fix prefix for snd_pcm_chmap_type enum members
Add _TYPE prefix to distinguish from the channel position.
Also add SND_CHMAP_TYPE_LAST entry pointing the last one like other
enums.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/pcm.h | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -476,10 +476,11 @@ int snd_pcm_unlink(snd_pcm_t *pcm);
/** channel map list type */
enum snd_pcm_chmap_type {
- SND_CHMAP_NONE = 0, /** unspecified channel position */
- SND_CHMAP_FIXED, /** fixed channel position */
- SND_CHMAP_VAR, /** freely swappable channel position */
- SND_CHMAP_PAIRED, /** pair-wise swappable channel position */
+ SND_CHMAP_TYPE_NONE = 0,/** unspecified channel position */
+ SND_CHMAP_TYPE_FIXED, /** fixed channel position */
+ SND_CHMAP_TYPE_VAR, /** freely swappable channel position */
+ SND_CHMAP_TYPE_PAIRED, /** pair-wise swappable channel position */
+ SND_CHMAP_TYPE_LAST = SND_CHMAP_TYPE_PAIRED, /** last entry */
};
/** channel positions */

View File

@ -0,0 +1,286 @@
From b4c64e815a051e711798be1d772f123d19c1ff6e Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 10 Sep 2012 18:07:36 +0200
Subject: [PATCH 13/30] PCM: Add string conversion helper functions for chmap
Added a few helper functions between chmap and string.
snd_pcm_chmap_type_name() -- a string of the given chmap type
snd_pcm_chmap_name() -- a string of the given channel position
snd_pcm_chmap_print() -- print channel map on the given buffer
snd_pcm_chmap_from_string() -- get a channel position from string
snd_pcm_parse_string() -- parse the whole channel map from string
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/pcm.h | 6 ++
src/pcm/pcm.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
test/chmap.c | 69 ++++------------------------
3 files changed, 160 insertions(+), 57 deletions(-)
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -534,6 +534,12 @@ void snd_pcm_free_chmaps(snd_pcm_chmap_q
snd_pcm_chmap_t *snd_pcm_get_chmap(snd_pcm_t *pcm);
int snd_pcm_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map);
+const char *snd_pcm_chmap_type_name(enum snd_pcm_chmap_type val);
+const char *snd_pcm_chmap_name(enum snd_pcm_chmap_position val);
+int snd_pcm_chmap_print(const snd_pcm_chmap_t *map, size_t maxlen, char *buf);
+unsigned int snd_pcm_chmap_from_string(const char *str);
+snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *str);
+
//int snd_pcm_mixer_element(snd_pcm_t *pcm, snd_mixer_t *mixer, snd_mixer_elem_t **elem);
/*
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -633,6 +633,7 @@ playback devices.
#include <malloc.h>
#include <stdarg.h>
#include <signal.h>
+#include <ctype.h>
#include <sys/poll.h>
#include <sys/shm.h>
#include <sys/mman.h>
@@ -7356,6 +7357,147 @@ int snd_pcm_set_chmap(snd_pcm_t *pcm, co
return pcm->ops->set_chmap(pcm, map);
}
+/*
+ */
+#define _NAME(n) [SND_CHMAP_TYPE_##n] = #n
+static const char *chmap_type_names[SND_CHMAP_TYPE_LAST + 1] = {
+ _NAME(NONE), _NAME(FIXED), _NAME(VAR), _NAME(PAIRED),
+};
+#undef _NAME
+
+const char *snd_pcm_chmap_type_name(enum snd_pcm_chmap_type val)
+{
+ if (val <= SND_CHMAP_TYPE_LAST)
+ return chmap_type_names[val];
+ else
+ return NULL;
+}
+
+#define _NAME(n) [SND_CHMAP_##n] = #n
+static const char *chmap_names[SND_CHMAP_LAST + 1] = {
+ _NAME(UNKNOWN),
+ _NAME(FL), _NAME(FR),
+ _NAME(RL), _NAME(RR),
+ _NAME(FC), _NAME(LFE),
+ _NAME(SL), _NAME(SR),
+ _NAME(RC), _NAME(FLC), _NAME(FRC), _NAME(RLC), _NAME(RRC),
+ _NAME(FLW), _NAME(FRW),
+ _NAME(FLH), _NAME(FCH), _NAME(FRH), _NAME(TC),
+ _NAME(NA),
+};
+#undef _NAME
+
+const char *snd_pcm_chmap_name(enum snd_pcm_chmap_position val)
+{
+ if (val <= SND_CHMAP_LAST)
+ return chmap_names[val];
+ else
+ return NULL;
+}
+
+int snd_pcm_chmap_print(const snd_pcm_chmap_t *map, size_t maxlen, char *buf)
+{
+ unsigned int i, len = 0;
+
+ for (i = 0; i < map->channels; i++) {
+ unsigned int p = map->pos[i] & SND_CHMAP_POSITION_MASK;
+ if (i > 0) {
+ len += snprintf(buf + len, maxlen - len, " ");
+ if (len >= maxlen)
+ return -ENOMEM;
+ }
+ if (map->pos[i] & SND_CHMAP_DRIVER_SPEC)
+ len += snprintf(buf + len, maxlen, "%d", p);
+ else {
+ const char *name = chmap_names[p];
+ if (name)
+ len += snprintf(buf + len, maxlen - len,
+ "%s", name);
+ else
+ len += snprintf(buf + len, maxlen - len,
+ "Ch%d", p);
+ }
+ if (len >= maxlen)
+ return -ENOMEM;
+ if (map->pos[i] & SND_CHMAP_PHASE_INVERSE) {
+ len += snprintf(buf + len, maxlen - len, "[INV]");
+ if (len >= maxlen)
+ return -ENOMEM;
+ }
+ }
+ return len;
+}
+
+static int str_to_chmap(const char *str, int len)
+{
+ int val;
+
+ if (isdigit(*str)) {
+ val = atoi(str);
+ if (val < 0)
+ return -1;
+ return val | SND_CHMAP_DRIVER_SPEC;
+ } else if (str[0] == 'C' && str[1] == 'h') {
+ val = atoi(str + 2);
+ if (val < 0)
+ return -1;
+ return val;
+ } else {
+ for (val = 0; val <= SND_CHMAP_LAST; val++) {
+ if (!strncmp(str, chmap_names[val], len))
+ return val;
+ }
+ return -1;
+ }
+}
+
+unsigned int snd_pcm_chmap_from_string(const char *str)
+{
+ return str_to_chmap(str, strlen(str));
+}
+
+snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *str)
+{
+ int i, ch = 0;
+ int tmp_map[64];
+ snd_pcm_chmap_t *map;
+
+ for (;;) {
+ const char *p;
+ int len, val;
+
+ if (ch >= (int)(sizeof(tmp_map) / sizeof(tmp_map[0])))
+ return NULL;
+ for (p = str; *p && isalnum(*p); p++)
+ ;
+ len = p - str;
+ if (!len)
+ return NULL;
+ val = str_to_chmap(str, len);
+ if (val < 0)
+ return NULL;
+ str += len;
+ if (*str == '[') {
+ if (!strncmp(str, "[INV]", 5)) {
+ val |= SND_CHMAP_PHASE_INVERSE;
+ str += 5;
+ }
+ }
+ tmp_map[ch] = val;
+ ch++;
+ for (; *str && !isalnum(*str); str++)
+ ;
+ if (!*str)
+ break;
+ }
+ map = malloc(sizeof(*map) + ch * sizeof(int));
+ if (!map)
+ return NULL;
+ map->channels = ch;
+ for (i = 0; i < ch; i++)
+ map->pos[i] = tmp_map[i];
+ return map;
+}
/*
* basic helpers
--- a/test/chmap.c
+++ b/test/chmap.c
@@ -21,62 +21,11 @@ static void usage(void)
" -r rate Sample rate\n");
}
-static const char * const chname[] = {
- "Unknown",
- "FL", "FR", "RL", "RR", "FC", "LFE", "SL", "SR", "RC",
- "FLC", "FRC", "RLC", "RRC", "FLW", "FRW", "FLH",
- "FCH", "FRH", "TC",
- "N/A",
-};
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
-
static void print_channels(const snd_pcm_chmap_t *map)
{
- unsigned int i;
-
- printf(" ");
- for (i = 0; i < map->channels; i++) {
- unsigned int c = map->pos[i];
- unsigned int p = c & SND_CHMAP_POSITION_MASK;
- if (c & SND_CHMAP_DRIVER_SPEC)
- printf(" %d", p);
- else if (p >= ARRAY_SIZE(chname))
- printf(" Ch%d", p);
- else
- printf(" %s", chname[p]);
- if (c & SND_CHMAP_PHASE_INVERSE)
- printf("[INV]");
- }
- printf("\n");
-}
-
-static int to_channel(const char *name)
-{
- unsigned int i;
-
- if (isdigit(*name))
- return atoi(name);
- for (i = 0; i < ARRAY_SIZE(chname); i++)
- if (!strcmp(chname[i], name))
- return i;
- return SND_CHMAP_UNKNOWN;
-}
-
-static const char *chmap_type(int type)
-{
- switch (type) {
- case SND_CHMAP_NONE:
- return "None";
- case SND_CHMAP_FIXED:
- return "Fixed";
- case SND_CHMAP_VAR:
- return "Variable";
- case SND_CHMAP_PAIRED:
- return "Paired";
- default:
- return "Unknown";
- }
+ char tmp[128];
+ if (snd_pcm_chmap_print(map, sizeof(tmp), tmp) > 0)
+ printf(" %s\n", tmp);
}
static int query_chmaps(snd_pcm_t *pcm)
@@ -89,7 +38,9 @@ static int query_chmaps(snd_pcm_t *pcm)
return 1;
}
for (p = maps; (v = *p) != NULL; p++) {
- printf("Type = %s, Channels = %d\n", chmap_type(v->type), v->map.channels);
+ printf("Type = %s, Channels = %d\n",
+ snd_pcm_chmap_type_name(v->type),
+ v->map.channels);
print_channels(&v->map);
}
snd_pcm_free_chmaps(maps);
@@ -173,8 +124,12 @@ static int set_chmap(snd_pcm_t *pcm, int
return 1;
}
map->channels = channels;
- for (i = 0; i < channels; i++)
- map->pos[i] = to_channel(arg[i]);
+ for (i = 0; i < channels; i++) {
+ int val = snd_pcm_chmap_from_string(arg[i]);
+ if (val < 0)
+ val = SND_CHMAP_UNKNOWN;
+ map->pos[i] = val;
+ }
if (snd_pcm_set_chmap(pcm, map) < 0) {
printf("Cannot set chmap\n");
return 1;

View File

@ -0,0 +1,25 @@
From fe81684745e5c121e2d110bf6955e3f2858d2c7c Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Tue, 11 Sep 2012 11:33:31 +0200
Subject: [PATCH 14/30] PCM: Add SND_CHMAP_API_VERSION definition
Just to make it easier for apps to support chmap conditionally via
simple ifdefs.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/pcm.h | 3 +++
1 file changed, 3 insertions(+)
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -474,6 +474,9 @@ int snd_pcm_wait(snd_pcm_t *pcm, int tim
int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2);
int snd_pcm_unlink(snd_pcm_t *pcm);
+/** channel mapping API version number */
+#define SND_CHMAP_API_VERSION ((1 << 16) | (0 << 8) | 0)
+
/** channel map list type */
enum snd_pcm_chmap_type {
SND_CHMAP_TYPE_NONE = 0,/** unspecified channel position */

View File

@ -0,0 +1,65 @@
From 25f3259b48e921886bda58075936de3d53b84bc1 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Tue, 11 Sep 2012 12:48:46 +0200
Subject: [PATCH 15/30] PCM: Add snd_pcm_chmap_long_name()
Just return a more verbose name than snd_pcm_chmap_name(), but
including white spaces.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/pcm.h | 1 +
src/pcm/pcm.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 33 insertions(+)
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -539,6 +539,7 @@ int snd_pcm_set_chmap(snd_pcm_t *pcm, co
const char *snd_pcm_chmap_type_name(enum snd_pcm_chmap_type val);
const char *snd_pcm_chmap_name(enum snd_pcm_chmap_position val);
+const char *snd_pcm_chmap_long_name(enum snd_pcm_chmap_position val);
int snd_pcm_chmap_print(const snd_pcm_chmap_t *map, size_t maxlen, char *buf);
unsigned int snd_pcm_chmap_from_string(const char *str);
snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *str);
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -7395,6 +7395,38 @@ const char *snd_pcm_chmap_name(enum snd_
return NULL;
}
+static const char *chmap_long_names[SND_CHMAP_LAST + 1] = {
+ [SND_CHMAP_UNKNOWN] = "Unknown",
+ [SND_CHMAP_FL] = "Front Left",
+ [SND_CHMAP_FR] = "Front Right",
+ [SND_CHMAP_RL] = "Rear Left",
+ [SND_CHMAP_RR] = "Rear Right",
+ [SND_CHMAP_FC] = "Front Center",
+ [SND_CHMAP_LFE] = "LFE",
+ [SND_CHMAP_SL] = "Side Left",
+ [SND_CHMAP_SR] = "Side Right",
+ [SND_CHMAP_RC] = "Rear Center",
+ [SND_CHMAP_FLC] = "Front Left Center",
+ [SND_CHMAP_FRC] = "Front Right Center",
+ [SND_CHMAP_RLC] = "Rear Left Center",
+ [SND_CHMAP_RRC] = "Rear Right Center",
+ [SND_CHMAP_FLW] = "Front Left Wide",
+ [SND_CHMAP_FRW] = "Front Right Wide",
+ [SND_CHMAP_FLH] = "Front Left High",
+ [SND_CHMAP_FCH] = "Front Center High",
+ [SND_CHMAP_FRH] = "Front Right High",
+ [SND_CHMAP_TC] = "Top Center",
+ [SND_CHMAP_NA] = "Unused",
+};
+
+const char *snd_pcm_chmap_long_name(enum snd_pcm_chmap_position val)
+{
+ if (val <= SND_CHMAP_LAST)
+ return chmap_long_names[val];
+ else
+ return NULL;
+}
+
int snd_pcm_chmap_print(const snd_pcm_chmap_t *map, size_t maxlen, char *buf)
{
unsigned int i, len = 0;

View File

@ -0,0 +1,198 @@
From 81135aac49c8a3b547181d44f78ffe2594db5dbe Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 12 Sep 2012 12:56:14 +0200
Subject: [PATCH 16/30] PCM: Add query_chmaps support to multi plugin
Also fix some bugs in get_chmap().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
src/pcm/pcm_multi.c | 152 +++++++++++++++++++++++++++++++++++++---------------
1 file changed, 111 insertions(+), 41 deletions(-)
--- a/src/pcm/pcm_multi.c
+++ b/src/pcm/pcm_multi.c
@@ -739,64 +739,134 @@ static int snd_pcm_multi_mmap(snd_pcm_t
return 0;
}
+static snd_pcm_chmap_query_t **snd_pcm_multi_query_chmaps(snd_pcm_t *pcm)
+{
+ snd_pcm_multi_t *multi = pcm->private_data;
+ snd_pcm_chmap_query_t **slave_maps[multi->slaves_count];
+ snd_pcm_chmap_query_t **maps;
+ unsigned int i;
+ int err = -ENOMEM;
+
+ memset(slave_maps, 0, sizeof(slave_maps));
+ maps = calloc(2, sizeof(*maps));
+ if (!maps)
+ return NULL;
+ maps[0] = calloc(multi->channels_count + 2, sizeof(int *));
+ if (!maps[0])
+ goto error;
+ maps[0]->type = SND_CHMAP_TYPE_FIXED;
+ maps[0]->map.channels = multi->channels_count;
+
+ for (i = 0; i < multi->slaves_count; i++) {
+ slave_maps[i] = snd_pcm_query_chmaps(multi->slaves[i].pcm);
+ if (!slave_maps[i])
+ goto error;
+ }
+
+ for (i = 0; i < multi->channels_count; i++) {
+ snd_pcm_multi_channel_t *bind = &multi->channels[i];
+ unsigned int slave_channels =
+ multi->slaves[bind->slave_idx].channels_count;
+ snd_pcm_chmap_query_t **p;
+
+ for (p = slave_maps[bind->slave_idx]; *p; p++) {
+ if ((*p)->map.channels == slave_channels) {
+ maps[0]->map.pos[i] =
+ (*p)->map.pos[bind->slave_channel];
+ break;
+ }
+ }
+ }
+ err = 0;
+
+ error:
+ for (i = 0; i < multi->slaves_count; i++) {
+ if (slave_maps[i])
+ snd_pcm_free_chmaps(slave_maps[i]);
+ }
+
+ if (err) {
+ snd_pcm_free_chmaps(maps);
+ return NULL;
+ }
+
+ return maps;
+}
+
static snd_pcm_chmap_t *snd_pcm_multi_get_chmap(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private_data;
snd_pcm_chmap_t *map;
- unsigned int i, idx;
+ snd_pcm_chmap_t *slave_maps[multi->slaves_count];
+ unsigned int i;
+ int err = -ENOMEM;
- map = malloc(pcm->channels + 4);
+ memset(slave_maps, 0, sizeof(slave_maps));
+ map = calloc(multi->channels_count + 1, sizeof(int));
if (!map)
return NULL;
- idx = 0;
- for (i = 0; i < multi->slaves_count; ++i) {
- unsigned int c;
- snd_pcm_chmap_t *slave_map;
- slave_map = snd_pcm_get_chmap(multi->slaves[i].pcm);
- if (!slave_map) {
- free(map);
- return NULL;
- }
- for (c = 0; c < slave_map->channels; c++) {
- if (idx >= pcm->channels)
- break;
- map->pos[idx++] = slave_map->pos[c];
- }
- free(slave_map);
+
+ for (i = 0; i < multi->slaves_count; i++) {
+ slave_maps[i] = snd_pcm_get_chmap(multi->slaves[i].pcm);
+ if (!slave_maps[i])
+ goto error;
}
+
+ map->channels = multi->channels_count;
+ for (i = 0; i < multi->channels_count; i++) {
+ snd_pcm_multi_channel_t *bind = &multi->channels[i];
+ map->pos[i] = slave_maps[bind->slave_idx]->pos[bind->slave_channel];
+ }
+ err = 0;
+
+ error:
+ for (i = 0; i < multi->slaves_count; i++)
+ free(slave_maps[i]);
+
+ if (err) {
+ free(map);
+ return NULL;
+ }
+
return map;
}
static int snd_pcm_multi_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
{
snd_pcm_multi_t *multi = pcm->private_data;
- const unsigned int *pos;
- unsigned int i, idx, chs;
- int err;
+ snd_pcm_chmap_t *slave_maps[multi->slaves_count];
+ unsigned int i;
+ int err = 0;
- chs = map->channels;
- if (chs != pcm->channels)
+ if (map->channels != multi->channels_count)
return -EINVAL;
- pos = map->pos;
- idx = 0;
- for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_chmap_t *slave_map;
- unsigned int slave_chs;
- slave_chs = multi->slaves[i].channels_count;
- if (idx + slave_chs > chs)
- break;
- slave_map = malloc(slave_chs * 4 + 4);
- if (!slave_map)
- return -ENOMEM;
- slave_map->channels = slave_chs;
- memcpy(slave_map->pos, pos + idx, slave_chs * 4);
- err = snd_pcm_set_chmap(multi->slaves[i].pcm, slave_map);
- free(slave_map);
+
+ for (i = 0; i < multi->slaves_count; i++) {
+ slave_maps[i] = calloc(multi->slaves[i].channels_count + 1,
+ sizeof(int));
+ if (!slave_maps[i]) {
+ err = -ENOMEM;
+ goto error;
+ }
+ }
+
+ for (i = 0; i < multi->channels_count; i++) {
+ snd_pcm_multi_channel_t *bind = &multi->channels[i];
+ slave_maps[bind->slave_idx]->pos[bind->slave_channel] =
+ map->pos[i];
+ }
+
+ for (i = 0; i < multi->slaves_count; i++) {
+ err = snd_pcm_set_chmap(multi->slaves[i].pcm, slave_maps[i]);
if (err < 0)
- return err;
- idx += slave_chs;
+ goto error;
}
- return 0;
+
+ error:
+ for (i = 0; i < multi->slaves_count; i++)
+ free(slave_maps[i]);
+
+ return err;
}
static void snd_pcm_multi_dump(snd_pcm_t *pcm, snd_output_t *out)
@@ -835,7 +905,7 @@ static const snd_pcm_ops_t snd_pcm_multi
.async = snd_pcm_multi_async,
.mmap = snd_pcm_multi_mmap,
.munmap = snd_pcm_multi_munmap,
- .query_chmaps = NULL, /* NYI */
+ .query_chmaps = snd_pcm_multi_query_chmaps,
.get_chmap = snd_pcm_multi_get_chmap,
.set_chmap = snd_pcm_multi_set_chmap,
};

View File

@ -0,0 +1,249 @@
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);

View File

@ -0,0 +1,85 @@
From a102028a5a747ecdf1d6fcd16aef0994477a951b Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 12 Sep 2012 15:09:57 +0200
Subject: [PATCH 18/30] PCM: Add the missing query_chmaps for route plugin
Also fix the channel count in get_chmap for route plugin.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
src/pcm/pcm_route.c | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
--- a/src/pcm/pcm_route.c
+++ b/src/pcm/pcm_route.c
@@ -67,6 +67,7 @@ typedef struct {
int use_getput;
unsigned int src_size;
snd_pcm_format_t dst_sfmt;
+ unsigned int nsrcs;
unsigned int ndsts;
snd_pcm_route_ttable_dst_t *dsts;
} snd_pcm_route_params_t;
@@ -707,22 +708,23 @@ static snd_pcm_chmap_t *snd_pcm_route_ge
{
snd_pcm_route_t *route = pcm->private_data;
snd_pcm_chmap_t *map, *slave_map;
- unsigned int src, dst;
+ unsigned int src, dst, nsrcs;
slave_map = snd_pcm_generic_get_chmap(pcm);
if (!slave_map)
return NULL;
- map = calloc(4, route->schannels + 1);
+ nsrcs = route->params.nsrcs;
+ map = calloc(4, nsrcs + 1);
if (!map) {
free(slave_map);
return NULL;
}
- map->channels = route->schannels;
+ map->channels = nsrcs;
for (dst = 0; dst < route->params.ndsts; dst++) {
snd_pcm_route_ttable_dst_t *d = &route->params.dsts[dst];
for (src = 0; src < d->nsrcs; src++) {
int c = d->srcs[src].channel;
- if (c < route->schannels && !map->pos[c])
+ if (c < nsrcs && !map->pos[c])
map->pos[c] = slave_map->pos[dst];
}
}
@@ -730,6 +732,17 @@ static snd_pcm_chmap_t *snd_pcm_route_ge
return map;
}
+static snd_pcm_chmap_query_t **snd_pcm_route_query_chmaps(snd_pcm_t *pcm)
+{
+ snd_pcm_chmap_query_t **maps;
+ snd_pcm_chmap_t *map = snd_pcm_route_get_chmap(pcm);
+ if (!map)
+ return NULL;
+ maps = _snd_pcm_make_single_query_chmaps(map);
+ free(map);
+ return maps;
+}
+
static void snd_pcm_route_dump(snd_pcm_t *pcm, snd_output_t *out)
{
snd_pcm_route_t *route = pcm->private_data;
@@ -787,7 +800,7 @@ static const snd_pcm_ops_t snd_pcm_route
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
- .query_chmaps = NULL, /* NYI */
+ .query_chmaps = snd_pcm_route_query_chmaps,
.get_chmap = snd_pcm_route_get_chmap,
.set_chmap = NULL, /* NYI */
};
@@ -812,6 +825,7 @@ static int route_load_ttable(snd_pcm_rou
dmul = tt_ssize;
}
params->ndsts = dused;
+ params->nsrcs = sused;
dptr = calloc(dused, sizeof(*params->dsts));
if (!dptr)
return -ENOMEM;

View File

@ -0,0 +1,104 @@
From 5ba11d69dafbd4502469fd957b4580169779664c Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 12 Sep 2012 15:15:32 +0200
Subject: [PATCH 19/30] Add chmap override definitions for Emu10k1, Audigy and
Audigy2 cards
These cards won't provide the channel maps from the driver itself
because of the dynamic routing. For simplicity, define chmaps in the
configurations, so that chmap querying of individual stereo streams
and combined multi streams works properly.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
src/conf/cards/Audigy.conf | 3 +++
src/conf/cards/Audigy2.conf | 4 ++++
src/conf/cards/EMU10K1.conf | 3 +++
3 files changed, 10 insertions(+)
--- a/src/conf/cards/Audigy.conf
+++ b/src/conf/cards/Audigy.conf
@@ -13,6 +13,7 @@ Audigy.pcm.front.0 {
slave.pcm {
type hw
card $CARD
+ chmap "FL,FR"
}
hooks.0 {
type ctl_elems
@@ -65,6 +66,7 @@ Audigy.pcm.rear.0 {
slave.pcm {
type hw
card $CARD
+ chmap "RL,RR"
}
hooks.0 {
type ctl_elems
@@ -100,6 +102,7 @@ Audigy.pcm.center_lfe.0 {
slave.pcm {
type hw
card $CARD
+ chmap "FC,LFE"
}
hooks.0 {
type ctl_elems
--- a/src/conf/cards/Audigy2.conf
+++ b/src/conf/cards/Audigy2.conf
@@ -13,6 +13,7 @@ Audigy2.pcm.front.0 {
slave.pcm {
type hw
card $CARD
+ chmap "FL,FR"
}
hooks.0 {
type ctl_elems
@@ -65,6 +66,7 @@ Audigy2.pcm.rear.0 {
slave.pcm {
type hw
card $CARD
+ chmap "RL,RR"
}
hooks.0 {
type ctl_elems
@@ -100,6 +102,7 @@ Audigy2.pcm.center_lfe.0 {
slave.pcm {
type hw
card $CARD
+ chmap "FC,LFE"
}
hooks.0 {
type ctl_elems
@@ -151,6 +154,7 @@ Audigy2.pcm.side.0 {
slave.pcm {
type hw
card $CARD
+ chmap "SL,SR"
}
hooks.0 {
type ctl_elems
--- a/src/conf/cards/EMU10K1.conf
+++ b/src/conf/cards/EMU10K1.conf
@@ -15,6 +15,7 @@ EMU10K1.pcm.front.0 {
slave.pcm {
type hw
card $CARD
+ chmap "FL,FR"
}
hooks.0 {
type ctl_elems
@@ -73,6 +74,7 @@ EMU10K1.pcm.rear.0 {
slave.pcm {
type hw
card $CARD
+ chmap "RL,RR"
}
hooks.0 {
type ctl_elems
@@ -111,6 +113,7 @@ EMU10K1.pcm.center_lfe.0 {
slave.pcm {
type hw
card $CARD
+ chmap "FC,LFE"
}
hooks.0 {
type ctl_elems

View File

@ -0,0 +1,438 @@
From ec7acfc408856cfe71a122e3b5387463d7b3d919 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 12 Sep 2012 17:13:22 +0200
Subject: [PATCH 20/30] PCM: Use compounds for overriding / enhancing chmaps
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 | 6 +-
src/conf/cards/Audigy2.conf | 8 +--
src/conf/cards/EMU10K1.conf | 6 +-
src/pcm/pcm.c | 109 +++++++++++++++++++++++++++++++++++++++++---
src/pcm/pcm_hw.c | 25 ++++------
src/pcm/pcm_local.h | 10 +++-
src/pcm/pcm_null.c | 25 ++++------
7 files changed, 144 insertions(+), 45 deletions(-)
--- a/src/conf/cards/Audigy.conf
+++ b/src/conf/cards/Audigy.conf
@@ -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
--- a/src/conf/cards/Audigy2.conf
+++ b/src/conf/cards/Audigy2.conf
@@ -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
--- a/src/conf/cards/EMU10K1.conf
+++ b/src/conf/cards/EMU10K1.conf
@@ -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
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -7531,25 +7531,37 @@ snd_pcm_chmap_t *snd_pcm_chmap_parse_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
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
*/
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -107,7 +107,7 @@ typedef struct {
int channels;
/* for chmap */
unsigned int chmap_caps;
- snd_pcm_chmap_t *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_h
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_c
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, 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_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, c
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, c
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);
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -975,6 +975,12 @@ static inline void gettimestamp(snd_htim
}
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);
--- a/src/pcm/pcm_null.c
+++ b/src/pcm/pcm_null.c
@@ -44,7 +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_chmap_query_t **chmap;
} snd_pcm_null_t;
#endif
@@ -274,7 +274,7 @@ static snd_pcm_chmap_query_t **snd_pcm_n
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
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,
{
snd_config_iterator_t i, next;
snd_pcm_null_t *null;
- snd_pcm_chmap_t *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,
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,
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;

View File

@ -0,0 +1,51 @@
From 2c61a4173ff2c3d57eb77b3f66e0d0e517c799d6 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 12 Sep 2012 17:34:49 +0200
Subject: [PATCH 21/30] conf: Add chmap definitions to TRIDENT and SI7018
configurations
Manually add the channel map definitions as the channel front/rear is
determined dynamically.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
src/conf/cards/SI7018.conf | 2 ++
src/conf/cards/TRID4DWAVENX.conf | 2 ++
2 files changed, 4 insertions(+)
--- a/src/conf/cards/SI7018.conf
+++ b/src/conf/cards/SI7018.conf
@@ -13,6 +13,7 @@ SI7018.pcm.front.0 {
}
type hw
card $CARD
+ chmap [ "UNKNOWN" "FL,FR" ]
}
<confdir:pcm/rear.conf>
@@ -26,6 +27,7 @@ SI7018.pcm.rear.0 {
slave.pcm {
type hw
card $CARD
+ chmap [ "UNKNOWN" "RL,RR" ]
}
hooks.0 {
type ctl_elems
--- a/src/conf/cards/TRID4DWAVENX.conf
+++ b/src/conf/cards/TRID4DWAVENX.conf
@@ -11,6 +11,7 @@ TRID4DWAVENX.pcm.front.0 {
}
type hw
card $CARD
+ chmap [ "UNKNOWN" "FL,FR" ]
}
<confdir:pcm/rear.conf>
@@ -24,6 +25,7 @@ TRID4DWAVENX.pcm.rear.0 {
slave.pcm {
type hw
card $CARD
+ chmap [ "UNKNOWN" "RL,RR" ]
}
hooks.0 {
type ctl_elems

View File

@ -0,0 +1,21 @@
From 58c45b30309a1dd255c8b9e5cb34398658867b81 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Thu, 13 Sep 2012 08:06:26 +0200
Subject: [PATCH 22/30] test/chmap: Fix wrong malloc size
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
test/chmap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/test/chmap.c
+++ b/test/chmap.c
@@ -118,7 +118,7 @@ static int set_chmap(snd_pcm_t *pcm, int
}
if (setup_pcm(pcm, format, channels, rate))
return 1;
- map = malloc(sizeof(int) * channels + 1);
+ map = malloc(sizeof(int) * (channels + 1));
if (!map) {
printf("cannot malloc\n");
return 1;

View File

@ -0,0 +1,116 @@
From f7300682dc0fe9faec94461af6fdcf098047a0d1 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 12 Sep 2012 18:43:59 +0200
Subject: [PATCH 23/30] PCM: Define MONO and other channel map positions
Follow the new definitions in the kernel side. MONO and others have
been added, and the order of position table was changed again.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/pcm.h | 11 +++++++++--
include/sound/asound.h | 13 ++++++++++---
src/pcm/pcm.c | 14 +++++++++++---
3 files changed, 30 insertions(+), 8 deletions(-)
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -489,6 +489,8 @@ enum snd_pcm_chmap_type {
/** channel positions */
enum snd_pcm_chmap_position {
SND_CHMAP_UNKNOWN = 0, /** unspecified */
+ SND_CHMAP_NA, /** N/A, silent */
+ SND_CHMAP_MONO, /** mono stream */
SND_CHMAP_FL, /** front left */
SND_CHMAP_FR, /** front right */
SND_CHMAP_RL, /** rear left */
@@ -508,8 +510,13 @@ enum snd_pcm_chmap_position {
SND_CHMAP_FCH, /** front center high */
SND_CHMAP_FRH, /** front right high */
SND_CHMAP_TC, /** top center */
- SND_CHMAP_NA, /** N/A, silent */
- SND_CHMAP_LAST = SND_CHMAP_NA, /** last entry */
+ SND_CHMAP_TFL, /** top front left */
+ SND_CHMAP_TFR, /** top front right */
+ SND_CHMAP_TFC, /** top front center */
+ SND_CHMAP_TRL, /** top rear left */
+ SND_CHMAP_TRR, /** top rear right */
+ SND_CHMAP_TRC, /** top rear center */
+ SND_CHMAP_LAST = SND_CHMAP_TRC, /** last entry */
};
#define SND_CHMAP_POSITION_MASK 0xffff /** bitmask for channel position */
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -479,8 +479,10 @@ enum {
/* channel positions */
enum {
- /* this follows the alsa-lib mixer channel value + 1 */
SNDRV_CHMAP_UNKNOWN = 0,
+ SNDRV_CHMAP_NA, /* N/A, silent */
+ SNDRV_CHMAP_MONO, /* mono stream */
+ /* this follows the alsa-lib mixer channel value + 3 */
SNDRV_CHMAP_FL, /* front left */
SNDRV_CHMAP_FR, /* front right */
SNDRV_CHMAP_RL, /* rear left */
@@ -501,8 +503,13 @@ enum {
SNDRV_CHMAP_FCH, /* front center high */
SNDRV_CHMAP_FRH, /* front right high */
SNDRV_CHMAP_TC, /* top center */
- SNDRV_CHMAP_NA, /* N/A, silent */
- SNDRV_CHMAP_LAST = SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_TFL, /* top front left */
+ SNDRV_CHMAP_TFR, /* top front right */
+ SNDRV_CHMAP_TFC, /* top front center */
+ SNDRV_CHMAP_TRL, /* top rear left */
+ SNDRV_CHMAP_TRR, /* top rear right */
+ SNDRV_CHMAP_TRC, /* top rear center */
+ SNDRV_CHMAP_LAST = SNDRV_CHMAP_TRC,
};
#define SNDRV_CHMAP_POSITION_MASK 0xffff
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -7375,7 +7375,7 @@ const char *snd_pcm_chmap_type_name(enum
#define _NAME(n) [SND_CHMAP_##n] = #n
static const char *chmap_names[SND_CHMAP_LAST + 1] = {
- _NAME(UNKNOWN),
+ _NAME(UNKNOWN), _NAME(NA), _NAME(MONO),
_NAME(FL), _NAME(FR),
_NAME(RL), _NAME(RR),
_NAME(FC), _NAME(LFE),
@@ -7383,7 +7383,8 @@ static const char *chmap_names[SND_CHMAP
_NAME(RC), _NAME(FLC), _NAME(FRC), _NAME(RLC), _NAME(RRC),
_NAME(FLW), _NAME(FRW),
_NAME(FLH), _NAME(FCH), _NAME(FRH), _NAME(TC),
- _NAME(NA),
+ _NAME(TFL), _NAME(TFR), _NAME(TFC),
+ _NAME(TRL), _NAME(TRR), _NAME(TRC),
};
#undef _NAME
@@ -7397,6 +7398,8 @@ const char *snd_pcm_chmap_name(enum snd_
static const char *chmap_long_names[SND_CHMAP_LAST + 1] = {
[SND_CHMAP_UNKNOWN] = "Unknown",
+ [SND_CHMAP_NA] = "Unused",
+ [SND_CHMAP_MONO] = "Mono",
[SND_CHMAP_FL] = "Front Left",
[SND_CHMAP_FR] = "Front Right",
[SND_CHMAP_RL] = "Rear Left",
@@ -7416,7 +7419,12 @@ static const char *chmap_long_names[SND_
[SND_CHMAP_FCH] = "Front Center High",
[SND_CHMAP_FRH] = "Front Right High",
[SND_CHMAP_TC] = "Top Center",
- [SND_CHMAP_NA] = "Unused",
+ [SND_CHMAP_TFL] = "Top Front Left",
+ [SND_CHMAP_TFR] = "Top Front Right",
+ [SND_CHMAP_TFC] = "Top Front Center",
+ [SND_CHMAP_TRL] = "Top Rear Left",
+ [SND_CHMAP_TRR] = "Top Rear Right",
+ [SND_CHMAP_TRC] = "Top Rear Center",
};
const char *snd_pcm_chmap_long_name(enum snd_pcm_chmap_position val)

View File

@ -0,0 +1,67 @@
From c6db60e32758e8f4bb6f066a5c6fc7758a0f4c49 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 12 Sep 2012 18:44:42 +0200
Subject: [PATCH 24/30] PCM: Fix the conversion from string to chmap position
Use strncasecmp() to allow lower cases, and also evaluate the inverted
phase suffix, too.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
src/pcm/pcm.c | 37 +++++++++++++++++++++++++++----------
1 file changed, 27 insertions(+), 10 deletions(-)
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -7471,24 +7471,41 @@ int snd_pcm_chmap_print(const snd_pcm_ch
static int str_to_chmap(const char *str, int len)
{
int val;
+ unsigned long v;
+ char *p;
if (isdigit(*str)) {
- val = atoi(str);
- if (val < 0)
+ v = strtoul(str, &p, 0);
+ if (v == ULONG_MAX)
return -1;
- return val | SND_CHMAP_DRIVER_SPEC;
- } else if (str[0] == 'C' && str[1] == 'h') {
- val = atoi(str + 2);
- if (val < 0)
+ val = v;
+ val |= SND_CHMAP_DRIVER_SPEC;
+ str = p;
+ } else if (!strncasecmp(str, "ch", 2)) {
+ v = strtoul(str + 2, &p, 0);
+ if (v == ULONG_MAX)
return -1;
- return val;
+ val = v;
+ str = p;
} else {
for (val = 0; val <= SND_CHMAP_LAST; val++) {
- if (!strncmp(str, chmap_names[val], len))
- return val;
+ int slen;
+ assert(chmap_names[val]);
+ slen = strlen(chmap_names[val]);
+ if (slen > len)
+ continue;
+ if (!strncasecmp(str, chmap_names[val], slen) &&
+ !isalpha(str[slen])) {
+ str += slen;
+ break;
+ }
}
- return -1;
+ if (val > SND_CHMAP_LAST)
+ return -1;
}
+ if (str && !strncasecmp(str, "[INV]", 5))
+ val |= SND_CHMAP_PHASE_INVERSE;
+ return val;
}
unsigned int snd_pcm_chmap_from_string(const char *str)

View File

@ -0,0 +1,158 @@
From 63f6f4a6103e55d242440488999e648beb5e4e4d Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Thu, 13 Sep 2012 08:38:59 +0200
Subject: [PATCH 25/30] PCM: A few doxygen fixes for chmap stuff
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/pcm.h | 18 +++++++++++-------
src/pcm/pcm.c | 43 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+), 7 deletions(-)
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -519,20 +519,24 @@ enum snd_pcm_chmap_position {
SND_CHMAP_LAST = SND_CHMAP_TRC, /** last entry */
};
-#define SND_CHMAP_POSITION_MASK 0xffff /** bitmask for channel position */
-#define SND_CHMAP_PHASE_INVERSE (0x01 << 16) /* the channel is phase inverted */
-#define SND_CHMAP_DRIVER_SPEC (0x02 << 16) /* non-standard channel value */
+/** bitmask for channel position */
+#define SND_CHMAP_POSITION_MASK 0xffff
+
+/** bit flag indicating the channel is phase inverted */
+#define SND_CHMAP_PHASE_INVERSE (0x01 << 16)
+/** bit flag indicating the non-standard channel value */
+#define SND_CHMAP_DRIVER_SPEC (0x02 << 16)
/** the channel map header */
typedef struct snd_pcm_chmap {
- unsigned int channels;
- unsigned int pos[0];
+ unsigned int channels; /** number of channels */
+ unsigned int pos[0]; /** channel position array */
} snd_pcm_chmap_t;
/** the header of array items returned from snd_pcm_query_chmaps() */
typedef struct snd_pcm_chmap_query {
- enum snd_pcm_chmap_type type;
- snd_pcm_chmap_t map;
+ enum snd_pcm_chmap_type type; /** channel map type */
+ snd_pcm_chmap_t map; /** available channel map */
} snd_pcm_chmap_query_t;
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -7310,6 +7310,9 @@ OBSOLETE1(snd_pcm_sw_params_get_silence_
* which contains the channel map. A channel map is represented by an
* integer array, beginning with the channel map type, followed by the
* number of channels, and the position of each channel.
+ *
+ * Note: the caller is requested to release the returned value via
+ * snd_pcm_free_chmaps().
*/
snd_pcm_chmap_query_t **snd_pcm_query_chmaps(snd_pcm_t *pcm)
{
@@ -7336,6 +7339,8 @@ void snd_pcm_free_chmaps(snd_pcm_chmap_q
* \!brief Get the current channel map
* \param pcm PCM instance
* \return the current channel map, or NULL if error
+ *
+ * Note: the caller is requested to release the returned value via free()
*/
snd_pcm_chmap_t *snd_pcm_get_chmap(snd_pcm_t *pcm)
{
@@ -7359,12 +7364,19 @@ int snd_pcm_set_chmap(snd_pcm_t *pcm, co
/*
*/
+#ifndef DOC_HIDDEN
#define _NAME(n) [SND_CHMAP_TYPE_##n] = #n
static const char *chmap_type_names[SND_CHMAP_TYPE_LAST + 1] = {
_NAME(NONE), _NAME(FIXED), _NAME(VAR), _NAME(PAIRED),
};
#undef _NAME
+#endif
+/**
+ * \!brief Get a name string for a channel map type as query results
+ * \param val Channel position
+ * \return The string corresponding to the given type, or NULL
+ */
const char *snd_pcm_chmap_type_name(enum snd_pcm_chmap_type val)
{
if (val <= SND_CHMAP_TYPE_LAST)
@@ -7373,6 +7385,7 @@ const char *snd_pcm_chmap_type_name(enum
return NULL;
}
+#ifndef DOC_HIDDEN
#define _NAME(n) [SND_CHMAP_##n] = #n
static const char *chmap_names[SND_CHMAP_LAST + 1] = {
_NAME(UNKNOWN), _NAME(NA), _NAME(MONO),
@@ -7387,7 +7400,13 @@ static const char *chmap_names[SND_CHMAP
_NAME(TRL), _NAME(TRR), _NAME(TRC),
};
#undef _NAME
+#endif
+/**
+ * \!brief Get a name string for a standard channel map position
+ * \param val Channel position
+ * \return The string corresponding to the given position, or NULL
+ */
const char *snd_pcm_chmap_name(enum snd_pcm_chmap_position val)
{
if (val <= SND_CHMAP_LAST)
@@ -7427,6 +7446,11 @@ static const char *chmap_long_names[SND_
[SND_CHMAP_TRC] = "Top Rear Center",
};
+/**
+ * \!brief Get a longer name string for a standard channel map position
+ * \param val Channel position
+ * \return The string corresponding to the given position, or NULL
+ */
const char *snd_pcm_chmap_long_name(enum snd_pcm_chmap_position val)
{
if (val <= SND_CHMAP_LAST)
@@ -7435,6 +7459,13 @@ const char *snd_pcm_chmap_long_name(enum
return NULL;
}
+/**
+ * \!brief Print the channels in chmap on the buffer
+ * \param map The channel map to print
+ * \param maxlen The maximal length to write (including NUL letter)
+ * \param buf The buffer to write
+ * \return The actual string length or a negative error code
+ */
int snd_pcm_chmap_print(const snd_pcm_chmap_t *map, size_t maxlen, char *buf)
{
unsigned int i, len = 0;
@@ -7508,11 +7539,23 @@ static int str_to_chmap(const char *str,
return val;
}
+/**
+ * \!brief Convert from string to channel position
+ * \param str The string to parse
+ * \return The channel position value or -1 as an error
+ */
unsigned int snd_pcm_chmap_from_string(const char *str)
{
return str_to_chmap(str, strlen(str));
}
+/**
+ * \!brief Convert from string to channel map
+ * \param str The string to parse
+ * \return The channel map
+ *
+ * Note: the caller is requested to release the returned value via free()
+ */
snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *str)
{
int i, ch = 0;

View File

@ -0,0 +1,30 @@
From 5a2daef19225478df7e3c1f8c6c9cb847e574b44 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Thu, 20 Sep 2012 13:43:12 +0200
Subject: [PATCH 26/30] PCM: Fill SND_CHMAP_NA to silent channels in route
plugin
Instead of SND_CHMAP_UNKNOWN, fill SND_CHMAP_NA to the silent channels.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
src/pcm/pcm_route.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- a/src/pcm/pcm_route.c
+++ b/src/pcm/pcm_route.c
@@ -720,11 +720,13 @@ static snd_pcm_chmap_t *snd_pcm_route_ge
return NULL;
}
map->channels = nsrcs;
+ for (src = 0; src < nsrcs; src++)
+ map->pos[src] = SND_CHMAP_NA;
for (dst = 0; dst < route->params.ndsts; dst++) {
snd_pcm_route_ttable_dst_t *d = &route->params.dsts[dst];
for (src = 0; src < d->nsrcs; src++) {
int c = d->srcs[src].channel;
- if (c < nsrcs && !map->pos[c])
+ if (c < nsrcs && map->pos[c] == SND_CHMAP_NA)
map->pos[c] = slave_map->pos[dst];
}
}

View File

@ -0,0 +1,43 @@
From 5a6ce315201f9e2abee51f4f890c1f5c6592c998 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Fri, 21 Sep 2012 17:59:42 +0200
Subject: [PATCH 27/30] PCM: Fix infinite loop in htimestamp of dmix, dsnoop
and dshare plugins
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
src/pcm/pcm_dmix.c | 1 +
src/pcm/pcm_dshare.c | 1 +
src/pcm/pcm_dsnoop.c | 1 +
3 files changed, 3 insertions(+)
--- a/src/pcm/pcm_dmix.c
+++ b/src/pcm/pcm_dmix.c
@@ -853,6 +853,7 @@ static int snd_pcm_dmix_htimestamp(snd_p
break;
*avail = avail1;
*tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm);
+ ok = 1;
}
return 0;
}
--- a/src/pcm/pcm_dshare.c
+++ b/src/pcm/pcm_dshare.c
@@ -543,6 +543,7 @@ static int snd_pcm_dshare_htimestamp(snd
break;
*avail = avail1;
*tstamp = snd_pcm_hw_fast_tstamp(dshare->spcm);
+ ok = 1;
}
return 0;
}
--- a/src/pcm/pcm_dsnoop.c
+++ b/src/pcm/pcm_dsnoop.c
@@ -458,6 +458,7 @@ static int snd_pcm_dsnoop_htimestamp(snd
break;
*avail = avail1;
*tstamp = snd_pcm_hw_fast_tstamp(dsnoop->spcm);
+ ok = 1;
}
return 0;
}

View File

@ -0,0 +1,287 @@
From 6429a450a315e00d9e00af46eb42784a4cc5dce1 Mon Sep 17 00:00:00 2001
From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Date: Fri, 21 Sep 2012 20:05:18 -0500
Subject: [PATCH 28/30] test: add audio_time
Simple test to create playback and capture streams, and
check elapsed time vs. sample counts reported by driver.
This should be helpful for driver developers and anyone
interested in system/audio time drift.
tested only on HDAudio
[added Makefile.am change by tiwai]
TODO:
- make period configurable
- better output messages
- support for wall clock when it's in the mainline
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
test/Makefile.am | 4
test/audio_time.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 240 insertions(+), 1 deletion(-)
create mode 100644 test/audio_time.c
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -2,7 +2,8 @@ SUBDIRS=. lsb
check_PROGRAMS=control pcm pcm_min latency seq \
playmidi1 timer rawmidi midiloop \
- oldapi queue_timer namehint client_event_filter chmap
+ oldapi queue_timer namehint client_event_filter \
+ chmap audio_time
control_LDADD=../src/libasound.la
pcm_LDADD=../src/libasound.la
@@ -19,6 +20,7 @@ namehint_LDADD=../src/libasound.la
client_event_filter_LDADD=../src/libasound.la
code_CFLAGS=-Wall -pipe -g -O2
chmap_LDADD=../src/libasound.la
+audio_time_LDADD=../src/libasound.la
INCLUDES=-I$(top_srcdir)/include
AM_CFLAGS=-Wall -pipe -g
--- /dev/null
+++ b/test/audio_time.c
@@ -0,0 +1,237 @@
+/*
+ * This program only tracks the difference between system time
+ * and audio time, as reported in snd_pcm_status(). It should be
+ * helpful to verify the information reported by drivers.
+ */
+
+#include "../include/asoundlib.h"
+#include <math.h>
+
+static char *device = "hw:0,0";
+
+snd_output_t *output = NULL;
+
+long long timestamp2ns(snd_htimestamp_t t)
+{
+ long long nsec;
+
+ nsec = t.tv_sec * 1000000000;
+ nsec += t.tv_nsec;
+
+ return nsec;
+}
+
+long long timediff(snd_htimestamp_t t1, snd_htimestamp_t t2)
+{
+ long long nsec1, nsec2;
+
+ nsec1 = timestamp2ns(t1);
+ nsec2 = timestamp2ns(t2);
+
+ return nsec1 - nsec2;
+}
+
+void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
+ snd_htimestamp_t *trigger_timestamp,
+ snd_pcm_uframes_t *avail, snd_pcm_sframes_t *delay)
+{
+ int err;
+ snd_pcm_status_t *status;
+
+ snd_pcm_status_alloca(&status);
+ if ((err = snd_pcm_status(handle, status)) < 0) {
+ printf("Stream status error: %s\n", snd_strerror(err));
+ exit(0);
+ }
+ snd_pcm_status_get_trigger_htstamp(status, trigger_timestamp);
+ snd_pcm_status_get_htstamp(status, timestamp);
+ *avail = snd_pcm_status_get_avail(status);
+ *delay = snd_pcm_status_get_delay(status);
+}
+
+#define PERIOD 6000
+#define PCM_LINK /* sync start for playback and capture */
+#define TRACK_CAPTURE /* dump capture timing info */
+#define TRACK_PLAYBACK /* dump playback timing info */
+#define PLAYBACK_BUFFERS 4
+
+
+int main(void)
+{
+ int err;
+ unsigned int i;
+ snd_pcm_t *handle_p = NULL;
+ snd_pcm_t *handle_c = NULL;
+ snd_pcm_sframes_t frames;
+ snd_htimestamp_t tstamp_c, tstamp_p;
+ snd_htimestamp_t trigger_tstamp_c, trigger_tstamp_p;
+ unsigned char buffer_p[PERIOD*4*4];
+ unsigned char buffer_c[PERIOD*4*4];
+
+ snd_pcm_sw_params_t *swparams_p;
+ snd_pcm_sw_params_t *swparams_c;
+
+ snd_pcm_uframes_t curr_count_c;
+ snd_pcm_uframes_t frame_count_c = 0;
+ snd_pcm_uframes_t curr_count_p;
+ snd_pcm_uframes_t frame_count_p = 0;
+
+ snd_pcm_sframes_t delay_p, delay_c;
+ snd_pcm_uframes_t avail_p, avail_c;
+
+ if ((err = snd_pcm_open(&handle_p, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+ printf("Playback open error: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+ if ((err = snd_pcm_set_params(handle_p,
+ SND_PCM_FORMAT_S16,
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ 2,
+ 48000,
+ 0,
+ 500000)) < 0) { /* 0.5sec */
+ printf("Playback open error: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ snd_pcm_sw_params_alloca(&swparams_p);
+ /* get the current swparams */
+ err = snd_pcm_sw_params_current(handle_p, swparams_p);
+ if (err < 0) {
+ printf("Unable to determine current swparams_p: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ /* enable tstamp */
+ err = snd_pcm_sw_params_set_tstamp_mode(handle_p, swparams_p, SND_PCM_TSTAMP_ENABLE);
+ if (err < 0) {
+ printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ /* write the sw parameters */
+ err = snd_pcm_sw_params(handle_p, swparams_p);
+ if (err < 0) {
+ printf("Unable to set swparams_p : %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ if ((err = snd_pcm_open(&handle_c, device, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
+ printf("Capture open error: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+ if ((err = snd_pcm_set_params(handle_c,
+ SND_PCM_FORMAT_S16,
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ 2,
+ 48000,
+ 0,
+ 500000)) < 0) { /* 0.5sec */
+ printf("Capture open error: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ snd_pcm_sw_params_alloca(&swparams_c);
+ /* get the current swparams */
+ err = snd_pcm_sw_params_current(handle_c, swparams_c);
+ if (err < 0) {
+ printf("Unable to determine current swparams_c: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ /* enable tstamp */
+ err = snd_pcm_sw_params_set_tstamp_mode(handle_c, swparams_c, SND_PCM_TSTAMP_ENABLE);
+ if (err < 0) {
+ printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+ /* write the sw parameters */
+ err = snd_pcm_sw_params(handle_c, swparams_c);
+ if (err < 0) {
+ printf("Unable to set swparams_c : %s\n", snd_strerror(err));
+ goto _exit;
+ }
+
+#ifdef PCM_LINK
+ if ((err = snd_pcm_link(handle_c, handle_p)) < 0) {
+ printf("Streams link error: %s\n", snd_strerror(err));
+ exit(0);
+ }
+#endif
+
+ i = PLAYBACK_BUFFERS;
+ while (i--) {
+ frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
+ if (frames < 0) {
+ printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
+ goto _exit;
+ }
+ frame_count_p += frames;
+ }
+
+ if (PLAYBACK_BUFFERS != 4)
+ snd_pcm_start(handle_p);
+
+#ifndef PCM_LINK
+ /* need to start capture explicitly */
+ snd_pcm_start(handle_c);
+#endif
+
+ while (1) {
+
+ frames = snd_pcm_wait(handle_c, -1);
+ if (frames < 0) {
+ printf("snd_pcm_wait failed: %s\n", snd_strerror(frames));
+ goto _exit;
+ }
+
+ frames = snd_pcm_readi(handle_c, buffer_c, PERIOD);
+ if (frames < 0) {
+ printf("snd_pcm_readi failed: %s\n", snd_strerror(frames));
+ goto _exit;
+ }
+ frame_count_c += frames;
+
+ frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
+ if (frames < 0) {
+ printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
+ goto _exit;
+ }
+
+ frame_count_p += frames;
+
+#if defined(TRACK_PLAYBACK)
+ gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p, &avail_p, &delay_p);
+
+ curr_count_p = frame_count_p - delay_p; /* written minus queued */
+
+ printf("playback: systime: %lli nsec, sample time %lli nsec \tsystime delta %lli \n",
+ timediff(tstamp_p,trigger_tstamp_p),
+ (long long)round(((float)curr_count_p * 1000000000.0 / 48000.0)),
+ timediff(tstamp_p, trigger_tstamp_p) - (long long)round((double)curr_count_p * 1000000000.0 / 48000.0)
+ );
+#endif
+
+#if defined(TRACK_CAPTURE)
+ gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c, &avail_c, &delay_c);
+
+ curr_count_c = frame_count_c + delay_c; /* read plus queued */
+
+ printf("\t capture: systime: %lli nsec, sample time %lli nsec \tsystime delta %lli \n",
+ timediff(tstamp_c,trigger_tstamp_c),
+ (long long)round(((float)curr_count_c * 1000000000.0 / 48000.0)),
+ timediff(tstamp_c, trigger_tstamp_c) - (long long)round((double)curr_count_c * 1000000000.0 / 48000.0)
+ );
+#endif
+
+ }
+
+_exit:
+ if (handle_p)
+ snd_pcm_close(handle_p);
+ if (handle_c)
+ snd_pcm_close(handle_c);
+
+ return 0;
+}

View File

@ -0,0 +1,49 @@
From 4bdb09126a32feb4394eaeb1d400d87e7c968770 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Wed, 10 Oct 2012 10:22:54 +0200
Subject: [PATCH 30/30] PCM: Fix the invalid snd_pcm_close() calls in rate
plugin
It happens in the error path, should call snd_pcm_free() instead.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
src/pcm/pcm_rate.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
--- a/src/pcm/pcm_rate.c
+++ b/src/pcm/pcm_rate.c
@@ -1394,13 +1394,13 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp,
}
} else {
SNDERR("Invalid type for rate converter");
- snd_pcm_close(pcm);
+ snd_pcm_free(pcm);
free(rate);
return -EINVAL;
}
if (err < 0) {
SNDERR("Cannot find rate converter");
- snd_pcm_close(pcm);
+ snd_pcm_free(pcm);
free(rate);
return -ENOENT;
}
@@ -1409,7 +1409,7 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp,
open_func = SND_PCM_RATE_PLUGIN_ENTRY(linear);
err = open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops);
if (err < 0) {
- snd_pcm_close(pcm);
+ snd_pcm_free(pcm);
free(rate);
return err;
}
@@ -1418,7 +1418,7 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp,
if (! rate->ops.init || ! (rate->ops.convert || rate->ops.convert_s16) ||
! rate->ops.input_frames || ! rate->ops.output_frames) {
SNDERR("Inproper rate plugin %s initialization", type);
- snd_pcm_close(pcm);
+ snd_pcm_free(pcm);
free(rate);
return err;
}

View File

@ -1,3 +1,12 @@
-------------------------------------------------------------------
Wed Oct 17 10:05:36 CEST 2012 - tiwai@suse.de
- 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
-------------------------------------------------------------------
Fri Sep 7 15:29:41 CEST 2012 - tiwai@suse.de

View File

@ -53,6 +53,36 @@ Source34: alsa-init.sh
Source40: 50-alsa.conf
Source41: install-snd-module
# Patch: alsa-lib-git-fixes.diff
Patch1: 0001-Implement-the-channel-mapping-API.patch
Patch2: 0002-Implement-get_chmap-set_chmap-for-PCM-plug-route-and.patch
Patch3: 0003-Implement-get_chmap-set_chmap-for-PCM-extplug-ioplug.patch
Patch4: 0004-Add-test-chmap-program.patch
Patch5: 0005-Cache-the-chmap-operation-errors.patch
Patch6: 0006-Define-channel-map-position-enum-in-pcm.h.patch
Patch7: 0007-Follow-channel-position-definitions-to-mixer-channel.patch
Patch8: 0008-Add-SND_CHMAP_NA-and-bit-flag-definitions.patch
Patch9: 0009-PCM-Introduce-snd_pcm_chmap_t-and-snd_pcm_chmap_quer.patch
Patch10: 0010-PCM-Implement-snd_pcm_query_chmaps_from_hw.patch
Patch11: 0011-Fix-duplicated-channel-entry-in-test-chmap.c.patch
Patch12: 0012-PCM-Fix-prefix-for-snd_pcm_chmap_type-enum-members.patch
Patch13: 0013-PCM-Add-string-conversion-helper-functions-for-chmap.patch
Patch14: 0014-PCM-Add-SND_CHMAP_API_VERSION-definition.patch
Patch15: 0015-PCM-Add-snd_pcm_chmap_long_name.patch
Patch16: 0016-PCM-Add-query_chmaps-support-to-multi-plugin.patch
Patch17: 0017-PCM-Add-chmap-options-to-hw-and-null-plugins.patch
Patch18: 0018-PCM-Add-the-missing-query_chmaps-for-route-plugin.patch
Patch19: 0019-Add-chmap-override-definitions-for-Emu10k1-Audigy-an.patch
Patch20: 0020-PCM-Use-compounds-for-overriding-enhancing-chmaps.patch
Patch21: 0021-conf-Add-chmap-definitions-to-TRIDENT-and-SI7018-con.patch
Patch22: 0022-test-chmap-Fix-wrong-malloc-size.patch
Patch23: 0023-PCM-Define-MONO-and-other-channel-map-positions.patch
Patch24: 0024-PCM-Fix-the-conversion-from-string-to-chmap-position.patch
Patch25: 0025-PCM-A-few-doxygen-fixes-for-chmap-stuff.patch
Patch26: 0026-PCM-Fill-SND_CHMAP_NA-to-silent-channels-in-route-pl.patch
Patch27: 0027-PCM-Fix-infinite-loop-in-htimestamp-of-dmix-dsnoop-a.patch
Patch28: 0028-test-add-audio_time.patch
Patch30: 0030-PCM-Fix-the-invalid-snd_pcm_close-calls-in-rate-plug.patch
#
Patch99: alsa-lib-doxygen-avoid-crash-for-11.3.diff
Url: http://www.alsa-project.org/
BuildRoot: %{_tmppath}/%{name}-%{version}-build
@ -103,6 +133,35 @@ Architecture.
%prep
%setup -q -n alsa-lib-%{package_version}
# %patch -p1
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%patch15 -p1
%patch16 -p1
%patch17 -p1
%patch18 -p1
%patch19 -p1
%patch20 -p1
%patch21 -p1
%patch22 -p1
%patch23 -p1
%patch24 -p1
%patch25 -p1
%patch26 -p1
%patch27 -p1
%patch28 -p1
%patch30 -p1
%if %suse_version == 1130
%patch99 -p1
%endif