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);
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);
#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;
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;
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;
}
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;
}
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;
}
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);
pcm->card = card;
pcm->device = device;
pcm->fd = fd;
+ pcm->mode = mode;
*handle = pcm;
return 0;
}