mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2026-03-06 01:40:09 -05:00
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>
This commit is contained in:
parent
5ba11d69da
commit
ec7acfc408
7 changed files with 144 additions and 45 deletions
|
|
@ -13,7 +13,7 @@ Audigy.pcm.front.0 {
|
||||||
slave.pcm {
|
slave.pcm {
|
||||||
type hw
|
type hw
|
||||||
card $CARD
|
card $CARD
|
||||||
chmap "FL,FR"
|
chmap [ "UNKNOWN" "FL,FR" ]
|
||||||
}
|
}
|
||||||
hooks.0 {
|
hooks.0 {
|
||||||
type ctl_elems
|
type ctl_elems
|
||||||
|
|
@ -66,7 +66,7 @@ Audigy.pcm.rear.0 {
|
||||||
slave.pcm {
|
slave.pcm {
|
||||||
type hw
|
type hw
|
||||||
card $CARD
|
card $CARD
|
||||||
chmap "RL,RR"
|
chmap [ "UNKNOWN" "RL,RR" ]
|
||||||
}
|
}
|
||||||
hooks.0 {
|
hooks.0 {
|
||||||
type ctl_elems
|
type ctl_elems
|
||||||
|
|
@ -102,7 +102,7 @@ Audigy.pcm.center_lfe.0 {
|
||||||
slave.pcm {
|
slave.pcm {
|
||||||
type hw
|
type hw
|
||||||
card $CARD
|
card $CARD
|
||||||
chmap "FC,LFE"
|
chmap [ "UNKNOWN" "FC,LFE" ]
|
||||||
}
|
}
|
||||||
hooks.0 {
|
hooks.0 {
|
||||||
type ctl_elems
|
type ctl_elems
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ Audigy2.pcm.front.0 {
|
||||||
slave.pcm {
|
slave.pcm {
|
||||||
type hw
|
type hw
|
||||||
card $CARD
|
card $CARD
|
||||||
chmap "FL,FR"
|
chmap [ "UNKNOWN" "FL,FR" ]
|
||||||
}
|
}
|
||||||
hooks.0 {
|
hooks.0 {
|
||||||
type ctl_elems
|
type ctl_elems
|
||||||
|
|
@ -66,7 +66,7 @@ Audigy2.pcm.rear.0 {
|
||||||
slave.pcm {
|
slave.pcm {
|
||||||
type hw
|
type hw
|
||||||
card $CARD
|
card $CARD
|
||||||
chmap "RL,RR"
|
chmap [ "UNKNOWN" "RL,RR" ]
|
||||||
}
|
}
|
||||||
hooks.0 {
|
hooks.0 {
|
||||||
type ctl_elems
|
type ctl_elems
|
||||||
|
|
@ -102,7 +102,7 @@ Audigy2.pcm.center_lfe.0 {
|
||||||
slave.pcm {
|
slave.pcm {
|
||||||
type hw
|
type hw
|
||||||
card $CARD
|
card $CARD
|
||||||
chmap "FC,LFE"
|
chmap [ "UNKNOWN" "FC,LFE" ]
|
||||||
}
|
}
|
||||||
hooks.0 {
|
hooks.0 {
|
||||||
type ctl_elems
|
type ctl_elems
|
||||||
|
|
@ -154,7 +154,7 @@ Audigy2.pcm.side.0 {
|
||||||
slave.pcm {
|
slave.pcm {
|
||||||
type hw
|
type hw
|
||||||
card $CARD
|
card $CARD
|
||||||
chmap "SL,SR"
|
chmap [ "UNKNOWN" "SL,SR" ]
|
||||||
}
|
}
|
||||||
hooks.0 {
|
hooks.0 {
|
||||||
type ctl_elems
|
type ctl_elems
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ EMU10K1.pcm.front.0 {
|
||||||
slave.pcm {
|
slave.pcm {
|
||||||
type hw
|
type hw
|
||||||
card $CARD
|
card $CARD
|
||||||
chmap "FL,FR"
|
chmap [ "UNKNOWN" "FL,FR" ]
|
||||||
}
|
}
|
||||||
hooks.0 {
|
hooks.0 {
|
||||||
type ctl_elems
|
type ctl_elems
|
||||||
|
|
@ -74,7 +74,7 @@ EMU10K1.pcm.rear.0 {
|
||||||
slave.pcm {
|
slave.pcm {
|
||||||
type hw
|
type hw
|
||||||
card $CARD
|
card $CARD
|
||||||
chmap "RL,RR"
|
chmap [ "UNKNOWN" "RL,RR" ]
|
||||||
}
|
}
|
||||||
hooks.0 {
|
hooks.0 {
|
||||||
type ctl_elems
|
type ctl_elems
|
||||||
|
|
@ -113,7 +113,7 @@ EMU10K1.pcm.center_lfe.0 {
|
||||||
slave.pcm {
|
slave.pcm {
|
||||||
type hw
|
type hw
|
||||||
card $CARD
|
card $CARD
|
||||||
chmap "FC,LFE"
|
chmap [ "UNKNOWN" "FC,LFE" ]
|
||||||
}
|
}
|
||||||
hooks.0 {
|
hooks.0 {
|
||||||
type ctl_elems
|
type ctl_elems
|
||||||
|
|
|
||||||
109
src/pcm/pcm.c
109
src/pcm/pcm.c
|
|
@ -7531,25 +7531,37 @@ snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *str)
|
||||||
return map;
|
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_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;
|
snd_pcm_chmap_query_t **maps;
|
||||||
|
|
||||||
maps = calloc(2, sizeof(*maps));
|
maps = calloc(2, sizeof(*maps));
|
||||||
if (!maps)
|
if (!maps)
|
||||||
return NULL;
|
return NULL;
|
||||||
*maps = malloc((src->channels + 2) * sizeof(int));
|
if (_copy_to_fixed_query_map(maps, src)) {
|
||||||
if (!*maps) {
|
|
||||||
free(maps);
|
free(maps);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
(*maps)->type = SND_CHMAP_TYPE_FIXED;
|
|
||||||
memcpy(&(*maps)->map, src, (src->channels + 1) * sizeof(int));
|
|
||||||
return maps;
|
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;
|
snd_pcm_chmap_t *map;
|
||||||
|
|
||||||
|
|
@ -7560,6 +7572,91 @@ snd_pcm_chmap_t *_snd_pcm_copy_chmap(snd_pcm_chmap_t *src)
|
||||||
return map;
|
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
|
* basic helpers
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ typedef struct {
|
||||||
int channels;
|
int channels;
|
||||||
/* for chmap */
|
/* for chmap */
|
||||||
unsigned int chmap_caps;
|
unsigned int chmap_caps;
|
||||||
snd_pcm_chmap_t *chmap_override;
|
snd_pcm_chmap_query_t **chmap_override;
|
||||||
} snd_pcm_hw_t;
|
} snd_pcm_hw_t;
|
||||||
|
|
||||||
#define SNDRV_FILE_PCM_STREAM_PLAYBACK ALSA_DEVICE_DIRECTORY "pcmC%iD%ip"
|
#define SNDRV_FILE_PCM_STREAM_PLAYBACK ALSA_DEVICE_DIRECTORY "pcmC%iD%ip"
|
||||||
|
|
@ -1146,7 +1146,7 @@ static snd_pcm_chmap_query_t **snd_pcm_hw_query_chmaps(snd_pcm_t *pcm)
|
||||||
snd_pcm_chmap_query_t **map;
|
snd_pcm_chmap_query_t **map;
|
||||||
|
|
||||||
if (hw->chmap_override)
|
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))
|
if (!chmap_caps(hw, CHMAP_CTL_QUERY))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -1171,7 +1171,7 @@ static snd_pcm_chmap_t *snd_pcm_hw_get_chmap(snd_pcm_t *pcm)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (hw->chmap_override)
|
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))
|
if (!chmap_caps(hw, CHMAP_CTL_GET))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -1603,7 +1603,7 @@ pcm.name {
|
||||||
[format STR] # Restrict only to the given format
|
[format STR] # Restrict only to the given format
|
||||||
[channels INT] # Restrict only to the given channels
|
[channels INT] # Restrict only to the given channels
|
||||||
[rate INT] # Restrict only to the given rate
|
[rate INT] # Restrict only to the given rate
|
||||||
[chmap MAP] # Override channel map
|
[chmap MAP] # Override channel maps; MAP is a string array
|
||||||
}
|
}
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
|
|
@ -1640,7 +1640,7 @@ int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
|
||||||
snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
|
snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
|
||||||
snd_config_t *n;
|
snd_config_t *n;
|
||||||
int nonblock = 1; /* non-block per default */
|
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;
|
snd_pcm_hw_t *hw;
|
||||||
|
|
||||||
/* look for defaults.pcm.nonblock definition */
|
/* look for defaults.pcm.nonblock definition */
|
||||||
|
|
@ -1732,13 +1732,8 @@ int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strcmp(id, "chmap") == 0) {
|
if (strcmp(id, "chmap") == 0) {
|
||||||
err = snd_config_get_string(n, &str);
|
snd_pcm_free_chmaps(chmap);
|
||||||
if (err < 0) {
|
chmap = _snd_pcm_parse_config_chmaps(n);
|
||||||
SNDERR("Invalid type for %s", id);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
free(chmap);
|
|
||||||
chmap = snd_pcm_chmap_parse_string(str);
|
|
||||||
if (!chmap) {
|
if (!chmap) {
|
||||||
SNDERR("Invalid channel map for %s", id);
|
SNDERR("Invalid channel map for %s", id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
@ -1746,17 +1741,21 @@ int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SNDERR("Unknown field %s", id);
|
SNDERR("Unknown field %s", id);
|
||||||
|
snd_pcm_free_chmaps(chmap);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (card < 0) {
|
if (card < 0) {
|
||||||
SNDERR("card is not defined");
|
SNDERR("card is not defined");
|
||||||
|
snd_pcm_free_chmaps(chmap);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream,
|
err = snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream,
|
||||||
mode | (nonblock ? SND_PCM_NONBLOCK : 0),
|
mode | (nonblock ? SND_PCM_NONBLOCK : 0),
|
||||||
0, sync_ptr_ioctl);
|
0, sync_ptr_ioctl);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
|
snd_pcm_free_chmaps(chmap);
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
if (nonblock && ! (mode & SND_PCM_NONBLOCK)) {
|
if (nonblock && ! (mode & SND_PCM_NONBLOCK)) {
|
||||||
/* revert to blocking mode for read/write access */
|
/* revert to blocking mode for read/write access */
|
||||||
snd_pcm_hw_nonblock(*pcmp, 0);
|
snd_pcm_hw_nonblock(*pcmp, 0);
|
||||||
|
|
|
||||||
|
|
@ -975,6 +975,12 @@ static inline void gettimestamp(snd_htimestamp_t *tstamp, int monotonic)
|
||||||
}
|
}
|
||||||
|
|
||||||
snd_pcm_chmap_query_t **
|
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_t *_snd_pcm_copy_chmap(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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ typedef struct {
|
||||||
snd_pcm_uframes_t appl_ptr;
|
snd_pcm_uframes_t appl_ptr;
|
||||||
snd_pcm_uframes_t hw_ptr;
|
snd_pcm_uframes_t hw_ptr;
|
||||||
int poll_fd;
|
int poll_fd;
|
||||||
snd_pcm_chmap_t *chmap;
|
snd_pcm_chmap_query_t **chmap;
|
||||||
} snd_pcm_null_t;
|
} snd_pcm_null_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -274,7 +274,7 @@ static snd_pcm_chmap_query_t **snd_pcm_null_query_chmaps(snd_pcm_t *pcm)
|
||||||
snd_pcm_null_t *null = pcm->private_data;
|
snd_pcm_null_t *null = pcm->private_data;
|
||||||
|
|
||||||
if (null->chmap)
|
if (null->chmap)
|
||||||
return _snd_pcm_make_single_query_chmaps(null->chmap);
|
return _snd_pcm_copy_chmap_query(null->chmap);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -283,7 +283,7 @@ static snd_pcm_chmap_t *snd_pcm_null_get_chmap(snd_pcm_t *pcm)
|
||||||
snd_pcm_null_t *null = pcm->private_data;
|
snd_pcm_null_t *null = pcm->private_data;
|
||||||
|
|
||||||
if (null->chmap)
|
if (null->chmap)
|
||||||
return _snd_pcm_copy_chmap(null->chmap);
|
return _snd_pcm_choose_fixed_chmap(pcm, null->chmap);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -407,7 +407,7 @@ and /dev/full (capture, must be readable).
|
||||||
\code
|
\code
|
||||||
pcm.name {
|
pcm.name {
|
||||||
type null # Null PCM
|
type null # Null PCM
|
||||||
[chmap MAP]
|
[chmap MAP] # Provide channel maps; MAP is a string array
|
||||||
}
|
}
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
|
|
@ -439,7 +439,7 @@ int _snd_pcm_null_open(snd_pcm_t **pcmp, const char *name,
|
||||||
{
|
{
|
||||||
snd_config_iterator_t i, next;
|
snd_config_iterator_t i, next;
|
||||||
snd_pcm_null_t *null;
|
snd_pcm_null_t *null;
|
||||||
snd_pcm_chmap_t *chmap = NULL;
|
snd_pcm_chmap_query_t **chmap = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
snd_config_for_each(i, next, conf) {
|
snd_config_for_each(i, next, conf) {
|
||||||
|
|
@ -450,14 +450,8 @@ int _snd_pcm_null_open(snd_pcm_t **pcmp, const char *name,
|
||||||
if (snd_pcm_conf_generic_id(id))
|
if (snd_pcm_conf_generic_id(id))
|
||||||
continue;
|
continue;
|
||||||
if (strcmp(id, "chmap") == 0) {
|
if (strcmp(id, "chmap") == 0) {
|
||||||
const char *str;
|
snd_pcm_free_chmaps(chmap);
|
||||||
err = snd_config_get_string(n, &str);
|
chmap = _snd_pcm_parse_config_chmaps(n);
|
||||||
if (err < 0) {
|
|
||||||
SNDERR("Invalid type for %s", id);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
free(chmap);
|
|
||||||
chmap = snd_pcm_chmap_parse_string(str);
|
|
||||||
if (!chmap) {
|
if (!chmap) {
|
||||||
SNDERR("Invalid channel map for %s", id);
|
SNDERR("Invalid channel map for %s", id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
@ -465,11 +459,14 @@ int _snd_pcm_null_open(snd_pcm_t **pcmp, const char *name,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SNDERR("Unknown field %s", id);
|
SNDERR("Unknown field %s", id);
|
||||||
|
snd_pcm_free_chmaps(chmap);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = snd_pcm_null_open(pcmp, name, stream, mode);
|
err = snd_pcm_null_open(pcmp, name, stream, mode);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
|
snd_pcm_free_chmaps(chmap);
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
null = (*pcmp)->private_data;
|
null = (*pcmp)->private_data;
|
||||||
null->chmap = chmap;
|
null->chmap = chmap;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue