mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	PCM SUBDEVICE selection enhancements
This commit is contained in:
		
							parent
							
								
									a234679700
								
							
						
					
					
						commit
						57631a012c
					
				
					 4 changed files with 83 additions and 15 deletions
				
			
		| 
						 | 
					@ -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_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_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_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_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, 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);
 | 
				
			||||||
int snd_ctl_pcm_playback_switch_list(snd_ctl_t *handle, int dev, snd_switch_list_t * list);
 | 
					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_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_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_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_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_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_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_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);
 | 
					int snd_ctl_mixer_switch_read(snd_ctl_t *handle, int dev, snd_switch_t * sw);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,7 @@ typedef struct snd_pcm snd_pcm_t;
 | 
				
			||||||
typedef struct snd_pcm_loopback snd_pcm_loopback_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(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_close(snd_pcm_t *handle);
 | 
				
			||||||
int snd_pcm_file_descriptor(snd_pcm_t *handle);
 | 
					int snd_pcm_file_descriptor(snd_pcm_t *handle);
 | 
				
			||||||
int snd_pcm_block_mode(snd_pcm_t *handle, int enable);
 | 
					int snd_pcm_block_mode(snd_pcm_t *handle, int enable);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@
 | 
				
			||||||
#include "asoundlib.h"
 | 
					#include "asoundlib.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SND_FILE_CONTROL	"/dev/snd/controlC%i"
 | 
					#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 {
 | 
					struct snd_ctl {
 | 
				
			||||||
	int card;
 | 
						int card;
 | 
				
			||||||
| 
						 | 
					@ -171,29 +171,33 @@ int snd_ctl_pcm_info(snd_ctl_t *handle, int dev, snd_pcm_info_t * info)
 | 
				
			||||||
	return 0;
 | 
						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;
 | 
						snd_ctl_t *ctl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctl = handle;
 | 
						ctl = handle;
 | 
				
			||||||
	if (!ctl || !info || dev < 0)
 | 
						if (!ctl || !info || dev < 0 || subdev < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0)
 | 
						if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0)
 | 
				
			||||||
		return -errno;
 | 
							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)
 | 
						if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_PLAYBACK_INFO, info) < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	return 0;
 | 
						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;
 | 
						snd_ctl_t *ctl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctl = handle;
 | 
						ctl = handle;
 | 
				
			||||||
	if (!ctl || !info || dev < 0)
 | 
						if (!ctl || !info || dev < 0 || subdev < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0)
 | 
						if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0)
 | 
				
			||||||
		return -errno;
 | 
							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)
 | 
						if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_CAPTURE_INFO, info) < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -250,7 +254,7 @@ int snd_ctl_pcm_capture_switch_list(snd_ctl_t *handle, int dev, snd_switch_list_
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0)
 | 
						if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0)
 | 
				
			||||||
		return -errno;
 | 
							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 -errno;
 | 
				
			||||||
	return 0;
 | 
						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;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0)
 | 
						if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0)
 | 
				
			||||||
		return -errno;
 | 
							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 -errno;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -278,7 +282,21 @@ int snd_ctl_pcm_capture_switch_write(snd_ctl_t *handle, int dev, snd_switch_t *
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0)
 | 
						if (ioctl(ctl->fd, SND_CTL_IOCTL_PCM_DEVICE, &dev) < 0)
 | 
				
			||||||
		return -errno;
 | 
							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 -errno;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,32 +35,79 @@ struct snd_pcm {
 | 
				
			||||||
	int card;
 | 
						int card;
 | 
				
			||||||
	int device;
 | 
						int device;
 | 
				
			||||||
	int fd;
 | 
						int fd;
 | 
				
			||||||
 | 
						int mode;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_open(snd_pcm_t **handle, int card, int device, 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];
 | 
						char filename[32];
 | 
				
			||||||
	snd_pcm_t *pcm;
 | 
						snd_pcm_t *pcm;
 | 
				
			||||||
 | 
						snd_ctl_t *ctl;
 | 
				
			||||||
 | 
						snd_pcm_playback_info_t pinfo;
 | 
				
			||||||
 | 
						snd_pcm_capture_info_t cinfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*handle = NULL;
 | 
						*handle = NULL;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	if (card < 0 || card >= SND_CARDS)
 | 
						if (card < 0 || card >= SND_CARDS)
 | 
				
			||||||
		return -EINVAL;
 | 
							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);
 | 
						sprintf(filename, SND_FILE_PCM, card, device);
 | 
				
			||||||
	if ((fd = open(filename, mode)) < 0) {
 | 
						if ((fd = open(filename, mode)) < 0) {
 | 
				
			||||||
		snd_card_load(card);
 | 
							err = -errno;
 | 
				
			||||||
		if ((fd = open(filename, mode)) < 0) 
 | 
							snd_ctl_close(ctl);
 | 
				
			||||||
			return -errno;
 | 
							return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (ioctl(fd, SND_PCM_IOCTL_PVERSION, &ver) < 0) {
 | 
						if (ioctl(fd, SND_PCM_IOCTL_PVERSION, &ver) < 0) {
 | 
				
			||||||
 | 
							err = -errno;
 | 
				
			||||||
		close(fd);
 | 
							close(fd);
 | 
				
			||||||
		return -errno;
 | 
							snd_ctl_close(ctl);
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_PCM_VERSION_MAX)) {
 | 
						if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_PCM_VERSION_MAX)) {
 | 
				
			||||||
		close(fd);
 | 
							close(fd);
 | 
				
			||||||
 | 
							snd_ctl_close(ctl);
 | 
				
			||||||
		return -SND_ERROR_INCOMPATIBLE_VERSION;
 | 
							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));
 | 
						pcm = (snd_pcm_t *) calloc(1, sizeof(snd_pcm_t));
 | 
				
			||||||
	if (pcm == NULL) {
 | 
						if (pcm == NULL) {
 | 
				
			||||||
		close(fd);
 | 
							close(fd);
 | 
				
			||||||
| 
						 | 
					@ -69,6 +116,7 @@ int snd_pcm_open(snd_pcm_t **handle, int card, int device, int mode)
 | 
				
			||||||
	pcm->card = card;
 | 
						pcm->card = card;
 | 
				
			||||||
	pcm->device = device;
 | 
						pcm->device = device;
 | 
				
			||||||
	pcm->fd = fd;
 | 
						pcm->fd = fd;
 | 
				
			||||||
 | 
						pcm->mode = mode;
 | 
				
			||||||
	*handle = pcm;
 | 
						*handle = pcm;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue