[alsa-devel] [PATCH] control, hw, rawmidi: accept control device node as card identifier when opening
Heya!
Traditionally low-level ALSA devices are opened with device strings like 'hw:CARD' where CARD is either a numeric index or a card name. This patch introduces a third syntax that allows you to specify the file name of the control device node. The purpose for this is to make ALSA a bit more like other Linux devices and allow implementaiton of udev device symlinks similar to how disks are currently handled, with /dev/disk/by-path/xxxx /dev/disk/by-id/xxxx and so on.
With this patch this line:
aplay -f CD -D hw:/dev/snd/controlC0 < /dev/urandom
becomes equivalent to this line:
aplay -f CD -D hw:0 < /dev/urandom
A more useful example is this:
aplay -f CD -D hw:/dev/snd/by-path/pci-0000:00:1a.7-usb-0:2:1.2
(this line requires a a few additional udev rules)
This only works for control devices nodes, not for PCM or any other device nodes. Since the control device node is used as 'entry point' when opening PCM devices this is no limitation.
Lennart
--- include/pcm_plugin.h | 4 ++- src/control/cards.c | 20 ++++++++++-- src/control/control_hw.c | 69 +++++++++++++++++++++++++++++++++---------- src/control/control_local.h | 3 +- src/pcm/pcm_hw.c | 29 ++++++++++++------ src/rawmidi/rawmidi_hw.c | 30 ++++++++++++------ src/rawmidi/rawmidi_local.h | 6 ++- 7 files changed, 118 insertions(+), 43 deletions(-)
diff --git a/include/pcm_plugin.h b/include/pcm_plugin.h index eea1d82..758144e 100644 --- a/include/pcm_plugin.h +++ b/include/pcm_plugin.h @@ -1,3 +1,4 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /** * \file include/pcm_plugin.h * \brief Common PCM plugin code @@ -66,7 +67,8 @@ typedef int snd_pcm_route_ttable_entry_t; * Hardware plugin */ int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, - int card, int device, int subdevice, + int card, const char *control_device_node, + int device, int subdevice, snd_pcm_stream_t stream, int mode, int mmap_emulation, int sync_ptr_ioctl); int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, diff --git a/src/control/cards.c b/src/control/cards.c index 4d2c739..912e8c8 100644 --- a/src/control/cards.c +++ b/src/control/cards.c @@ -1,3 +1,4 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /** * \file control/cards.c * \brief Basic Soundcard Operations @@ -127,12 +128,25 @@ int snd_card_get_index(const char *string) return card; return err; } + + if (string[0] == '/') { + err = snd_ctl_hw_open(&handle, NULL, -1, string, 0); + + if (err < 0) + return err; + + card = snd_ctl_hw_card(handle); + snd_ctl_close(handle); + + return card; + } + for (card = 0; card < 32; card++) { #ifdef SUPPORT_ALOAD if (! snd_card_load(card)) continue; #endif - if (snd_ctl_hw_open(&handle, NULL, card, 0) < 0) + if (snd_ctl_hw_open(&handle, NULL, card, NULL, 0) < 0) continue; if (snd_ctl_card_info(handle, &info) < 0) { snd_ctl_close(handle); @@ -159,7 +173,7 @@ int snd_card_get_name(int card, char **name) if (name == NULL) return -EINVAL; - if ((err = snd_ctl_hw_open(&handle, NULL, card, 0)) < 0) + if ((err = snd_ctl_hw_open(&handle, NULL, card, NULL, 0)) < 0) return err; if ((err = snd_ctl_card_info(handle, &info)) < 0) { snd_ctl_close(handle); @@ -186,7 +200,7 @@ int snd_card_get_longname(int card, char **name) if (name == NULL) return -EINVAL; - if ((err = snd_ctl_hw_open(&handle, NULL, card, 0)) < 0) + if ((err = snd_ctl_hw_open(&handle, NULL, card, NULL, 0)) < 0) return err; if ((err = snd_ctl_card_info(handle, &info)) < 0) { snd_ctl_close(handle); diff --git a/src/control/control_hw.c b/src/control/control_hw.c index e9a6be2..3cead5e 100644 --- a/src/control/control_hw.c +++ b/src/control/control_hw.c @@ -1,4 +1,5 @@ -/* +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * * Control Interface - Hardware * Copyright (c) 1998,1999,2000 by Jaroslav Kysela perex@perex.cz * Copyright (c) 2000 by Abramo Bagnara abramo@alsa-project.org @@ -49,6 +50,12 @@ typedef struct { } snd_ctl_hw_t; #endif /* DOC_HIDDEN */
+int snd_ctl_hw_card(snd_ctl_t *handle) { + snd_ctl_hw_t *hw = handle->private_data; + + return hw->card; +} + static int snd_ctl_hw_close(snd_ctl_t *handle) { snd_ctl_hw_t *hw = handle->private_data; @@ -361,7 +368,7 @@ static const snd_ctl_ops_t snd_ctl_hw_ops = { .read = snd_ctl_hw_read, };
-int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode) +int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, const char *devnode, int mode) { int fd, ver; char filename[sizeof(SNDRV_FILE_CONTROL) + 10]; @@ -370,13 +377,23 @@ int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode) snd_ctl_hw_t *hw; int err;
- *handle = NULL; + *handle = NULL;
- if (CHECK_SANITY(card < 0 || card >= 32)) { + if (CHECK_SANITY(!!devnode == (card >= 0))) { + SNDMSG("Specified both card index and device node"); + return -EINVAL; + } + + if (CHECK_SANITY(card >= 32)) { SNDMSG("Invalid card index %d", card); return -EINVAL; } - sprintf(filename, SNDRV_FILE_CONTROL, card); + + if (!devnode) { + sprintf(filename, SNDRV_FILE_CONTROL, card); + devnode = filename; + } + if (mode & SND_CTL_READONLY) fmode = O_RDONLY; else @@ -385,13 +402,15 @@ int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode) fmode |= O_NONBLOCK; if (mode & SND_CTL_ASYNC) fmode |= O_ASYNC; - fd = snd_open_device(filename, fmode); - if (fd < 0) { + fd = snd_open_device(devnode, fmode); + if (fd < 0 && card >= 0) { snd_card_load(card); - fd = snd_open_device(filename, fmode); - if (fd < 0) - return -errno; + fd = snd_open_device(devnode, fmode); } + + if (fd < 0) + return -errno; + #if 0 /* * this is bogus, an application have to care about open filedescriptors @@ -412,6 +431,19 @@ int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode) close(fd); return -SND_ERROR_INCOMPATIBLE_VERSION; } + + if (card < 0) { + snd_ctl_card_info_t info; + + if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &info) < 0) { + err = -errno; + close(fd); + return err; + } + + card = info.card; + } + hw = calloc(1, sizeof(snd_ctl_hw_t)); if (hw == NULL) { close(fd); @@ -437,7 +469,7 @@ int _snd_ctl_hw_open(snd_ctl_t **handlep, char *name, snd_config_t *root ATTRIBU { snd_config_iterator_t i, next; long card = -1; - const char *str; + const char *str, *devnode = NULL; int err; snd_config_for_each(i, next, conf) { snd_config_t *n = snd_config_iterator_entry(i); @@ -454,16 +486,21 @@ int _snd_ctl_hw_open(snd_ctl_t **handlep, char *name, snd_config_t *root ATTRIBU err = snd_config_get_string(n, &str); if (err < 0) return -EINVAL; - card = snd_card_get_index(str); - if (card < 0) - return card; + if (str[0] == '/') + devnode = name; + else { + card = snd_card_get_index(str); + if (card < 0) + return card; + } + } continue; } return -EINVAL; } - if (card < 0) + if (card < 0 && !devnode) return -EINVAL; - return snd_ctl_hw_open(handlep, name, card, mode); + return snd_ctl_hw_open(handlep, name, card, devnode, mode); } SND_DLSYM_BUILD_VERSION(_snd_ctl_hw_open, SND_CONTROL_DLSYM_VERSION); diff --git a/src/control/control_local.h b/src/control/control_local.h index fd9f941..5088b5f 100644 --- a/src/control/control_local.h +++ b/src/control/control_local.h @@ -95,6 +95,7 @@ struct _snd_hctl { int snd_ctl_new(snd_ctl_t **ctlp, snd_ctl_type_t type, const char *name); int _snd_ctl_poll_descriptor(snd_ctl_t *ctl); #define _snd_ctl_async_descriptor _snd_ctl_poll_descriptor -int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode); +int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, const char *devnode, int mode); +int snd_ctl_hw_card(snd_ctl_t *handle); int snd_ctl_shm_open(snd_ctl_t **handlep, const char *name, const char *sockname, const char *sname, int mode); int snd_ctl_async(snd_ctl_t *ctl, int sig, pid_t pid); diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index c46d14f..59734a1 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -1,3 +1,4 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /** * \file pcm/pcm_hw.c * \ingroup PCM_Plugins @@ -1260,7 +1261,8 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, * \brief Creates a new hw PCM * \param pcmp Returns created PCM handle * \param name Name of PCM - * \param card Number of card + * \param card Number of card (must be -1 if control_device_node is non-NULL) + * \param control_device_node Control device node in the file system (must be NULL if card is != -1) * \param device Number of device * \param subdevice Number of subdevice * \param stream PCM Stream @@ -1273,7 +1275,8 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, * changed in future. */ int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, - int card, int device, int subdevice, + int card, const char *control_device_node, + int device, int subdevice, snd_pcm_stream_t stream, int mode, int mmap_emulation ATTRIBUTE_UNUSED, int sync_ptr_ioctl) @@ -1288,9 +1291,11 @@ int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
assert(pcmp);
- if ((ret = snd_ctl_hw_open(&ctl, NULL, card, 0)) < 0) + if ((ret = snd_ctl_hw_open(&ctl, NULL, card, control_device_node, 0)) < 0) return ret;
+ card = snd_ctl_hw_card(ctl); + switch (stream) { case SND_PCM_STREAM_PLAYBACK: filefmt = SNDRV_FILE_PCM_STREAM_PLAYBACK; @@ -1399,7 +1404,7 @@ int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, { snd_config_iterator_t i, next; long card = -1, device = 0, subdevice = -1; - const char *str; + const char *str, *devnode = NULL; int err, sync_ptr_ioctl = 0; int rate = 0, channels = 0; snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN; @@ -1428,10 +1433,14 @@ int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, SNDERR("Invalid type for %s", id); return -EINVAL; } - card = snd_card_get_index(str); - if (card < 0) { - SNDERR("Invalid value for %s", id); - return card; + if (str[0] == '/') + devnode = str; + else { + card = snd_card_get_index(str); + if (card < 0) { + SNDERR("Invalid value for %s", id); + return card; + } } } continue; @@ -1498,11 +1507,11 @@ int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, SNDERR("Unknown field %s", id); return -EINVAL; } - if (card < 0) { + if (card < 0 && !devnode) { SNDERR("card is not defined"); return -EINVAL; } - err = snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream, + err = snd_pcm_hw_open(pcmp, name, card, devnode, device, subdevice, stream, mode | (nonblock ? SND_PCM_NONBLOCK : 0), 0, sync_ptr_ioctl); if (err < 0) diff --git a/src/rawmidi/rawmidi_hw.c b/src/rawmidi/rawmidi_hw.c index 87829fd..f02d4cf 100644 --- a/src/rawmidi/rawmidi_hw.c +++ b/src/rawmidi/rawmidi_hw.c @@ -1,4 +1,5 @@ -/* +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * * RawMIDI - Hardware * Copyright (c) 2000 by Jaroslav Kysela perex@perex.cz * Abramo Bagnara abramo@alsa-project.org @@ -170,7 +171,9 @@ static const snd_rawmidi_ops_t snd_rawmidi_hw_ops = {
int snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, - const char *name, int card, int device, int subdevice, + const char *name, + int card, const char *control_device_node, + int device, int subdevice, int mode) { int fd, ver, ret; @@ -186,9 +189,12 @@ int snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, *inputp = NULL; if (outputp) *outputp = NULL; - - if ((ret = snd_ctl_hw_open(&ctl, NULL, card, 0)) < 0) + + if ((ret = snd_ctl_hw_open(&ctl, NULL, card, control_device_node, 0)) < 0) return ret; + + card = snd_ctl_hw_card(ctl); + sprintf(filename, SNDRV_FILE_RAWMIDI, card, device);
__again: @@ -330,7 +336,7 @@ int _snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, { snd_config_iterator_t i, next; long card = -1, device = 0, subdevice = -1; - const char *str; + const char *str, *devnode = NULL; int err; snd_config_for_each(i, next, conf) { snd_config_t *n = snd_config_iterator_entry(i); @@ -345,9 +351,13 @@ int _snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, err = snd_config_get_string(n, &str); if (err < 0) return -EINVAL; - card = snd_card_get_index(str); - if (card < 0) - return card; + if (str[0] == '/') + devnode = str; + else { + card = snd_card_get_index(str); + if (card < 0) + return card; + } } continue; } @@ -365,8 +375,8 @@ int _snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, } return -EINVAL; } - if (card < 0) + if (card < 0 && !devnode) return -EINVAL; - return snd_rawmidi_hw_open(inputp, outputp, name, card, device, subdevice, mode); + return snd_rawmidi_hw_open(inputp, outputp, name, card, devnode, device, subdevice, mode); } SND_DLSYM_BUILD_VERSION(_snd_rawmidi_hw_open, SND_RAWMIDI_DLSYM_VERSION); diff --git a/src/rawmidi/rawmidi_local.h b/src/rawmidi/rawmidi_local.h index 3388502..ed2b7da 100644 --- a/src/rawmidi/rawmidi_local.h +++ b/src/rawmidi/rawmidi_local.h @@ -1,4 +1,4 @@ -/* +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * Rawmidi interface - local header file * Copyright (c) 2000 by Abramo Bagnara abramo@alsa-project.org * @@ -51,7 +51,9 @@ struct _snd_rawmidi { };
int snd_rawmidi_hw_open(snd_rawmidi_t **input, snd_rawmidi_t **output, - const char *name, int card, int device, int subdevice, + const char *name, + int card, const char *control_device_node, + int device, int subdevice, int mode);
int snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
On Tue, 12 May 2009, Lennart Poettering wrote:
Heya!
Traditionally low-level ALSA devices are opened with device strings like 'hw:CARD' where CARD is either a numeric index or a card name. This patch introduces a third syntax that allows you to specify the file name of the control device node. The purpose for this is to make ALSA a bit more like other Linux devices and allow implementaiton of udev device symlinks similar to how disks are currently handled, with /dev/disk/by-path/xxxx /dev/disk/by-id/xxxx and so on.
With this patch this line:
aplay -f CD -D hw:/dev/snd/controlC0 < /dev/urandom
becomes equivalent to this line:
aplay -f CD -D hw:0 < /dev/urandom
A more useful example is this:
aplay -f CD -D hw:/dev/snd/by-path/pci-0000:00:1a.7-usb-0:2:1.2
(this line requires a a few additional udev rules)
This only works for control devices nodes, not for PCM or any other device nodes. Since the control device node is used as 'entry point' when opening PCM devices this is no limitation.
NAK. Passing control device to open() functions is not a good idea. The snd_card_get_index() function might be extended to allow /dev style argument. Returned card index can be used as argument for hw: devices without this massive change.
http://git.alsa-project.org/?p=alsa-lib.git;a=commit;h=33ab0b5381c87e151e87e...
Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
On Tue, 12 May 2009, Jaroslav Kysela wrote:
On Tue, 12 May 2009, Lennart Poettering wrote:
Heya!
Traditionally low-level ALSA devices are opened with device strings like 'hw:CARD' where CARD is either a numeric index or a card name. This patch introduces a third syntax that allows you to specify the file name of the control device node. The purpose for this is to make ALSA a bit more like other Linux devices and allow implementaiton of udev device symlinks similar to how disks are currently handled, with /dev/disk/by-path/xxxx /dev/disk/by-id/xxxx and so on.
With this patch this line:
aplay -f CD -D hw:/dev/snd/controlC0 < /dev/urandom
becomes equivalent to this line:
aplay -f CD -D hw:0 < /dev/urandom
A more useful example is this:
aplay -f CD -D hw:/dev/snd/by-path/pci-0000:00:1a.7-usb-0:2:1.2
(this line requires a a few additional udev rules)
This only works for control devices nodes, not for PCM or any other device nodes. Since the control device node is used as 'entry point' when opening PCM devices this is no limitation.
NAK. Passing control device to open() functions is not a good idea. The snd_card_get_index() function might be extended to allow /dev style argument. Returned card index can be used as argument for hw: devices without this massive change.
http://git.alsa-project.org/?p=alsa-lib.git;a=commit;h=33ab0b5381c87e151e87e...
I just noticed that snd_card_get_index() is used to parse "card" configuration item when it's string, so control device name can be passed instead card identification to all open() functions in alsa-lib with my above patch, too. But it's preferred to use direct card index to reduce control device open/close sequences.
Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
On Tue, 12.05.09 13:40, Jaroslav Kysela (perex@perex.cz) wrote:
On Tue, 12 May 2009, Jaroslav Kysela wrote:
On Tue, 12 May 2009, Lennart Poettering wrote:
Heya!
Traditionally low-level ALSA devices are opened with device strings like 'hw:CARD' where CARD is either a numeric index or a card name. This patch introduces a third syntax that allows you to specify the file name of the control device node. The purpose for this is to make ALSA a bit more like other Linux devices and allow implementaiton of udev device symlinks similar to how disks are currently handled, with /dev/disk/by-path/xxxx /dev/disk/by-id/xxxx and so on.
With this patch this line:
aplay -f CD -D hw:/dev/snd/controlC0 < /dev/urandom
becomes equivalent to this line:
aplay -f CD -D hw:0 < /dev/urandom
A more useful example is this:
aplay -f CD -D hw:/dev/snd/by-path/pci-0000:00:1a.7-usb-0:2:1.2
(this line requires a a few additional udev rules)
This only works for control devices nodes, not for PCM or any other device nodes. Since the control device node is used as 'entry point' when opening PCM devices this is no limitation.
NAK. Passing control device to open() functions is not a good idea. The snd_card_get_index() function might be extended to allow /dev style argument. Returned card index can be used as argument for hw: devices without this massive change.
http://git.alsa-project.org/?p=alsa-lib.git;a=commit;h=33ab0b5381c87e151e87e...
I just noticed that snd_card_get_index() is used to parse "card" configuration item when it's string, so control device name can be passed instead card identification to all open() functions in alsa-lib with my above patch, too. But it's preferred to use direct card index to reduce control device open/close sequences.
With my original patch there are no superfluous opens.
Lennart
On Tue, 12 May 2009, Lennart Poettering wrote:
With my original patch there are no superfluous opens.
If application uses more *open() calls from alsa-lib for one card (for example to open ctl handle and pcm handle), it's better to obtain card index at first, because each conversion requires one or more (card id) open/close sequence for control device to get card_info. Providing direct card index eliminates this conversion. It's just suggested optimization.
Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
On Tue, 12.05.09 14:42, Jaroslav Kysela (perex@perex.cz) wrote:
On Tue, 12 May 2009, Lennart Poettering wrote:
With my original patch there are no superfluous opens.
If application uses more *open() calls from alsa-lib for one card (for example to open ctl handle and pcm handle), it's better to obtain card index at first, because each conversion requires one or more (card id) open/close sequence for control device to get card_info. Providing direct card index eliminates this conversion. It's just suggested optimization.
I think if apps want to open ctl and hw at the same time the most elegant way would be this:
<snip> snd_pcm_open(&pcm, "hw:/dev/snd/by-path/yaddayadda", ...); snd_pcm_info(pcm, &info); snd_ctl_open(&ctl, snprint("hw:%i", snd_pcm_info_get_card(info))); </snip>
With my patch that costs exactly two open() calls. It's also more flexible since it will handle arbitrary device strings, doesn't need to hardcode "hw:".
You seem to suggest this:
<snip> i = snd_card_index("hw:/dev/snd/by-path/yaddayadda"); snd_hw_open(&hw, snprint("hw:%i", i)); snd_ctl_open(&ctl, snprint("hw:%i", i)); </snip>
Which your patch that costs three open()s. And hardcodes "hw".
I really would like to know why my patch was so bad?
Lennart
On Tue, 12 May 2009, Lennart Poettering wrote:
On Tue, 12.05.09 14:42, Jaroslav Kysela (perex@perex.cz) wrote:
On Tue, 12 May 2009, Lennart Poettering wrote:
With my original patch there are no superfluous opens.
If application uses more *open() calls from alsa-lib for one card (for example to open ctl handle and pcm handle), it's better to obtain card index at first, because each conversion requires one or more (card id) open/close sequence for control device to get card_info. Providing direct card index eliminates this conversion. It's just suggested optimization.
I think if apps want to open ctl and hw at the same time the most elegant way would be this:
<snip> snd_pcm_open(&pcm, "hw:/dev/snd/by-path/yaddayadda", ...); snd_pcm_info(pcm, &info); snd_ctl_open(&ctl, snprint("hw:%i", snd_pcm_info_get_card(info))); </snip>
With my patch that costs exactly two open() calls. It's also more flexible since it will handle arbitrary device strings, doesn't need to hardcode "hw:".
The mentioned code will work with my patch as well. There is no difference, because extended snd_card_get_index() is called from _*open() callbacks when card argument is a string.
You seem to suggest this:
<snip> i = snd_card_index("hw:/dev/snd/by-path/yaddayadda");
It should be: i = snd_card_index("/dev/snd/by-path/yaddayadda");
snd_hw_open(&hw, snprint("hw:%i", i));
You mean probably snd_pcm_open() here.
snd_ctl_open(&ctl, snprint("hw:%i", i));
</snip>
Which your patch that costs three open()s.
It's similar to your patch. Two open calls. snd_pcm_open() does not use ctl device if a direct card index is specified.
And hardcodes "hw".
It's not relevant. Your code also hardcodes "hw" (and application should decide if hw: is a proper interface not alsa-lib - any defined device which accepts the card argument will work).
I really would like to know why my patch was so bad?
I do not think that an addition of extra argument to open() calls is good in this case. The card identification for open() calls is string anyway, because you may use syntax like 'hw:FirstHDACard' - see 'cat /proc/asound/cards' for string identification. All other extensions should be in the configuration area (in .conf files or configuration parsing code).
Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
On Tue, 12.05.09 16:40, Jaroslav Kysela (perex@perex.cz) wrote:
With my patch that costs exactly two open() calls. It's also more flexible since it will handle arbitrary device strings, doesn't need to hardcode "hw:".
The mentioned code will work with my patch as well. There is no difference, because extended snd_card_get_index() is called from _*open() callbacks when card argument is a string.
Yes, it will work. But at the price of one extra open.
You seem to suggest this:
<snip> i = snd_card_index("hw:/dev/snd/by-path/yaddayadda");
It should be: i = snd_card_index("/dev/snd/by-path/yaddayadda");
Yes, of course.
snd_hw_open(&hw, snprint("hw:%i", i));
You mean probably snd_pcm_open() here.
Yes, you are right.
snd_ctl_open(&ctl, snprint("hw:%i", i));
</snip>
Which your patch that costs three open()s.
It's similar to your patch. Two open calls. snd_pcm_open() does not use ctl device if a direct card index is specified.
Hmm? The first thing snd_pcm_hw_open() does is calling snd_ctl_hw_open(). So with your code, the name will bre resolved and the ctl device opened and closed for that. And then shortly after the device will be reopened right-away and then kept open. In my code after the resolving I'd just keep the device open.
Your code requires three open()s for this, mine required two.
And hardcodes "hw".
It's not relevant. Your code also hardcodes "hw" (and application should decide if hw: is a proper interface not alsa-lib - any defined device which accepts the card argument will work).
The example code I gave doesn't hardcode it. You can specify any device as long as the stream info knows the card parameter properly.
I really would like to know why my patch was so bad?
I do not think that an addition of extra argument to open() calls is good in this case. The card identification for open() calls is string anyway, because you may use syntax like 'hw:FirstHDACard' - see 'cat /proc/asound/cards' for string identification. All other extensions should be in the configuration area (in .conf files or configuration parsing code).
Hmm? The whole point of my patch was to make ALSA devices a bit more like other devices, i.e. with persistancy of device symlinks and stuff. Also, AFAICS the snd_pcm_hw_open() call (and friends) are internal anyway?
Anyway, given that your code has the same effect as mine, it's probably not worth dicussing this any further...
Lennart
On Tue, 12 May 2009, Lennart Poettering wrote:
Hmm? The first thing snd_pcm_hw_open() does is calling snd_ctl_hw_open(). So with your code, the name will bre resolved and the ctl device opened and closed for that. And then shortly after the device will be reopened right-away and then kept open. In my code after the resolving I'd just keep the device open.
Your code requires three open()s for this, mine required two.
I see your point now - I forgot that control API is used to prefer subdevices. But it would be better to add some cache for ctl opens in alsa-lib rather than abusing other levels of API with additional information.
Thanks, Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
On Tue, 12.05.09 08:09, Jaroslav Kysela (perex@perex.cz) wrote:
On Tue, 12 May 2009, Lennart Poettering wrote:
Heya!
Traditionally low-level ALSA devices are opened with device strings like 'hw:CARD' where CARD is either a numeric index or a card name. This patch introduces a third syntax that allows you to specify the file name of the control device node. The purpose for this is to make ALSA a bit more like other Linux devices and allow implementaiton of udev device symlinks similar to how disks are currently handled, with /dev/disk/by-path/xxxx /dev/disk/by-id/xxxx and so on.
With this patch this line:
aplay -f CD -D hw:/dev/snd/controlC0 < /dev/urandom
becomes equivalent to this line:
aplay -f CD -D hw:0 < /dev/urandom
A more useful example is this:
aplay -f CD -D hw:/dev/snd/by-path/pci-0000:00:1a.7-usb-0:2:1.2
(this line requires a a few additional udev rules)
This only works for control devices nodes, not for PCM or any other device nodes. Since the control device node is used as 'entry point' when opening PCM devices this is no limitation.
NAK. Passing control device to open() functions is not a good idea.
Why? Please elaborate!
The whole point of this patch is to allow users to write struff like hw:/dev/snd/by-path/pci-0000:00:1a.7-usb-0:2:1.2 whereever they could otherwise write hw:0. Why is that a bad idea?
The snd_card_get_index() function might be extended to allow /dev style argument. Returned card index can be used as argument for hw: devices without this massive change.
This is no improvement at all, because no application does that. The point of the patch was to improve the flexibility for all applications.
Lennart
participants (2)
-
Jaroslav Kysela
-
Lennart Poettering