From 57631a012ca9370a6b5cb33d3d86bee8a2a696f2 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sun, 22 Aug 1999 13:34:31 +0000 Subject: [PATCH] PCM SUBDEVICE selection enhancements --- include/control.h | 5 +++-- include/pcm.h | 1 + src/control/control.c | 34 +++++++++++++++++++++++------- src/pcm/pcm.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 83 insertions(+), 15 deletions(-) diff --git a/include/control.h b/include/control.h index 44720cf1..8247f0ec 100644 --- a/include/control.h +++ b/include/control.h @@ -40,14 +40,15 @@ int snd_ctl_switch_read(snd_ctl_t *handle, snd_switch_t * sw); int snd_ctl_switch_write(snd_ctl_t *handle, snd_switch_t * sw); int snd_ctl_hwdep_info(snd_ctl_t *handle, int dev, snd_hwdep_info_t * info); int snd_ctl_pcm_info(snd_ctl_t *handle, int dev, snd_pcm_info_t * info); -int snd_ctl_pcm_playback_info(snd_ctl_t *handle, int dev, snd_pcm_playback_info_t * info); -int snd_ctl_pcm_capture_info(snd_ctl_t *handle, int dev, snd_pcm_capture_info_t * info); +int snd_ctl_pcm_playback_info(snd_ctl_t *handle, int dev, int subdev, snd_pcm_playback_info_t * info); +int snd_ctl_pcm_capture_info(snd_ctl_t *handle, int dev, int subdev, snd_pcm_capture_info_t * info); int snd_ctl_pcm_playback_switch_list(snd_ctl_t *handle, int dev, snd_switch_list_t * list); int snd_ctl_pcm_playback_switch_read(snd_ctl_t *handle, int dev, snd_switch_t * sw); int snd_ctl_pcm_playback_switch_write(snd_ctl_t *handle, int dev, snd_switch_t * sw); int snd_ctl_pcm_capture_switch_list(snd_ctl_t *handle, int dev, snd_switch_list_t * list); int snd_ctl_pcm_capture_switch_read(snd_ctl_t *handle, int dev, snd_switch_t * sw); int snd_ctl_pcm_capture_switch_write(snd_ctl_t *handle, int dev, snd_switch_t * sw); +int snd_ctl_pcm_prefer_subdevice(snd_ctl_t *handle, int dev, int subdev); int snd_ctl_mixer_info(snd_ctl_t *handle, int dev, snd_mixer_info_t * info); int snd_ctl_mixer_switch_list(snd_ctl_t *handle, int dev, snd_switch_list_t *list); int snd_ctl_mixer_switch_read(snd_ctl_t *handle, int dev, snd_switch_t * sw); diff --git a/include/pcm.h b/include/pcm.h index 69707810..85fba847 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -17,6 +17,7 @@ typedef struct snd_pcm snd_pcm_t; typedef struct snd_pcm_loopback snd_pcm_loopback_t; int snd_pcm_open(snd_pcm_t **handle, int card, int device, int mode); +int snd_pcm_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int mode); int snd_pcm_close(snd_pcm_t *handle); int snd_pcm_file_descriptor(snd_pcm_t *handle); int snd_pcm_block_mode(snd_pcm_t *handle, int enable); diff --git a/src/control/control.c b/src/control/control.c index 8fd59880..ff1c8af6 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -29,7 +29,7 @@ #include "asoundlib.h" #define SND_FILE_CONTROL "/dev/snd/controlC%i" -#define SND_CTL_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0) +#define SND_CTL_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 1) struct snd_ctl { int card; @@ -171,29 +171,33 @@ int snd_ctl_pcm_info(snd_ctl_t *handle, int dev, snd_pcm_info_t * info) return 0; } -int snd_ctl_pcm_playback_info(snd_ctl_t *handle, int dev, snd_pcm_playback_info_t * info) +int snd_ctl_pcm_playback_info(snd_ctl_t *handle, int dev, int subdev, snd_pcm_playback_info_t * info) { snd_ctl_t *ctl; ctl = handle; - if (!ctl || !info || dev < 0) + if (!ctl || !info || dev < 0 || subdev < 0) return -EINVAL; if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0) return -errno; + if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_SUBDEVICE, &subdev) < 0) + return -errno; if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_PLAYBACK_INFO, info) < 0) return -errno; return 0; } -int snd_ctl_pcm_capture_info(snd_ctl_t *handle, int dev, snd_pcm_capture_info_t * info) +int snd_ctl_pcm_capture_info(snd_ctl_t *handle, int dev, int subdev, snd_pcm_capture_info_t * info) { snd_ctl_t *ctl; ctl = handle; - if (!ctl || !info || dev < 0) + if (!ctl || !info || dev < 0 || subdev < 0) return -EINVAL; if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0) return -errno; + if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_SUBDEVICE, &subdev) < 0) + return -errno; if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_CAPTURE_INFO, info) < 0) return -errno; return 0; @@ -250,7 +254,7 @@ int snd_ctl_pcm_capture_switch_list(snd_ctl_t *handle, int dev, snd_switch_list_ return -EINVAL; if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0) return -errno; - if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_RSWITCH_LIST, list) < 0) + if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_CSWITCH_LIST, list) < 0) return -errno; return 0; } @@ -264,7 +268,7 @@ int snd_ctl_pcm_capture_switch_read(snd_ctl_t *handle, int dev, snd_switch_t * s return -EINVAL; if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0) return -errno; - if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_RSWITCH_READ, sw) < 0) + if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_CSWITCH_READ, sw) < 0) return -errno; return 0; } @@ -278,7 +282,21 @@ int snd_ctl_pcm_capture_switch_write(snd_ctl_t *handle, int dev, snd_switch_t * return -EINVAL; if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0) return -errno; - if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_RSWITCH_WRITE, sw) < 0) + if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_CSWITCH_WRITE, sw) < 0) + return -errno; + return 0; +} + +int snd_ctl_pcm_prefer_subdevice(snd_ctl_t *handle, int dev, int subdev) +{ + snd_ctl_t *ctl; + + ctl = handle; + if (!ctl || dev < 0) + return -EINVAL; + if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0) + return -errno; + if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_PREFER_SUBDEVICE, &subdev) < 0) return -errno; return 0; } diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 350b4ad3..7046df8b 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -35,32 +35,79 @@ struct snd_pcm { int card; int device; int fd; + int mode; }; int snd_pcm_open(snd_pcm_t **handle, int card, int device, int mode) { - int fd, ver; + return snd_pcm_open_subdevice(handle, card, device, -1, mode); +} + +int snd_pcm_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int mode) +{ + int fd, ver, err, attempt = 0; char filename[32]; snd_pcm_t *pcm; + snd_ctl_t *ctl; + snd_pcm_playback_info_t pinfo; + snd_pcm_capture_info_t cinfo; *handle = NULL; if (card < 0 || card >= SND_CARDS) return -EINVAL; + if ((err = snd_ctl_open(&ctl, card)) < 0) + return err; + __again: + if (attempt++ > 3) { + snd_ctl_close(ctl); + return -EBUSY; + } + if ((err = snd_ctl_pcm_prefer_subdevice(ctl, device, subdevice)) < 0) { + snd_ctl_close(ctl); + return err; + } sprintf(filename, SND_FILE_PCM, card, device); if ((fd = open(filename, mode)) < 0) { - snd_card_load(card); - if ((fd = open(filename, mode)) < 0) - return -errno; + err = -errno; + snd_ctl_close(ctl); + return err; } if (ioctl(fd, SND_PCM_IOCTL_PVERSION, &ver) < 0) { + err = -errno; close(fd); - return -errno; + snd_ctl_close(ctl); + return err; } if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_PCM_VERSION_MAX)) { close(fd); + snd_ctl_close(ctl); return -SND_ERROR_INCOMPATIBLE_VERSION; } + if (subdevice >= 0 && (mode == SND_PCM_OPEN_PLAYBACK || mode == SND_PCM_OPEN_DUPLEX)) { + if (ioctl(fd, SND_PCM_IOCTL_PLAYBACK_INFO, &pinfo) < 0) { + err = -errno; + close(fd); + snd_ctl_close(ctl); + return err; + } + if (pinfo.subdevice != subdevice) { + close(fd); + goto __again; + } + } + if (subdevice >= 0 && (mode == SND_PCM_OPEN_CAPTURE || mode == SND_PCM_OPEN_DUPLEX)) { + if (ioctl(fd, SND_PCM_IOCTL_CAPTURE_INFO, &cinfo) < 0) { + err = -errno; + close(fd); + snd_ctl_close(ctl); + return err; + } + if (cinfo.subdevice != subdevice) { + close(fd); + goto __again; + } + } pcm = (snd_pcm_t *) calloc(1, sizeof(snd_pcm_t)); if (pcm == NULL) { close(fd); @@ -69,6 +116,7 @@ int snd_pcm_open(snd_pcm_t **handle, int card, int device, int mode) pcm->card = card; pcm->device = device; pcm->fd = fd; + pcm->mode = mode; *handle = pcm; return 0; } -- 2.11.0