mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	Cleaned pcm internals. Added mmap'able plugins
This commit is contained in:
		
							parent
							
								
									340eb52ea2
								
							
						
					
					
						commit
						5673d299a9
					
				
					 5 changed files with 594 additions and 274 deletions
				
			
		| 
						 | 
					@ -6,7 +6,7 @@ libasound_la_SOURCES = error.c
 | 
				
			||||||
libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \
 | 
					libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \
 | 
				
			||||||
                      rawmidi/librawmidi.la timer/libtimer.la hwdep/libhwdep.la \
 | 
					                      rawmidi/librawmidi.la timer/libtimer.la hwdep/libhwdep.la \
 | 
				
			||||||
                      seq/libseq.la instr/libinstr.la
 | 
					                      seq/libseq.la instr/libinstr.la
 | 
				
			||||||
libasound_la_LDFLAGS = -version-info $(COMPATNUM)
 | 
					libasound_la_LDFLAGS = -version-info $(COMPATNUM) -lpthread
 | 
				
			||||||
 | 
					
 | 
				
			||||||
control/libcontrol.la:
 | 
					control/libcontrol.la:
 | 
				
			||||||
	$(MAKE) -C control libcontrol.la
 | 
						$(MAKE) -C control libcontrol.la
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										145
									
								
								src/pcm/pcm.c
									
										
									
									
									
								
							
							
						
						
									
										145
									
								
								src/pcm/pcm.c
									
										
									
									
									
								
							| 
						 | 
					@ -139,8 +139,8 @@ int snd_pcm_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevi
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pcm->card = card;
 | 
						pcm->card = card;
 | 
				
			||||||
	pcm->device = device;
 | 
						pcm->device = device;
 | 
				
			||||||
	pcm->fd[SND_PCM_CHANNEL_PLAYBACK] = pfd;
 | 
						pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd = pfd;
 | 
				
			||||||
	pcm->fd[SND_PCM_CHANNEL_CAPTURE] = cfd;
 | 
						pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd = cfd;
 | 
				
			||||||
	pcm->mode = mode;
 | 
						pcm->mode = mode;
 | 
				
			||||||
	pcm->ver = ver;
 | 
						pcm->ver = ver;
 | 
				
			||||||
	*handle = pcm;
 | 
						*handle = pcm;
 | 
				
			||||||
| 
						 | 
					@ -155,10 +155,11 @@ int snd_pcm_close(snd_pcm_t *pcm)
 | 
				
			||||||
	if (!pcm)
 | 
						if (!pcm)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	for (channel = 0; channel < 2; ++channel) {
 | 
						for (channel = 0; channel < 2; ++channel) {
 | 
				
			||||||
		snd_pcm_munmap(pcm, channel);
 | 
							snd_pcm_plugin_munmap(pcm, channel);
 | 
				
			||||||
		snd_pcm_plugin_clear(pcm, channel);
 | 
							snd_pcm_plugin_clear(pcm, channel);
 | 
				
			||||||
		if (pcm->fd[channel] >= 0)
 | 
							snd_pcm_munmap(pcm, channel);
 | 
				
			||||||
			if (close(pcm->fd[channel]))
 | 
							if (pcm->chan[channel].fd >= 0)
 | 
				
			||||||
 | 
								if (close(pcm->chan[channel].fd))
 | 
				
			||||||
				res = -errno;
 | 
									res = -errno;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	free(pcm);
 | 
						free(pcm);
 | 
				
			||||||
| 
						 | 
					@ -171,7 +172,7 @@ int snd_pcm_file_descriptor(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (channel < 0 || channel > 1)
 | 
						if (channel < 0 || channel > 1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	return pcm->fd[channel];
 | 
						return pcm->chan[channel].fd;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_nonblock_mode(snd_pcm_t *pcm, int nonblock)
 | 
					int snd_pcm_nonblock_mode(snd_pcm_t *pcm, int nonblock)
 | 
				
			||||||
| 
						 | 
					@ -182,7 +183,7 @@ int snd_pcm_nonblock_mode(snd_pcm_t *pcm, int nonblock)
 | 
				
			||||||
	if (!pcm)
 | 
						if (!pcm)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	for (channel = 0; channel < 2; ++channel) {
 | 
						for (channel = 0; channel < 2; ++channel) {
 | 
				
			||||||
		fd = pcm->fd[channel];
 | 
							fd = pcm->chan[channel].fd;
 | 
				
			||||||
		if (fd < 0)
 | 
							if (fd < 0)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if ((flags = fcntl(fd, F_GETFL)) < 0)
 | 
							if ((flags = fcntl(fd, F_GETFL)) < 0)
 | 
				
			||||||
| 
						 | 
					@ -207,7 +208,7 @@ int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
 | 
				
			||||||
	if (!pcm || !info)
 | 
						if (!pcm || !info)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	for (channel = 0; channel < 2; ++channel) {
 | 
						for (channel = 0; channel < 2; ++channel) {
 | 
				
			||||||
		fd = pcm->fd[channel];
 | 
							fd = pcm->chan[channel].fd;
 | 
				
			||||||
		if (fd >= 0)
 | 
							if (fd >= 0)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -223,7 +224,7 @@ int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (info->channel < 0 || info->channel > 1)
 | 
						if (info->channel < 0 || info->channel > 1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	fd = pcm->fd[info->channel];
 | 
						fd = pcm->chan[info->channel].fd;
 | 
				
			||||||
	if (fd < 0)
 | 
						if (fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_INFO, info) < 0)
 | 
						if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_INFO, info) < 0)
 | 
				
			||||||
| 
						 | 
					@ -235,43 +236,47 @@ int snd_pcm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	int fd;
 | 
						int fd;
 | 
				
			||||||
 | 
						struct snd_pcm_chan *chan;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!pcm || !params)
 | 
						if (!pcm || !params)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (params->channel < 0 || params->channel > 1)
 | 
						if (params->channel < 0 || params->channel > 1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	fd = pcm->fd[params->channel];
 | 
						chan = &pcm->chan[params->channel];
 | 
				
			||||||
 | 
						fd = chan->fd;
 | 
				
			||||||
	if (fd < 0)
 | 
						if (fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_PARAMS, params) < 0)
 | 
						if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_PARAMS, params) < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	pcm->setup_is_valid[params->channel] = 0;
 | 
						chan->setup_is_valid = 0;
 | 
				
			||||||
	memset(&pcm->setup[params->channel], 0, sizeof(snd_pcm_channel_setup_t));
 | 
						memset(&chan->setup, 0, sizeof(snd_pcm_channel_setup_t));
 | 
				
			||||||
	pcm->setup[params->channel].channel = params->channel;
 | 
						chan->setup.channel = params->channel;
 | 
				
			||||||
	if ((err = snd_pcm_channel_setup(pcm, &pcm->setup[params->channel]))<0)
 | 
						if ((err = snd_pcm_channel_setup(pcm, &chan->setup))<0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	pcm->setup_is_valid[params->channel] = 1;
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
 | 
					int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int fd;
 | 
						int fd;
 | 
				
			||||||
 | 
						struct snd_pcm_chan *chan;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!pcm || !setup)
 | 
						if (!pcm || !setup)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (setup->channel < 0 || setup->channel > 1)
 | 
						if (setup->channel < 0 || setup->channel > 1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	fd = pcm->fd[setup->channel];
 | 
						chan = &pcm->chan[setup->channel];
 | 
				
			||||||
 | 
						fd = chan->fd;
 | 
				
			||||||
	if (fd < 0)
 | 
						if (fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->setup_is_valid[setup->channel]) {
 | 
						if (chan->setup_is_valid) {
 | 
				
			||||||
		memcpy(setup, &pcm->setup[setup->channel], sizeof(*setup));
 | 
							memcpy(setup, &chan->setup, sizeof(*setup));
 | 
				
			||||||
	} else {
 | 
							return 0;
 | 
				
			||||||
		if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0)
 | 
					 | 
				
			||||||
			return -errno;
 | 
					 | 
				
			||||||
		memcpy(&pcm->setup[setup->channel], setup, sizeof(*setup));
 | 
					 | 
				
			||||||
		pcm->setup_is_valid[setup->channel] = 1;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						memcpy(&chan->setup, setup, sizeof(*setup));
 | 
				
			||||||
 | 
						chan->setup_is_valid = 1;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -282,7 +287,7 @@ int snd_pcm_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t * set
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (channel < 0 || channel > 1)
 | 
						if (channel < 0 || channel > 1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	fd = pcm->fd[channel];
 | 
						fd = pcm->chan[channel].fd;
 | 
				
			||||||
	if (fd < 0)
 | 
						if (fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(fd, SND_PCM_IOCTL_VOICE_SETUP, setup) < 0)
 | 
						if (ioctl(fd, SND_PCM_IOCTL_VOICE_SETUP, setup) < 0)
 | 
				
			||||||
| 
						 | 
					@ -295,7 +300,7 @@ int snd_pcm_channel_status(snd_pcm_t *pcm, snd_pcm_channel_status_t * status)
 | 
				
			||||||
	int fd;
 | 
						int fd;
 | 
				
			||||||
	if (!pcm || !status)
 | 
						if (!pcm || !status)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	fd = pcm->fd[status->channel];
 | 
						fd = pcm->chan[status->channel].fd;
 | 
				
			||||||
	if (fd < 0)
 | 
						if (fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_STATUS, status) < 0)
 | 
						if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_STATUS, status) < 0)
 | 
				
			||||||
| 
						 | 
					@ -307,9 +312,9 @@ int snd_pcm_playback_prepare(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!pcm)
 | 
						if (!pcm)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0)
 | 
						if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_PCM_IOCTL_CHANNEL_PREPARE) < 0)
 | 
						if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_PREPARE) < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -318,9 +323,9 @@ int snd_pcm_capture_prepare(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!pcm)
 | 
						if (!pcm)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->fd[SND_PCM_CHANNEL_CAPTURE] < 0)
 | 
						if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(pcm->fd[SND_PCM_CHANNEL_CAPTURE], SND_PCM_IOCTL_CHANNEL_PREPARE) < 0)
 | 
						if (ioctl(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, SND_PCM_IOCTL_CHANNEL_PREPARE) < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -341,9 +346,9 @@ int snd_pcm_playback_go(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!pcm)
 | 
						if (!pcm)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0)
 | 
						if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_PCM_IOCTL_CHANNEL_GO) < 0)
 | 
						if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_GO) < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -352,9 +357,9 @@ int snd_pcm_capture_go(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!pcm)
 | 
						if (!pcm)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->fd[SND_PCM_CHANNEL_CAPTURE] < 0)
 | 
						if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(pcm->fd[SND_PCM_CHANNEL_CAPTURE], SND_PCM_IOCTL_CHANNEL_GO) < 0)
 | 
						if (ioctl(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, SND_PCM_IOCTL_CHANNEL_GO) < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -375,9 +380,9 @@ int snd_pcm_sync_go(snd_pcm_t *pcm, snd_pcm_sync_t *sync)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!pcm || !sync)
 | 
						if (!pcm || !sync)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0)
 | 
						if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_PCM_IOCTL_SYNC_GO, sync) < 0)
 | 
						if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_SYNC_GO, sync) < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -386,9 +391,9 @@ int snd_pcm_playback_drain(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!pcm)
 | 
						if (!pcm)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0)
 | 
						if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_PCM_IOCTL_CHANNEL_DRAIN) < 0)
 | 
						if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_DRAIN) < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -397,9 +402,9 @@ int snd_pcm_playback_flush(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!pcm)
 | 
						if (!pcm)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0)
 | 
						if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_PCM_IOCTL_CHANNEL_FLUSH) < 0)
 | 
						if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_FLUSH) < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -408,9 +413,9 @@ int snd_pcm_capture_flush(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!pcm)
 | 
						if (!pcm)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->fd[SND_PCM_CHANNEL_CAPTURE] < 0)
 | 
						if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(pcm->fd[SND_PCM_CHANNEL_CAPTURE], SND_PCM_IOCTL_CHANNEL_FLUSH) < 0)
 | 
						if (ioctl(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, SND_PCM_IOCTL_CHANNEL_FLUSH) < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -431,22 +436,24 @@ int snd_pcm_playback_pause(snd_pcm_t *pcm, int enable)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!pcm)
 | 
						if (!pcm)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0)
 | 
						if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_PCM_IOCTL_CHANNEL_PAUSE, &enable) < 0)
 | 
						if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_PAUSE, &enable) < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ssize_t snd_pcm_transfer_size(snd_pcm_t *pcm, int channel)
 | 
					ssize_t snd_pcm_transfer_size(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct snd_pcm_chan *chan;
 | 
				
			||||||
	if (!pcm || channel < 0 || channel > 1)
 | 
						if (!pcm || channel < 0 || channel > 1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (!pcm->setup_is_valid[channel])
 | 
						chan = &pcm->chan[channel];
 | 
				
			||||||
 | 
						if (!chan->setup_is_valid)
 | 
				
			||||||
		return -EBADFD;
 | 
							return -EBADFD;
 | 
				
			||||||
	if (pcm->setup[channel].mode != SND_PCM_MODE_BLOCK)
 | 
						if (chan->setup.mode != SND_PCM_MODE_BLOCK)
 | 
				
			||||||
		return -EBADFD;
 | 
							return -EBADFD;
 | 
				
			||||||
	return pcm->setup[channel].buf.block.frag_size;
 | 
						return chan->setup.buf.block.frag_size;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ssize_t snd_pcm_write(snd_pcm_t *pcm, const void *buffer, size_t size)
 | 
					ssize_t snd_pcm_write(snd_pcm_t *pcm, const void *buffer, size_t size)
 | 
				
			||||||
| 
						 | 
					@ -455,9 +462,9 @@ ssize_t snd_pcm_write(snd_pcm_t *pcm, const void *buffer, size_t size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!pcm || (!buffer && size > 0) || size < 0)
 | 
						if (!pcm || (!buffer && size > 0) || size < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0)
 | 
						if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	result = write(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], buffer, size);
 | 
						result = write(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, buffer, size);
 | 
				
			||||||
	if (result < 0)
 | 
						if (result < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
| 
						 | 
					@ -469,16 +476,16 @@ ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, int count)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!pcm || (!vector && count > 0) || count < 0)
 | 
						if (!pcm || (!vector && count > 0) || count < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->fd[SND_PCM_CHANNEL_PLAYBACK] < 0)
 | 
						if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
#if 0
 | 
					#if 0
 | 
				
			||||||
	result = writev(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], vector, count);
 | 
						result = writev(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, vector, count);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		snd_v_args_t args;
 | 
							snd_v_args_t args;
 | 
				
			||||||
		args.vector = vector;
 | 
							args.vector = vector;
 | 
				
			||||||
		args.count = count;
 | 
							args.count = count;
 | 
				
			||||||
		result = ioctl(pcm->fd[SND_PCM_CHANNEL_PLAYBACK], SND_IOCTL_WRITEV, &args);
 | 
							result = ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_IOCTL_WRITEV, &args);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	if (result < 0)
 | 
						if (result < 0)
 | 
				
			||||||
| 
						 | 
					@ -492,9 +499,9 @@ ssize_t snd_pcm_read(snd_pcm_t *pcm, void *buffer, size_t size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!pcm || (!buffer && size > 0) || size < 0)
 | 
						if (!pcm || (!buffer && size > 0) || size < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->fd[SND_PCM_CHANNEL_CAPTURE] < 0)
 | 
						if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	result = read(pcm->fd[SND_PCM_CHANNEL_CAPTURE], buffer, size);
 | 
						result = read(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, buffer, size);
 | 
				
			||||||
	if (result < 0)
 | 
						if (result < 0)
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
| 
						 | 
					@ -506,16 +513,16 @@ ssize_t snd_pcm_readv(snd_pcm_t *pcm, const struct iovec *vector, int count)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!pcm || (!vector && count > 0) || count < 0)
 | 
						if (!pcm || (!vector && count > 0) || count < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->fd[SND_PCM_CHANNEL_CAPTURE] < 0)
 | 
						if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
#if 0
 | 
					#if 0
 | 
				
			||||||
	result = readv(pcm->fd[SND_PCM_CHANNEL_CAPTURE], vector, count);
 | 
						result = readv(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, vector, count);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		snd_v_args_t args;
 | 
							snd_v_args_t args;
 | 
				
			||||||
		args.vector = vector;
 | 
							args.vector = vector;
 | 
				
			||||||
		args.count = count;
 | 
							args.count = count;
 | 
				
			||||||
		result = ioctl(pcm->fd[SND_PCM_CHANNEL_CAPTURE], SND_IOCTL_READV, &args);
 | 
							result = ioctl(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, SND_IOCTL_READV, &args);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	if (result < 0)
 | 
						if (result < 0)
 | 
				
			||||||
| 
						 | 
					@ -528,6 +535,7 @@ int snd_pcm_mmap(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t **control,
 | 
				
			||||||
	snd_pcm_channel_info_t info;
 | 
						snd_pcm_channel_info_t info;
 | 
				
			||||||
	int err, fd, prot;
 | 
						int err, fd, prot;
 | 
				
			||||||
	void *caddr, *daddr;
 | 
						void *caddr, *daddr;
 | 
				
			||||||
 | 
						struct snd_pcm_chan *chan;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (control)
 | 
						if (control)
 | 
				
			||||||
		*control = NULL;
 | 
							*control = NULL;
 | 
				
			||||||
| 
						 | 
					@ -535,7 +543,8 @@ int snd_pcm_mmap(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t **control,
 | 
				
			||||||
		*buffer = NULL;
 | 
							*buffer = NULL;
 | 
				
			||||||
	if (!pcm || channel < 0 || channel > 1 || !control || !buffer)
 | 
						if (!pcm || channel < 0 || channel > 1 || !control || !buffer)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	fd = pcm->fd[channel];
 | 
						chan = &pcm->chan[channel];
 | 
				
			||||||
 | 
						fd = chan->fd;
 | 
				
			||||||
	if (fd < 0)
 | 
						if (fd < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	memset(&info, 0, sizeof(info));
 | 
						memset(&info, 0, sizeof(info));
 | 
				
			||||||
| 
						 | 
					@ -552,24 +561,26 @@ int snd_pcm_mmap(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t **control,
 | 
				
			||||||
		munmap(caddr, sizeof(snd_pcm_mmap_control_t));
 | 
							munmap(caddr, sizeof(snd_pcm_mmap_control_t));
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	*control = pcm->mmap_caddr[channel] = caddr;
 | 
						*control = chan->mmap_control = caddr;
 | 
				
			||||||
	*buffer = pcm->mmap_daddr[channel] = daddr;
 | 
						*buffer = chan->mmap_data = daddr;
 | 
				
			||||||
	pcm->mmap_size[channel] = info.mmap_size;
 | 
						chan->mmap_size = info.mmap_size;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_munmap(snd_pcm_t *pcm, int channel)
 | 
					int snd_pcm_munmap(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct snd_pcm_chan *chan;
 | 
				
			||||||
	if (!pcm || channel < 0 || channel > 1)
 | 
						if (!pcm || channel < 0 || channel > 1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (pcm->mmap_caddr[channel]) {
 | 
						chan = &pcm->chan[channel];
 | 
				
			||||||
		munmap(pcm->mmap_caddr[channel], sizeof(snd_pcm_mmap_control_t));
 | 
						if (chan->mmap_control) {
 | 
				
			||||||
		pcm->mmap_caddr[channel] = NULL;
 | 
							munmap(chan->mmap_control, sizeof(snd_pcm_mmap_control_t));
 | 
				
			||||||
 | 
							chan->mmap_control = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (pcm->mmap_daddr[channel]) {
 | 
						if (chan->mmap_data) {
 | 
				
			||||||
		munmap(pcm->mmap_daddr[channel], pcm->mmap_size[channel]);
 | 
							munmap(chan->mmap_data, chan->mmap_size);
 | 
				
			||||||
		pcm->mmap_daddr[channel] = NULL;
 | 
							chan->mmap_data = NULL;
 | 
				
			||||||
		pcm->mmap_size[channel] = 0;
 | 
							chan->mmap_size = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,27 +19,41 @@
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <pthread.h>
 | 
				
			||||||
#include "asoundlib.h"
 | 
					#include "asoundlib.h"
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 | 
					struct snd_pcm_plug {
 | 
				
			||||||
 | 
						snd_pcm_plugin_t *first;
 | 
				
			||||||
 | 
						snd_pcm_plugin_t *last;
 | 
				
			||||||
 | 
						void *alloc_ptr[2];
 | 
				
			||||||
 | 
						long alloc_size[2];
 | 
				
			||||||
 | 
						int alloc_lock[2];
 | 
				
			||||||
 | 
						snd_pcm_mmap_control_t *mmap_control;
 | 
				
			||||||
 | 
						char *mmap_data;
 | 
				
			||||||
 | 
						long mmap_size;
 | 
				
			||||||
 | 
						pthread_t thread;
 | 
				
			||||||
 | 
						int thread_stop;
 | 
				
			||||||
 | 
						int setup_is_valid;
 | 
				
			||||||
 | 
						snd_pcm_channel_setup_t setup;
 | 
				
			||||||
 | 
						int hwstatus;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct snd_pcm_chan {
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
						int setup_is_valid;
 | 
				
			||||||
 | 
						snd_pcm_channel_setup_t setup;
 | 
				
			||||||
 | 
						snd_pcm_mmap_control_t *mmap_control;
 | 
				
			||||||
 | 
						char *mmap_data;
 | 
				
			||||||
 | 
						long mmap_size;
 | 
				
			||||||
 | 
						struct snd_pcm_plug plug;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm {
 | 
					struct snd_pcm {
 | 
				
			||||||
	int card;
 | 
						int card;
 | 
				
			||||||
	int device;
 | 
						int device;
 | 
				
			||||||
	int mode;
 | 
						int mode;
 | 
				
			||||||
	int ver;
 | 
						int ver;
 | 
				
			||||||
	int fd[2];
 | 
						struct snd_pcm_chan chan[2];
 | 
				
			||||||
	int setup_is_valid[2];
 | 
					 | 
				
			||||||
	snd_pcm_channel_setup_t setup[2];
 | 
					 | 
				
			||||||
	snd_pcm_mmap_control_t *mmap_caddr[2];
 | 
					 | 
				
			||||||
	char *mmap_daddr[2];
 | 
					 | 
				
			||||||
	long mmap_size[2];
 | 
					 | 
				
			||||||
	snd_pcm_plugin_t *plugin_first[2];
 | 
					 | 
				
			||||||
	snd_pcm_plugin_t *plugin_last[2];
 | 
					 | 
				
			||||||
	void *plugin_alloc_ptr[4];
 | 
					 | 
				
			||||||
	long plugin_alloc_size[4];
 | 
					 | 
				
			||||||
	int plugin_alloc_lock[4];
 | 
					 | 
				
			||||||
	void *plugin_alloc_xptr[2];
 | 
					 | 
				
			||||||
	long plugin_alloc_xsize[2];
 | 
					 | 
				
			||||||
	int plugin_alloc_xchannel;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unsigned int snd_pcm_plugin_formats(unsigned int formats);
 | 
					unsigned int snd_pcm_plugin_formats(unsigned int formats);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,11 +26,11 @@
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <math.h>
 | 
					#include <math.h>
 | 
				
			||||||
#include <sys/uio.h>
 | 
					#include <sys/uio.h>
 | 
				
			||||||
 | 
					#include <sys/poll.h>
 | 
				
			||||||
#include "pcm_local.h"
 | 
					#include "pcm_local.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void *snd_pcm_plugin_buf_alloc(snd_pcm_t *pcm, size_t size);
 | 
					static void *snd_pcm_plugin_buf_alloc(snd_pcm_t *pcm, int channel, size_t size);
 | 
				
			||||||
static void snd_pcm_plugin_buf_free(snd_pcm_t *pcm, void *ptr);
 | 
					static void snd_pcm_plugin_buf_free(snd_pcm_t *pcm, int channel, void *ptr);
 | 
				
			||||||
static void *snd_pcm_plugin_ptr_alloc(snd_pcm_t *pcm, size_t size);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
snd_pcm_plugin_t *snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle,
 | 
					snd_pcm_plugin_t *snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle,
 | 
				
			||||||
				       const char *name,
 | 
									       const char *name,
 | 
				
			||||||
| 
						 | 
					@ -64,6 +64,8 @@ snd_pcm_plugin_t *snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle,
 | 
				
			||||||
	plugin->handle = handle;
 | 
						plugin->handle = handle;
 | 
				
			||||||
	plugin->voices = (snd_pcm_plugin_voice_t *)((char *)plugin + sizeof(*plugin));
 | 
						plugin->voices = (snd_pcm_plugin_voice_t *)((char *)plugin + sizeof(*plugin));
 | 
				
			||||||
	plugin->extra_data = (char *)plugin->voices + voices * sizeof(snd_pcm_plugin_voice_t);
 | 
						plugin->extra_data = (char *)plugin->voices + voices * sizeof(snd_pcm_plugin_voice_t);
 | 
				
			||||||
 | 
						plugin->src_voices = snd_pcm_plugin_src_voices;
 | 
				
			||||||
 | 
						plugin->dst_voices = snd_pcm_plugin_dst_voices;
 | 
				
			||||||
	return plugin;
 | 
						return plugin;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -82,29 +84,27 @@ int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin)
 | 
				
			||||||
int snd_pcm_plugin_clear(snd_pcm_t *pcm, int channel)
 | 
					int snd_pcm_plugin_clear(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_plugin_t *plugin, *plugin_next;
 | 
						snd_pcm_plugin_t *plugin, *plugin_next;
 | 
				
			||||||
 | 
						struct snd_pcm_plug *plug;
 | 
				
			||||||
	int idx;
 | 
						int idx;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	if (!pcm)
 | 
						if (!pcm)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	plugin = pcm->plugin_first[channel];
 | 
						plugin = pcm->chan[channel].plug.first;
 | 
				
			||||||
	pcm->plugin_first[channel] = NULL;
 | 
						pcm->chan[channel].plug.first = NULL;
 | 
				
			||||||
	pcm->plugin_last[channel] = NULL;
 | 
						pcm->chan[channel].plug.last = NULL;
 | 
				
			||||||
	while (plugin) {
 | 
						while (plugin) {
 | 
				
			||||||
		plugin_next = plugin->next;
 | 
							plugin_next = plugin->next;
 | 
				
			||||||
		snd_pcm_plugin_free(plugin);
 | 
							snd_pcm_plugin_free(plugin);
 | 
				
			||||||
		plugin = plugin_next;
 | 
							plugin = plugin_next;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (idx = 0; idx < 4; idx++) {
 | 
						plug = &pcm->chan[channel].plug;
 | 
				
			||||||
		if (pcm->plugin_alloc_ptr[idx])
 | 
						for (idx = 0; idx < 2; idx++) {
 | 
				
			||||||
			free(pcm->plugin_alloc_ptr[idx]);
 | 
							if (plug->alloc_ptr[idx])
 | 
				
			||||||
		pcm->plugin_alloc_ptr[idx] = 0;
 | 
								free(plug->alloc_ptr[idx]);
 | 
				
			||||||
		pcm->plugin_alloc_size[idx] = 0;
 | 
							plug->alloc_ptr[idx] = 0;
 | 
				
			||||||
		pcm->plugin_alloc_lock[idx] = 0;
 | 
							plug->alloc_size[idx] = 0;
 | 
				
			||||||
 | 
							plug->alloc_lock[idx] = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (pcm->plugin_alloc_xptr[channel])
 | 
					 | 
				
			||||||
		free(pcm->plugin_alloc_xptr[channel]);
 | 
					 | 
				
			||||||
	pcm->plugin_alloc_xptr[channel] = NULL;
 | 
					 | 
				
			||||||
	pcm->plugin_alloc_xsize[channel] = 0;
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,14 +112,14 @@ int snd_pcm_plugin_insert(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t *plugin)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!pcm || channel < 0 || channel > 1 || !plugin)
 | 
						if (!pcm || channel < 0 || channel > 1 || !plugin)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	plugin->next = pcm->plugin_first[channel];
 | 
						plugin->next = pcm->chan[channel].plug.first;
 | 
				
			||||||
	plugin->prev = NULL;
 | 
						plugin->prev = NULL;
 | 
				
			||||||
	if (pcm->plugin_first[channel]) {
 | 
						if (pcm->chan[channel].plug.first) {
 | 
				
			||||||
		pcm->plugin_first[channel]->prev = plugin;
 | 
							pcm->chan[channel].plug.first->prev = plugin;
 | 
				
			||||||
		pcm->plugin_first[channel] = plugin;
 | 
							pcm->chan[channel].plug.first = plugin;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		pcm->plugin_last[channel] =
 | 
							pcm->chan[channel].plug.last =
 | 
				
			||||||
		pcm->plugin_first[channel] = plugin;
 | 
							pcm->chan[channel].plug.first = plugin;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -129,13 +129,13 @@ int snd_pcm_plugin_append(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t *plugin)
 | 
				
			||||||
	if (!pcm || channel < 0 || channel > 1 || !plugin)
 | 
						if (!pcm || channel < 0 || channel > 1 || !plugin)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	plugin->next = NULL;
 | 
						plugin->next = NULL;
 | 
				
			||||||
	plugin->prev = pcm->plugin_last[channel];
 | 
						plugin->prev = pcm->chan[channel].plug.last;
 | 
				
			||||||
	if (pcm->plugin_last[channel]) {
 | 
						if (pcm->chan[channel].plug.last) {
 | 
				
			||||||
		pcm->plugin_last[channel]->next = plugin;
 | 
							pcm->chan[channel].plug.last->next = plugin;
 | 
				
			||||||
		pcm->plugin_last[channel] = plugin;
 | 
							pcm->chan[channel].plug.last = plugin;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		pcm->plugin_last[channel] =
 | 
							pcm->chan[channel].plug.last =
 | 
				
			||||||
		pcm->plugin_first[channel] = plugin;
 | 
							pcm->chan[channel].plug.first = plugin;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -149,9 +149,9 @@ int snd_pcm_plugin_remove_to(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t *plug
 | 
				
			||||||
	plugin1 = plugin;
 | 
						plugin1 = plugin;
 | 
				
			||||||
	while (plugin1->prev)
 | 
						while (plugin1->prev)
 | 
				
			||||||
		plugin1 = plugin1->prev;
 | 
							plugin1 = plugin1->prev;
 | 
				
			||||||
	if (pcm->plugin_first[channel] != plugin1)
 | 
						if (pcm->chan[channel].plug.first != plugin1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	pcm->plugin_first[channel] = plugin;
 | 
						pcm->chan[channel].plug.first = plugin;
 | 
				
			||||||
	plugin1 = plugin->prev;
 | 
						plugin1 = plugin->prev;
 | 
				
			||||||
	plugin->prev = NULL;
 | 
						plugin->prev = NULL;
 | 
				
			||||||
	while (plugin1) {
 | 
						while (plugin1) {
 | 
				
			||||||
| 
						 | 
					@ -166,7 +166,7 @@ int snd_pcm_plugin_remove_first(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_plugin_t *plugin;
 | 
						snd_pcm_plugin_t *plugin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	plugin = pcm->plugin_first[channel];
 | 
						plugin = pcm->chan[channel].plug.first;
 | 
				
			||||||
	if (plugin->next) {
 | 
						if (plugin->next) {
 | 
				
			||||||
		plugin = plugin->next;
 | 
							plugin = plugin->next;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -179,14 +179,14 @@ snd_pcm_plugin_t *snd_pcm_plugin_first(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!pcm || channel < 0 || channel > 1)
 | 
						if (!pcm || channel < 0 || channel > 1)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	return pcm->plugin_first[channel];
 | 
						return pcm->chan[channel].plug.first;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
snd_pcm_plugin_t *snd_pcm_plugin_last(snd_pcm_t *pcm, int channel)
 | 
					snd_pcm_plugin_t *snd_pcm_plugin_last(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!pcm || channel < 0 || channel > 1)
 | 
						if (!pcm || channel < 0 || channel > 1)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	return pcm->plugin_last[channel];
 | 
						return pcm->chan[channel].plug.last;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -223,7 +223,16 @@ int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
 | 
				
			||||||
	info->formats = snd_pcm_plugin_formats(info->formats);
 | 
						info->formats = snd_pcm_plugin_formats(info->formats);
 | 
				
			||||||
	info->min_rate = 4000;
 | 
						info->min_rate = 4000;
 | 
				
			||||||
	info->max_rate = 192000;
 | 
						info->max_rate = 192000;
 | 
				
			||||||
	info->rates = SND_PCM_RATE_8000_48000;
 | 
						info->min_voices = 1;
 | 
				
			||||||
 | 
						info->max_voices = 32;
 | 
				
			||||||
 | 
						info->rates = SND_PCM_RATE_CONTINUOUS;
 | 
				
			||||||
 | 
						info->buffer_size = snd_pcm_plugin_client_size(pcm, info->channel, info->buffer_size);
 | 
				
			||||||
 | 
						info->min_fragment_size = snd_pcm_plugin_client_size(pcm, info->channel, info->min_fragment_size);
 | 
				
			||||||
 | 
						info->max_fragment_size = snd_pcm_plugin_client_size(pcm, info->channel, info->max_fragment_size);
 | 
				
			||||||
 | 
						info->fragment_align = snd_pcm_plugin_client_size(pcm, info->channel, info->fragment_align);
 | 
				
			||||||
 | 
						info->fifo_size = snd_pcm_plugin_client_size(pcm, info->channel, info->fifo_size);
 | 
				
			||||||
 | 
						info->transfer_block_size = snd_pcm_plugin_client_size(pcm, info->channel, info->transfer_block_size);
 | 
				
			||||||
 | 
						info->mmap_size = snd_pcm_plugin_client_size(pcm, info->channel, info->mmap_size);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -233,7 +242,7 @@ static int snd_pcm_plugin_action(snd_pcm_t *pcm, int channel, int action,
 | 
				
			||||||
	snd_pcm_plugin_t *plugin;
 | 
						snd_pcm_plugin_t *plugin;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	plugin = pcm->plugin_first[channel];
 | 
						plugin = pcm->chan[channel].plug.first;
 | 
				
			||||||
	while (plugin) {
 | 
						while (plugin) {
 | 
				
			||||||
		if (plugin->action) {
 | 
							if (plugin->action) {
 | 
				
			||||||
			if ((err = plugin->action(plugin, action, data))<0)
 | 
								if ((err = plugin->action(plugin, action, data))<0)
 | 
				
			||||||
| 
						 | 
					@ -249,11 +258,16 @@ int snd_pcm_plugin_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
 | 
				
			||||||
	snd_pcm_channel_params_t hwparams, params1;
 | 
						snd_pcm_channel_params_t hwparams, params1;
 | 
				
			||||||
	snd_pcm_channel_info_t hwinfo;
 | 
						snd_pcm_channel_info_t hwinfo;
 | 
				
			||||||
	snd_pcm_plugin_t *plugin;
 | 
						snd_pcm_plugin_t *plugin;
 | 
				
			||||||
 | 
						struct snd_pcm_plug *plug;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	if (!pcm || !params || params->channel < 0 || params->channel > 1)
 | 
						if (!pcm || !params || params->channel < 0 || params->channel > 1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						plug = &pcm->chan[params->channel].plug;
 | 
				
			||||||
 | 
						if (plug->mmap_data)
 | 
				
			||||||
 | 
							return -EBADFD;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 *  try to decide, if a conversion is required
 | 
						 *  try to decide, if a conversion is required
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
| 
						 | 
					@ -276,6 +290,9 @@ int snd_pcm_plugin_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
 | 
				
			||||||
	if ((err = snd_pcm_plugin_format(pcm, ¶ms1, &hwparams, &hwinfo)) < 0)
 | 
						if ((err = snd_pcm_plugin_format(pcm, ¶ms1, &hwparams, &hwinfo)) < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (snd_pcm_plugin_first(pcm, params->channel) == NULL)
 | 
				
			||||||
 | 
							return snd_pcm_channel_params(pcm, params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 *  I/O plugins
 | 
						 *  I/O plugins
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
| 
						 | 
					@ -323,6 +340,12 @@ int snd_pcm_plugin_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
 | 
				
			||||||
	err = snd_pcm_channel_params(pcm, &hwparams);
 | 
						err = snd_pcm_channel_params(pcm, &hwparams);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						plug->setup_is_valid = 0;
 | 
				
			||||||
 | 
						memset(&plug->setup, 0, sizeof(snd_pcm_channel_setup_t));
 | 
				
			||||||
 | 
						plug->setup.channel = params->channel;
 | 
				
			||||||
 | 
						if ((err = snd_pcm_plugin_setup(pcm, &plug->setup))<0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
	err = snd_pcm_plugin_action(pcm, hwparams.channel, INIT, (long)&hwparams);
 | 
						err = snd_pcm_plugin_action(pcm, hwparams.channel, INIT, (long)&hwparams);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
| 
						 | 
					@ -332,9 +355,17 @@ int snd_pcm_plugin_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
 | 
				
			||||||
int snd_pcm_plugin_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
 | 
					int snd_pcm_plugin_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
						struct snd_pcm_plug *plug;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	if (!pcm || !setup || setup->channel < 0 || setup->channel > 1)
 | 
						if (!pcm || !setup || setup->channel < 0 || setup->channel > 1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						plug = &pcm->chan[setup->channel].plug;
 | 
				
			||||||
 | 
						if (plug->first == NULL)
 | 
				
			||||||
 | 
							return snd_pcm_channel_setup(pcm, setup);
 | 
				
			||||||
 | 
						if (plug->setup_is_valid) {
 | 
				
			||||||
 | 
							memcpy(setup, &plug->setup, sizeof(*setup));
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	err = snd_pcm_channel_setup(pcm, setup);
 | 
						err = snd_pcm_channel_setup(pcm, setup);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
| 
						 | 
					@ -349,12 +380,17 @@ int snd_pcm_plugin_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (setup->channel == SND_PCM_CHANNEL_PLAYBACK)
 | 
				
			||||||
 | 
							setup->format = plug->first->src_format;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							setup->format = plug->last->dst_format;
 | 
				
			||||||
 | 
						memcpy(&plug->setup, setup, sizeof(*setup));
 | 
				
			||||||
 | 
						plug->setup_is_valid = 1;
 | 
				
			||||||
	return 0;	
 | 
						return 0;	
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_channel_status_t *status)
 | 
					int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_channel_status_t *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	double ratio;
 | 
					 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	if (!pcm || !status || status->channel < 0 || status->channel > 1)
 | 
						if (!pcm || !status || status->channel < 0 || status->channel > 1)
 | 
				
			||||||
| 
						 | 
					@ -362,9 +398,6 @@ int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_channel_status_t *status)
 | 
				
			||||||
	err = snd_pcm_channel_status(pcm, status);
 | 
						err = snd_pcm_channel_status(pcm, status);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	ratio = snd_pcm_plugin_transfer_ratio(pcm, status->channel);
 | 
					 | 
				
			||||||
	if (ratio <= 0)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	/* FIXME: scount may overflow */
 | 
						/* FIXME: scount may overflow */
 | 
				
			||||||
	status->scount = snd_pcm_plugin_client_size(pcm, status->channel, status->scount);
 | 
						status->scount = snd_pcm_plugin_client_size(pcm, status->channel, status->scount);
 | 
				
			||||||
	status->count = snd_pcm_plugin_client_size(pcm, status->channel, status->count);
 | 
						status->count = snd_pcm_plugin_client_size(pcm, status->channel, status->count);
 | 
				
			||||||
| 
						 | 
					@ -372,13 +405,100 @@ int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_channel_status_t *status)
 | 
				
			||||||
	return 0;	
 | 
						return 0;	
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void mmap_clear(struct snd_pcm_plug *plug)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int idx;
 | 
				
			||||||
 | 
						snd_pcm_mmap_fragment_t *f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						f = plug->mmap_control->fragments;
 | 
				
			||||||
 | 
						for (idx = 0; idx < plug->setup.buf.block.frags; idx++) {
 | 
				
			||||||
 | 
							f->data = 0;
 | 
				
			||||||
 | 
							f->io = 0;
 | 
				
			||||||
 | 
							f->res[0] = 0;
 | 
				
			||||||
 | 
							f->res[1] = 0;
 | 
				
			||||||
 | 
							f++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						plug->mmap_control->status.frag_io = 0;
 | 
				
			||||||
 | 
						plug->mmap_control->status.block = 0;
 | 
				
			||||||
 | 
						plug->mmap_control->status.expblock = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void snd_pcm_plugin_status_change(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct snd_pcm_chan *chan;
 | 
				
			||||||
 | 
						struct snd_pcm_plug *plug;
 | 
				
			||||||
 | 
						snd_pcm_channel_status_t status;
 | 
				
			||||||
 | 
						int newstatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						chan = &pcm->chan[channel];
 | 
				
			||||||
 | 
						plug = &chan->plug;
 | 
				
			||||||
 | 
						if (!plug->mmap_data)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						if (chan->mmap_control) {
 | 
				
			||||||
 | 
							newstatus = chan->mmap_control->status.status;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							status.channel = channel;
 | 
				
			||||||
 | 
							if (snd_pcm_channel_status(pcm, &status) < 0)
 | 
				
			||||||
 | 
								newstatus = SND_PCM_STATUS_NOTREADY;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								newstatus = status.status;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (plug->mmap_control->status.status == SND_PCM_STATUS_RUNNING &&
 | 
				
			||||||
 | 
						    newstatus != SND_PCM_STATUS_RUNNING) {
 | 
				
			||||||
 | 
							mmap_clear(plug);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						plug->mmap_control->status.status = newstatus;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_plugin_prepare(snd_pcm_t *pcm, int channel)
 | 
					int snd_pcm_plugin_prepare(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((err = snd_pcm_plugin_action(pcm, channel, PREPARE, 0))<0)
 | 
						if ((err = snd_pcm_plugin_action(pcm, channel, PREPARE, 0))<0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	return snd_pcm_channel_prepare(pcm, channel);
 | 
						if ((err = snd_pcm_channel_prepare(pcm, channel)) < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						snd_pcm_plugin_status_change(pcm, channel);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int snd_pcm_plugin_go(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct snd_pcm_chan *chan;
 | 
				
			||||||
 | 
						struct snd_pcm_plug *plug;
 | 
				
			||||||
 | 
						if (!pcm || channel < 0 || channel > 1)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						chan = &pcm->chan[channel];
 | 
				
			||||||
 | 
						plug = &chan->plug;
 | 
				
			||||||
 | 
						if (plug->first == NULL)
 | 
				
			||||||
 | 
							return snd_pcm_channel_go(pcm, channel);
 | 
				
			||||||
 | 
						if (plug->mmap_control) {
 | 
				
			||||||
 | 
							if (plug->mmap_control->status.status != SND_PCM_STATUS_PREPARED)
 | 
				
			||||||
 | 
								return -EBADFD;
 | 
				
			||||||
 | 
							if (channel == SND_PCM_CHANNEL_PLAYBACK) {
 | 
				
			||||||
 | 
								if (!plug->mmap_control->fragments[0].data)
 | 
				
			||||||
 | 
									return -EIO;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (plug->mmap_control->fragments[0].data)
 | 
				
			||||||
 | 
									return -EIO;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							plug->mmap_control->status.status = SND_PCM_STATUS_RUNNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int snd_pcm_plugin_sync_go(snd_pcm_t *pcm, snd_pcm_sync_t *sync)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						if (!pcm || !sync)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						if (snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK) ||
 | 
				
			||||||
 | 
						    snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_CAPTURE)) {
 | 
				
			||||||
 | 
							if ((err = snd_pcm_plugin_go(pcm, SND_PCM_CHANNEL_PLAYBACK)) < 0)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							return snd_pcm_plugin_go(pcm, SND_PCM_CHANNEL_CAPTURE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return snd_pcm_sync_go(pcm, sync);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_plugin_playback_drain(snd_pcm_t *pcm)
 | 
					int snd_pcm_plugin_playback_drain(snd_pcm_t *pcm)
 | 
				
			||||||
| 
						 | 
					@ -387,7 +507,10 @@ int snd_pcm_plugin_playback_drain(snd_pcm_t *pcm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((err = snd_pcm_plugin_action(pcm, SND_PCM_CHANNEL_PLAYBACK, DRAIN, 0))<0)
 | 
						if ((err = snd_pcm_plugin_action(pcm, SND_PCM_CHANNEL_PLAYBACK, DRAIN, 0))<0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	return snd_pcm_playback_drain(pcm);
 | 
						if ((err = snd_pcm_playback_drain(pcm)) < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						snd_pcm_plugin_status_change(pcm, SND_PCM_CHANNEL_PLAYBACK);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_plugin_flush(snd_pcm_t *pcm, int channel)
 | 
					int snd_pcm_plugin_flush(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
| 
						 | 
					@ -397,73 +520,75 @@ int snd_pcm_plugin_flush(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
	pdprintf("flush\n");
 | 
						pdprintf("flush\n");
 | 
				
			||||||
	if ((err = snd_pcm_plugin_action(pcm, channel, FLUSH, 0))<0)
 | 
						if ((err = snd_pcm_plugin_action(pcm, channel, FLUSH, 0))<0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	return snd_pcm_channel_flush(pcm, channel);
 | 
						if ((err = snd_pcm_channel_flush(pcm, channel)) < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						snd_pcm_plugin_status_change(pcm, channel);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int snd_pcm_plugin_pause(snd_pcm_t *pcm, int enable)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if ((err = snd_pcm_playback_pause(pcm, enable)) < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						snd_pcm_plugin_status_change(pcm, SND_PCM_CHANNEL_PLAYBACK);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ssize_t snd_pcm_plugin_transfer_size(snd_pcm_t *pcm, int channel)
 | 
					ssize_t snd_pcm_plugin_transfer_size(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ssize_t result;
 | 
						struct snd_pcm_plug *plug;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((result = snd_pcm_transfer_size(pcm, channel)) < 0)
 | 
					 | 
				
			||||||
		return result;
 | 
					 | 
				
			||||||
	return snd_pcm_plugin_client_size(pcm, channel, result);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int snd_pcm_plugin_pointer(snd_pcm_t *pcm, int channel, void **ptr, size_t *size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_plugin_t *plugin = NULL;
 | 
					 | 
				
			||||||
	snd_pcm_plugin_voice_t *voices;
 | 
					 | 
				
			||||||
	size_t samples;
 | 
					 | 
				
			||||||
	int width;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!ptr || !size || *size < 1)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	*ptr = NULL;
 | 
					 | 
				
			||||||
	if (!pcm || channel < 0 || channel > 1)
 | 
						if (!pcm || channel < 0 || channel > 1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if ((*size = snd_pcm_plugin_transfer_size(pcm, channel)) < 0)
 | 
						plug = &pcm->chan[channel].plug;
 | 
				
			||||||
		return *size;
 | 
						if (plug->first == NULL)
 | 
				
			||||||
	if (channel == SND_PCM_CHANNEL_PLAYBACK && plugin->src_voices) {
 | 
							return snd_pcm_plugin_transfer_size(pcm, channel);
 | 
				
			||||||
		plugin = pcm->plugin_first[channel];
 | 
						if (!plug->setup_is_valid)
 | 
				
			||||||
		if (!plugin)
 | 
							return -EBADFD;
 | 
				
			||||||
			goto __skip;
 | 
						if (plug->setup.mode != SND_PCM_MODE_BLOCK)
 | 
				
			||||||
		if (!plugin->src_format.interleave)
 | 
							return -EBADFD;
 | 
				
			||||||
			goto __skip;
 | 
						return plug->setup.buf.block.frag_size;
 | 
				
			||||||
		if ((width = snd_pcm_format_width(plugin->src_format.format)) < 0)
 | 
					}
 | 
				
			||||||
			return width;
 | 
					
 | 
				
			||||||
		samples = *size * width;
 | 
					int snd_pcm_plugin_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t *setup)
 | 
				
			||||||
		if ((samples % (plugin->src_format.voices * 8)) != 0)
 | 
					{
 | 
				
			||||||
			return -EINVAL;
 | 
						int voice, width, size;
 | 
				
			||||||
		samples /= (plugin->src_format.voices * 8);
 | 
						struct snd_pcm_plug* plug;
 | 
				
			||||||
		pcm->plugin_alloc_xchannel = SND_PCM_CHANNEL_PLAYBACK;
 | 
						
 | 
				
			||||||
		if (plugin->src_voices(plugin, &voices, samples,
 | 
						if (!pcm || !setup)
 | 
				
			||||||
				       snd_pcm_plugin_ptr_alloc) < 0)
 | 
							return -EINVAL;
 | 
				
			||||||
			goto __skip;
 | 
						if (channel < 0 || channel > 1)
 | 
				
			||||||
		*ptr = voices->addr;
 | 
							return -EINVAL;
 | 
				
			||||||
		return 0;
 | 
						voice = setup->voice;
 | 
				
			||||||
	} else if (channel == SND_PCM_CHANNEL_CAPTURE && plugin->dst_voices) {
 | 
						memset(setup, 0, sizeof(*setup));
 | 
				
			||||||
		plugin = pcm->plugin_last[channel];
 | 
						setup->voice = voice;
 | 
				
			||||||
		if (!plugin)
 | 
						if (voice < 0)
 | 
				
			||||||
			goto __skip;
 | 
							return -EINVAL;
 | 
				
			||||||
		if (plugin->dst_format.interleave)
 | 
						plug = &pcm->chan[channel].plug;
 | 
				
			||||||
			goto __skip;
 | 
						if (plug->first == NULL)
 | 
				
			||||||
		if ((width = snd_pcm_format_width(plugin->dst_format.format)) < 0)
 | 
							return snd_pcm_voice_setup(pcm, channel, setup);
 | 
				
			||||||
			return width;
 | 
						if (!plug->mmap_control) {
 | 
				
			||||||
		samples = *size * width;
 | 
							setup->addr = -1;
 | 
				
			||||||
		if ((samples % (plugin->dst_format.voices * 8)) != 0)
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		samples /= (plugin->src_format.voices * 8);
 | 
					 | 
				
			||||||
		pcm->plugin_alloc_xchannel = SND_PCM_CHANNEL_CAPTURE;
 | 
					 | 
				
			||||||
		if (plugin->dst_voices(plugin, &voices, *size,
 | 
					 | 
				
			||||||
				       snd_pcm_plugin_ptr_alloc) < 0)
 | 
					 | 
				
			||||||
			goto __skip;
 | 
					 | 
				
			||||||
		*ptr = voices->addr;
 | 
					 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
      __skip:
 | 
						if (voice >= plug->setup.format.voices)
 | 
				
			||||||
      	*ptr = snd_pcm_plugin_ptr_alloc(pcm, *size);
 | 
							return -EINVAL;
 | 
				
			||||||
      	if (*ptr == NULL)
 | 
					
 | 
				
			||||||
      		return -ENOMEM;
 | 
						width = snd_pcm_format_physical_width(plug->setup.format.format);
 | 
				
			||||||
 | 
					        if (width < 0)
 | 
				
			||||||
 | 
					                return width;
 | 
				
			||||||
 | 
						size = plug->mmap_size;
 | 
				
			||||||
 | 
						if (plug->setup.format.interleave) {
 | 
				
			||||||
 | 
					                setup->addr = 0;
 | 
				
			||||||
 | 
					                setup->first = voice * width;
 | 
				
			||||||
 | 
					                setup->step = plug->setup.format.voices * width;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					                size /= plug->setup.format.voices;
 | 
				
			||||||
 | 
					                setup->addr = setup->voice * size;
 | 
				
			||||||
 | 
					                setup->first = 0;
 | 
				
			||||||
 | 
					                setup->step = width;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -528,7 +653,7 @@ static ssize_t snd_pcm_plugin_writev1(snd_pcm_t *pcm, const struct iovec *vector
 | 
				
			||||||
	ssize_t size;
 | 
						ssize_t size;
 | 
				
			||||||
	int idx, err;
 | 
						int idx, err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	plugin = pcm->plugin_first[SND_PCM_CHANNEL_PLAYBACK];
 | 
						plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK);
 | 
				
			||||||
	if ((err = snd_pcm_plugin_load_src_vector(plugin, &src_voices, vector, count)) < 0)
 | 
						if ((err = snd_pcm_plugin_load_src_vector(plugin, &src_voices, vector, count)) < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	size = 0;
 | 
						size = 0;
 | 
				
			||||||
| 
						 | 
					@ -542,33 +667,26 @@ static ssize_t snd_pcm_plugin_writev1(snd_pcm_t *pcm, const struct iovec *vector
 | 
				
			||||||
			ssize_t samples1 = samples;
 | 
								ssize_t samples1 = samples;
 | 
				
			||||||
			if (plugin->dst_samples)
 | 
								if (plugin->dst_samples)
 | 
				
			||||||
				samples1 = plugin->dst_samples(plugin, samples);
 | 
									samples1 = plugin->dst_samples(plugin, samples);
 | 
				
			||||||
			if (next->src_voices) {
 | 
								if ((err = next->src_voices(next, &dst_voices, samples1)) < 0) {
 | 
				
			||||||
				if ((err = next->src_voices(next, &dst_voices, samples1, snd_pcm_plugin_buf_alloc)) < 0) {
 | 
									snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_PLAYBACK, src_voices->aptr);
 | 
				
			||||||
					snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
 | 
									return err;
 | 
				
			||||||
					return err;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				if ((err = snd_pcm_plugin_src_voices(next, &dst_voices, samples1)) < 0) {
 | 
					 | 
				
			||||||
					snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
 | 
					 | 
				
			||||||
					return err;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			dst_voices = NULL;
 | 
								dst_voices = NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		pdprintf("write plugin: %s, %i\n", plugin->name, samples);
 | 
							pdprintf("write plugin: %s, %i\n", plugin->name, samples);
 | 
				
			||||||
		if ((samples = plugin->transfer(plugin, src_voices, dst_voices, samples)) < 0) {
 | 
							if ((samples = plugin->transfer(plugin, src_voices, dst_voices, samples)) < 0) {
 | 
				
			||||||
			snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
 | 
								snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_PLAYBACK, src_voices->aptr);
 | 
				
			||||||
			if (dst_voices)
 | 
								if (dst_voices)
 | 
				
			||||||
				snd_pcm_plugin_buf_free(pcm, dst_voices->aptr);
 | 
									snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_PLAYBACK, dst_voices->aptr);
 | 
				
			||||||
			return samples;
 | 
								return samples;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
 | 
							snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_PLAYBACK, src_voices->aptr);
 | 
				
			||||||
		plugin = plugin->next;
 | 
							plugin = plugin->next;
 | 
				
			||||||
		src_voices = dst_voices;
 | 
							src_voices = dst_voices;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	samples = snd_pcm_plugin_client_samples(pcm, SND_PCM_CHANNEL_PLAYBACK, samples);
 | 
						samples = snd_pcm_plugin_client_samples(pcm, SND_PCM_CHANNEL_PLAYBACK, samples);
 | 
				
			||||||
	size = snd_pcm_plugin_src_samples_to_size(pcm->plugin_first[SND_PCM_CHANNEL_PLAYBACK], samples);
 | 
						size = snd_pcm_plugin_src_samples_to_size(snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK), samples);
 | 
				
			||||||
	if (size < 0)
 | 
						if (size < 0)
 | 
				
			||||||
		return size;
 | 
							return size;
 | 
				
			||||||
	pdprintf("writev result = %i\n", size);
 | 
						pdprintf("writev result = %i\n", size);
 | 
				
			||||||
| 
						 | 
					@ -582,7 +700,7 @@ ssize_t snd_pcm_plugin_writev(snd_pcm_t *pcm, const struct iovec *vector, int co
 | 
				
			||||||
	int size = 0;
 | 
						int size = 0;
 | 
				
			||||||
	if (vector == NULL)
 | 
						if (vector == NULL)
 | 
				
			||||||
		return -EFAULT;
 | 
							return -EFAULT;
 | 
				
			||||||
	plugin = pcm->plugin_first[SND_PCM_CHANNEL_PLAYBACK];
 | 
						plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK);
 | 
				
			||||||
	if (plugin == NULL)
 | 
						if (plugin == NULL)
 | 
				
			||||||
		return snd_pcm_readv(pcm, vector, count);
 | 
							return snd_pcm_readv(pcm, vector, count);
 | 
				
			||||||
	voices = plugin->src_format.voices;
 | 
						voices = plugin->src_format.voices;
 | 
				
			||||||
| 
						 | 
					@ -621,50 +739,42 @@ static ssize_t snd_pcm_plugin_readv1(snd_pcm_t *pcm, const struct iovec *vector,
 | 
				
			||||||
	ssize_t size;
 | 
						ssize_t size;
 | 
				
			||||||
	int idx, err;
 | 
						int idx, err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	plugin = pcm->plugin_first[SND_PCM_CHANNEL_CAPTURE];
 | 
						plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_CAPTURE);
 | 
				
			||||||
	size = 0;
 | 
						size = 0;
 | 
				
			||||||
	for (idx = 0; idx < count; idx++)
 | 
						for (idx = 0; idx < count; idx++)
 | 
				
			||||||
		size += vector[idx].iov_len;
 | 
							size += vector[idx].iov_len;
 | 
				
			||||||
	if (size < 0)
 | 
						if (size < 0)
 | 
				
			||||||
		return size;
 | 
							return size;
 | 
				
			||||||
	samples = snd_pcm_plugin_dst_size_to_samples(pcm->plugin_last[SND_PCM_CHANNEL_CAPTURE], size);
 | 
						samples = snd_pcm_plugin_dst_size_to_samples(snd_pcm_plugin_last(pcm, SND_PCM_CHANNEL_CAPTURE), size);
 | 
				
			||||||
	samples = snd_pcm_plugin_hardware_samples(pcm, SND_PCM_CHANNEL_CAPTURE, samples);
 | 
						samples = snd_pcm_plugin_hardware_samples(pcm, SND_PCM_CHANNEL_CAPTURE, samples);
 | 
				
			||||||
	while (plugin && samples > 0) {
 | 
						while (plugin && samples > 0) {
 | 
				
			||||||
		if ((next = plugin->next) != NULL) {
 | 
							if ((next = plugin->next) != NULL) {
 | 
				
			||||||
			if (plugin->dst_voices) {
 | 
								if ((err = plugin->dst_voices(plugin, &dst_voices, samples)) < 0) {
 | 
				
			||||||
				if ((err = plugin->dst_voices(plugin, &dst_voices, samples, snd_pcm_plugin_buf_alloc)) < 0) {
 | 
									if (src_voices)
 | 
				
			||||||
					if (src_voices)
 | 
										snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_CAPTURE, src_voices->aptr);
 | 
				
			||||||
						snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
 | 
									return err;
 | 
				
			||||||
					return err;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				if ((err = snd_pcm_plugin_dst_voices(plugin, &dst_voices, samples)) < 0) {
 | 
					 | 
				
			||||||
					if (src_voices)
 | 
					 | 
				
			||||||
						snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
 | 
					 | 
				
			||||||
					return err;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			if ((err = snd_pcm_plugin_load_dst_vector(plugin, &dst_voices, vector, count)) < 0) {
 | 
								if ((err = snd_pcm_plugin_load_dst_vector(plugin, &dst_voices, vector, count)) < 0) {
 | 
				
			||||||
				if (src_voices)
 | 
									if (src_voices)
 | 
				
			||||||
					snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
 | 
										snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_CAPTURE, src_voices->aptr);
 | 
				
			||||||
				return err;
 | 
									return err;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		pdprintf("read plugin: %s, %i\n", plugin->name, samples);
 | 
							pdprintf("read plugin: %s, %i\n", plugin->name, samples);
 | 
				
			||||||
		if ((samples = plugin->transfer(plugin, src_voices, dst_voices, samples)) < 0) {
 | 
							if ((samples = plugin->transfer(plugin, src_voices, dst_voices, samples)) < 0) {
 | 
				
			||||||
			if (src_voices)
 | 
								if (src_voices)
 | 
				
			||||||
				snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
 | 
									snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_CAPTURE, src_voices->aptr);
 | 
				
			||||||
			snd_pcm_plugin_buf_free(pcm, dst_voices->aptr);
 | 
								snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_CAPTURE, dst_voices->aptr);
 | 
				
			||||||
			return samples;
 | 
								return samples;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (src_voices)
 | 
							if (src_voices)
 | 
				
			||||||
			snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
 | 
								snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_CAPTURE, src_voices->aptr);
 | 
				
			||||||
		plugin = plugin->next;
 | 
							plugin = plugin->next;
 | 
				
			||||||
		src_voices = dst_voices;
 | 
							src_voices = dst_voices;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	snd_pcm_plugin_buf_free(pcm, dst_voices->aptr);
 | 
						snd_pcm_plugin_buf_free(pcm, SND_PCM_CHANNEL_CAPTURE, dst_voices->aptr);
 | 
				
			||||||
	size = snd_pcm_plugin_dst_samples_to_size(pcm->plugin_last[SND_PCM_CHANNEL_CAPTURE], samples);
 | 
						size = snd_pcm_plugin_dst_samples_to_size(snd_pcm_plugin_last(pcm, SND_PCM_CHANNEL_CAPTURE), samples);
 | 
				
			||||||
	pdprintf("readv result = %i\n", size);
 | 
						pdprintf("readv result = %i\n", size);
 | 
				
			||||||
	return size;
 | 
						return size;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -676,7 +786,7 @@ ssize_t snd_pcm_plugin_readv(snd_pcm_t *pcm, const struct iovec *vector, int cou
 | 
				
			||||||
	int size = 0;
 | 
						int size = 0;
 | 
				
			||||||
	if (vector == NULL)
 | 
						if (vector == NULL)
 | 
				
			||||||
		return -EFAULT;
 | 
							return -EFAULT;
 | 
				
			||||||
	plugin = pcm->plugin_last[SND_PCM_CHANNEL_CAPTURE];
 | 
						plugin = snd_pcm_plugin_last(pcm, SND_PCM_CHANNEL_CAPTURE);
 | 
				
			||||||
	if (plugin == NULL)
 | 
						if (plugin == NULL)
 | 
				
			||||||
		return snd_pcm_readv(pcm, vector, count);
 | 
							return snd_pcm_readv(pcm, vector, count);
 | 
				
			||||||
	voices = plugin->dst_format.voices;
 | 
						voices = plugin->dst_format.voices;
 | 
				
			||||||
| 
						 | 
					@ -712,7 +822,7 @@ ssize_t snd_pcm_plugin_write(snd_pcm_t *pcm, const void *buffer, size_t count)
 | 
				
			||||||
	snd_pcm_plugin_t *plugin;
 | 
						snd_pcm_plugin_t *plugin;
 | 
				
			||||||
	int voices;
 | 
						int voices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((plugin = pcm->plugin_first[SND_PCM_CHANNEL_PLAYBACK]) == NULL)
 | 
						if ((plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK)) == NULL)
 | 
				
			||||||
		return snd_pcm_write(pcm, buffer, count);
 | 
							return snd_pcm_write(pcm, buffer, count);
 | 
				
			||||||
	voices = plugin->src_format.voices;
 | 
						voices = plugin->src_format.voices;
 | 
				
			||||||
	if (count % voices != 0)
 | 
						if (count % voices != 0)
 | 
				
			||||||
| 
						 | 
					@ -739,7 +849,7 @@ ssize_t snd_pcm_plugin_read(snd_pcm_t *pcm, void *buffer, size_t count)
 | 
				
			||||||
	snd_pcm_plugin_t *plugin;
 | 
						snd_pcm_plugin_t *plugin;
 | 
				
			||||||
	int voices;
 | 
						int voices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((plugin = pcm->plugin_last[SND_PCM_CHANNEL_CAPTURE]) == NULL)
 | 
						if ((plugin = snd_pcm_plugin_last(pcm, SND_PCM_CHANNEL_CAPTURE)) == NULL)
 | 
				
			||||||
		return snd_pcm_read(pcm, buffer, count);
 | 
							return snd_pcm_read(pcm, buffer, count);
 | 
				
			||||||
	voices = plugin->dst_format.voices;
 | 
						voices = plugin->dst_format.voices;
 | 
				
			||||||
	if (count % voices != 0)
 | 
						if (count % voices != 0)
 | 
				
			||||||
| 
						 | 
					@ -765,82 +875,69 @@ ssize_t snd_pcm_plugin_read(snd_pcm_t *pcm, void *buffer, size_t count)
 | 
				
			||||||
 *  Plugin helpers
 | 
					 *  Plugin helpers
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void *snd_pcm_plugin_buf_alloc(snd_pcm_t *pcm, size_t size)
 | 
					static void *snd_pcm_plugin_buf_alloc(snd_pcm_t *pcm, int channel, size_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int idx;
 | 
						int idx;
 | 
				
			||||||
	void *ptr;
 | 
						void *ptr;
 | 
				
			||||||
 | 
						struct snd_pcm_plug *plug;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pcm == NULL || size <= 0)
 | 
						if (pcm == NULL || size <= 0)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	for (idx = 0; idx < 4; idx++) {
 | 
						plug = &pcm->chan[channel].plug;
 | 
				
			||||||
		if (pcm->plugin_alloc_lock[idx])
 | 
						for (idx = 0; idx < 2; idx++) {
 | 
				
			||||||
 | 
							if (plug->alloc_lock[idx])
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (pcm->plugin_alloc_ptr[idx] == NULL)
 | 
							if (plug->alloc_ptr[idx] == NULL)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (pcm->plugin_alloc_size[idx] >= size) {
 | 
							if (plug->alloc_size[idx] >= size) {
 | 
				
			||||||
			pcm->plugin_alloc_lock[idx] = 1;
 | 
								plug->alloc_lock[idx] = 1;
 | 
				
			||||||
			return pcm->plugin_alloc_ptr[idx];
 | 
								return plug->alloc_ptr[idx];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (idx = 0; idx < 4; idx++) {
 | 
						for (idx = 0; idx < 2; idx++) {
 | 
				
			||||||
		if (pcm->plugin_alloc_lock[idx])
 | 
							if (plug->alloc_lock[idx])
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (pcm->plugin_alloc_ptr[idx] == NULL)
 | 
							if (plug->alloc_ptr[idx] == NULL)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		ptr = realloc(pcm->plugin_alloc_ptr[idx], size);
 | 
							ptr = realloc(plug->alloc_ptr[idx], size);
 | 
				
			||||||
		if (ptr == NULL)
 | 
							if (ptr == NULL)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		pcm->plugin_alloc_size[idx] = size;
 | 
							plug->alloc_size[idx] = size;
 | 
				
			||||||
		pcm->plugin_alloc_lock[idx] = 1;
 | 
							plug->alloc_lock[idx] = 1;
 | 
				
			||||||
		return pcm->plugin_alloc_ptr[idx] = ptr;
 | 
							return plug->alloc_ptr[idx] = ptr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (idx = 0; idx < 4; idx++) {
 | 
						for (idx = 0; idx < 2; idx++) {
 | 
				
			||||||
		if (pcm->plugin_alloc_ptr[idx] != NULL)
 | 
							if (plug->alloc_ptr[idx] != NULL)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		ptr = malloc(size);
 | 
							ptr = malloc(size);
 | 
				
			||||||
		if (ptr == NULL)
 | 
							if (ptr == NULL)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		pcm->plugin_alloc_size[idx] = size;
 | 
							plug->alloc_size[idx] = size;
 | 
				
			||||||
		pcm->plugin_alloc_lock[idx] = 1;
 | 
							plug->alloc_lock[idx] = 1;
 | 
				
			||||||
		return pcm->plugin_alloc_ptr[idx] = ptr;
 | 
							return plug->alloc_ptr[idx] = ptr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void snd_pcm_plugin_buf_free(snd_pcm_t *pcm, void *ptr)
 | 
					static void snd_pcm_plugin_buf_free(snd_pcm_t *pcm, int channel, void *ptr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int idx;
 | 
						int idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct snd_pcm_plug *plug;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pcm == NULL || ptr == NULL)
 | 
						if (pcm == NULL || ptr == NULL)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	for (idx = 0; idx < 4; idx++) {
 | 
						plug = &pcm->chan[channel].plug;
 | 
				
			||||||
		if (pcm->plugin_alloc_ptr[idx] == ptr) {
 | 
						for (idx = 0; idx < 2; idx++) {
 | 
				
			||||||
			pcm->plugin_alloc_lock[idx] = 0;
 | 
							if (plug->alloc_ptr[idx] == ptr) {
 | 
				
			||||||
 | 
								plug->alloc_lock[idx] = 0;
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void *snd_pcm_plugin_ptr_alloc(snd_pcm_t *pcm, size_t size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	void *ptr;
 | 
					 | 
				
			||||||
	int channel = pcm->plugin_alloc_xchannel;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (pcm->plugin_alloc_xptr[channel]) {
 | 
					 | 
				
			||||||
		if (pcm->plugin_alloc_xsize[channel] >= size)
 | 
					 | 
				
			||||||
			return pcm->plugin_alloc_xptr[channel];
 | 
					 | 
				
			||||||
		ptr = realloc(pcm->plugin_alloc_xptr[channel], size);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		ptr = malloc(size);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (ptr == NULL)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	pcm->plugin_alloc_xptr[channel] = (char *)ptr;
 | 
					 | 
				
			||||||
	pcm->plugin_alloc_xsize[channel] = size;			
 | 
					 | 
				
			||||||
	return ptr;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_plugin_xvoices(snd_pcm_plugin_t *plugin,
 | 
					static int snd_pcm_plugin_xvoices(snd_pcm_plugin_t *plugin,
 | 
				
			||||||
 | 
									  int channel,
 | 
				
			||||||
				  snd_pcm_plugin_voice_t **voices,
 | 
									  snd_pcm_plugin_voice_t **voices,
 | 
				
			||||||
				  size_t samples,
 | 
									  size_t samples,
 | 
				
			||||||
				  snd_pcm_format_t *format)
 | 
									  snd_pcm_format_t *format)
 | 
				
			||||||
| 
						 | 
					@ -857,7 +954,7 @@ static int snd_pcm_plugin_xvoices(snd_pcm_plugin_t *plugin,
 | 
				
			||||||
	if ((size % 8) != 0)
 | 
						if ((size % 8) != 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	size /= 8;
 | 
						size /= 8;
 | 
				
			||||||
	ptr = (char *)snd_pcm_plugin_buf_alloc(plugin->handle, size);
 | 
						ptr = (char *)snd_pcm_plugin_buf_alloc(plugin->handle, channel, size);
 | 
				
			||||||
	if (ptr == NULL)
 | 
						if (ptr == NULL)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	if ((size % format->voices) != 0)
 | 
						if ((size % format->voices) != 0)
 | 
				
			||||||
| 
						 | 
					@ -884,12 +981,212 @@ int snd_pcm_plugin_src_voices(snd_pcm_plugin_t *plugin,
 | 
				
			||||||
			      snd_pcm_plugin_voice_t **voices,
 | 
								      snd_pcm_plugin_voice_t **voices,
 | 
				
			||||||
			      size_t samples)
 | 
								      size_t samples)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return snd_pcm_plugin_xvoices(plugin, voices, samples, &plugin->src_format);
 | 
						return snd_pcm_plugin_xvoices(plugin, SND_PCM_CHANNEL_PLAYBACK, voices, samples, &plugin->src_format);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_plugin_dst_voices(snd_pcm_plugin_t *plugin,
 | 
					int snd_pcm_plugin_dst_voices(snd_pcm_plugin_t *plugin,
 | 
				
			||||||
			      snd_pcm_plugin_voice_t **voices,
 | 
								      snd_pcm_plugin_voice_t **voices,
 | 
				
			||||||
			      size_t samples)
 | 
								      size_t samples)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return snd_pcm_plugin_xvoices(plugin, voices, samples, &plugin->dst_format);
 | 
						return snd_pcm_plugin_xvoices(plugin, SND_PCM_CHANNEL_CAPTURE, voices, samples, &plugin->dst_format);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *playback_mmap(void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_pcm_t *pcm = data;
 | 
				
			||||||
 | 
						struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
 | 
				
			||||||
 | 
						struct snd_pcm_plug *plug = &chan->plug;
 | 
				
			||||||
 | 
						snd_pcm_mmap_control_t *control;
 | 
				
			||||||
 | 
						void *buffer;
 | 
				
			||||||
 | 
						int frags;
 | 
				
			||||||
 | 
						int frag_size, voice_size, voice_frag_size;
 | 
				
			||||||
 | 
						int voices;
 | 
				
			||||||
 | 
						control = plug->mmap_control;
 | 
				
			||||||
 | 
						buffer = plug->mmap_data;
 | 
				
			||||||
 | 
						frags = plug->setup.buf.block.frags;
 | 
				
			||||||
 | 
						frag_size = plug->setup.buf.block.frag_size;
 | 
				
			||||||
 | 
						voices = plug->setup.format.voices;
 | 
				
			||||||
 | 
						voice_size = plug->mmap_size / voices;
 | 
				
			||||||
 | 
						voice_frag_size = voice_size / frags;
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							int err;
 | 
				
			||||||
 | 
							struct pollfd pfd;
 | 
				
			||||||
 | 
							int frag = control->status.frag_io;
 | 
				
			||||||
 | 
							if (plug->thread_stop)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							if (control->status.status != SND_PCM_STATUS_RUNNING &&
 | 
				
			||||||
 | 
							    control->status.status != SND_PCM_STATUS_PREPARED) {
 | 
				
			||||||
 | 
								usleep(100000);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							pfd.fd = chan->fd;
 | 
				
			||||||
 | 
							pfd.events = POLLOUT;
 | 
				
			||||||
 | 
							pfd.revents = 0;
 | 
				
			||||||
 | 
							err = poll(&pfd, 1, -1);
 | 
				
			||||||
 | 
							if (err < 0) {
 | 
				
			||||||
 | 
								fprintf(stderr, "error on poll\n");
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!control->fragments[frag].data) {
 | 
				
			||||||
 | 
								usleep(10000);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							/* NYI: status.block */
 | 
				
			||||||
 | 
							control->fragments[frag].io = 1;
 | 
				
			||||||
 | 
							if (plug->setup.format.interleave) {
 | 
				
			||||||
 | 
								err = snd_pcm_plugin_write(pcm, buffer + frag * frag_size, frag_size);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								struct iovec vector[voices];
 | 
				
			||||||
 | 
								struct iovec *v = vector;
 | 
				
			||||||
 | 
								int voice;
 | 
				
			||||||
 | 
								for (voice = 0; voice < voices; ++voice) {
 | 
				
			||||||
 | 
									v->iov_base = buffer + voice_size * voice + frag * voice_frag_size;
 | 
				
			||||||
 | 
									v->iov_len = voice_frag_size;
 | 
				
			||||||
 | 
									v++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								err = snd_pcm_plugin_writev(pcm, vector, voice_frag_size);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (err <= 0) {
 | 
				
			||||||
 | 
								control->fragments[frag].io = 0;
 | 
				
			||||||
 | 
								snd_pcm_plugin_status_change(pcm, SND_PCM_CHANNEL_PLAYBACK);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							control->fragments[frag].io = 0;
 | 
				
			||||||
 | 
							control->fragments[frag].data = 0;
 | 
				
			||||||
 | 
							frag++;
 | 
				
			||||||
 | 
							if (frag == frags)
 | 
				
			||||||
 | 
								frag = 0;
 | 
				
			||||||
 | 
							control->status.frag_io = frag;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *capture_mmap(void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_pcm_t *pcm = data;
 | 
				
			||||||
 | 
						struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
 | 
				
			||||||
 | 
						struct snd_pcm_plug *plug = &chan->plug;
 | 
				
			||||||
 | 
						snd_pcm_mmap_control_t *control;
 | 
				
			||||||
 | 
						void *buffer;
 | 
				
			||||||
 | 
						int frag, frags;
 | 
				
			||||||
 | 
						int frag_size, voice_size, voice_frag_size;
 | 
				
			||||||
 | 
						int voices;
 | 
				
			||||||
 | 
						control = plug->mmap_control;
 | 
				
			||||||
 | 
						buffer = plug->mmap_data;
 | 
				
			||||||
 | 
						frag = 0;
 | 
				
			||||||
 | 
						frags = plug->setup.buf.block.frags;
 | 
				
			||||||
 | 
						frag_size = plug->setup.buf.block.frag_size;
 | 
				
			||||||
 | 
						voices = plug->setup.format.voices;
 | 
				
			||||||
 | 
						voice_size = plug->mmap_size / voices;
 | 
				
			||||||
 | 
						voice_frag_size = voice_size / frags;
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							int err;
 | 
				
			||||||
 | 
							struct pollfd pfd;
 | 
				
			||||||
 | 
							if (plug->thread_stop)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							if (control->status.status != SND_PCM_STATUS_RUNNING) {
 | 
				
			||||||
 | 
								usleep(100000);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							pfd.fd = chan->fd;
 | 
				
			||||||
 | 
							pfd.events = POLLIN;
 | 
				
			||||||
 | 
							pfd.revents = 0;
 | 
				
			||||||
 | 
							err = poll(&pfd, 1, -1);
 | 
				
			||||||
 | 
							if (err < 0) {
 | 
				
			||||||
 | 
								printf("error on poll\n");
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (control->fragments[frag].data) {
 | 
				
			||||||
 | 
								usleep(10000);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							/* NYI: status.block */
 | 
				
			||||||
 | 
							control->status.frag_io = frag;
 | 
				
			||||||
 | 
							control->fragments[frag].io = 1;
 | 
				
			||||||
 | 
							if (plug->setup.format.interleave) {
 | 
				
			||||||
 | 
								err = snd_pcm_plugin_read(pcm, buffer + frag * frag_size, frag_size);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								struct iovec vector[voices];
 | 
				
			||||||
 | 
								struct iovec *v = vector;
 | 
				
			||||||
 | 
								int voice;
 | 
				
			||||||
 | 
								for (voice = 0; voice < voices; ++voice) {
 | 
				
			||||||
 | 
									v->iov_base = buffer + voice_size * voice + frag * voice_frag_size;
 | 
				
			||||||
 | 
									v->iov_len = voice_frag_size;
 | 
				
			||||||
 | 
									v++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								err = snd_pcm_plugin_readv(pcm, vector, voice_frag_size);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (err < 0) {
 | 
				
			||||||
 | 
								snd_pcm_plugin_status_change(pcm, SND_PCM_CHANNEL_CAPTURE);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							control->fragments[frag].io = 0;
 | 
				
			||||||
 | 
							control->fragments[frag].data = 1;
 | 
				
			||||||
 | 
							frag++;
 | 
				
			||||||
 | 
							if (frag == frags)
 | 
				
			||||||
 | 
								frag = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int snd_pcm_plugin_mmap(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t **control, void **data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct snd_pcm_plug *plug;
 | 
				
			||||||
 | 
						if (!pcm || channel < 0 || channel > 1 || !control || !data)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						plug = &pcm->chan[channel].plug;
 | 
				
			||||||
 | 
						if (plug->first == NULL)
 | 
				
			||||||
 | 
							return snd_pcm_mmap(pcm, channel, control, data);
 | 
				
			||||||
 | 
						if (!plug->setup_is_valid)
 | 
				
			||||||
 | 
							return -EBADFD;
 | 
				
			||||||
 | 
						if (plug->setup.mode != SND_PCM_MODE_BLOCK)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (plug->mmap_data) {
 | 
				
			||||||
 | 
							*control = plug->mmap_control;
 | 
				
			||||||
 | 
							*data = plug->mmap_data;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						plug->mmap_control = malloc(sizeof(snd_pcm_mmap_control_t));
 | 
				
			||||||
 | 
						plug->mmap_size = plug->setup.buf.block.frag_size * plug->setup.buf.block.frags;
 | 
				
			||||||
 | 
						plug->mmap_data = malloc(plug->mmap_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mmap_clear(plug);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*control = plug->mmap_control;
 | 
				
			||||||
 | 
						*data = plug->mmap_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						plug->thread_stop = 0;
 | 
				
			||||||
 | 
						if (channel == SND_PCM_CHANNEL_PLAYBACK)
 | 
				
			||||||
 | 
							err = pthread_create(&plug->thread, NULL, playback_mmap, pcm);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							err = pthread_create(&plug->thread, NULL, capture_mmap, pcm);
 | 
				
			||||||
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							snd_pcm_plugin_munmap(pcm, channel);
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int snd_pcm_plugin_munmap(snd_pcm_t *pcm, int channel)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct snd_pcm_plug *plug;
 | 
				
			||||||
 | 
						if (!pcm || channel < 0 || channel > 1)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						plug = &pcm->chan[channel].plug;
 | 
				
			||||||
 | 
						if (plug->first == NULL)
 | 
				
			||||||
 | 
							return snd_pcm_munmap(pcm, channel);
 | 
				
			||||||
 | 
						if (plug->mmap_data) {
 | 
				
			||||||
 | 
							plug->thread_stop = 1;
 | 
				
			||||||
 | 
							pthread_join(plug->thread, NULL);
 | 
				
			||||||
 | 
							free(plug->mmap_control);
 | 
				
			||||||
 | 
							plug->mmap_control = 0;
 | 
				
			||||||
 | 
							free(plug->mmap_data);
 | 
				
			||||||
 | 
							plug->mmap_data = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,7 +75,7 @@ static int poll_playback(snd_pcm_t *pcm)
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	if (pcm->mode & SND_PCM_OPEN_NONBLOCK)
 | 
						if (pcm->mode & SND_PCM_OPEN_NONBLOCK)
 | 
				
			||||||
		return -EAGAIN;
 | 
							return -EAGAIN;
 | 
				
			||||||
	pfd.fd = pcm->fd[SND_PCM_CHANNEL_PLAYBACK];
 | 
						pfd.fd = pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd;
 | 
				
			||||||
	pfd.events = POLLOUT;
 | 
						pfd.events = POLLOUT;
 | 
				
			||||||
	pfd.revents = 0;
 | 
						pfd.revents = 0;
 | 
				
			||||||
	err = poll(&pfd, 1, 1000);
 | 
						err = poll(&pfd, 1, 1000);
 | 
				
			||||||
| 
						 | 
					@ -146,7 +146,7 @@ static int poll_capture(snd_pcm_t *pcm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pcm->mode & SND_PCM_OPEN_NONBLOCK)
 | 
						if (pcm->mode & SND_PCM_OPEN_NONBLOCK)
 | 
				
			||||||
		return -EAGAIN;
 | 
							return -EAGAIN;
 | 
				
			||||||
	pfd.fd = pcm->fd[SND_PCM_CHANNEL_CAPTURE];
 | 
						pfd.fd = pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd;
 | 
				
			||||||
	pfd.events = POLLIN;
 | 
						pfd.events = POLLIN;
 | 
				
			||||||
	pfd.revents = 0;
 | 
						pfd.revents = 0;
 | 
				
			||||||
	err = poll(&pfd, 1, 1000);
 | 
						err = poll(&pfd, 1, 1000);
 | 
				
			||||||
| 
						 | 
					@ -185,8 +185,7 @@ static int query_capture(snd_pcm_plugin_t *plugin, int not_use_poll)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int mmap_src_voices(snd_pcm_plugin_t *plugin,
 | 
					static int mmap_src_voices(snd_pcm_plugin_t *plugin,
 | 
				
			||||||
			   snd_pcm_plugin_voice_t **voices,
 | 
								   snd_pcm_plugin_voice_t **voices,
 | 
				
			||||||
			   size_t samples,
 | 
								   size_t samples)
 | 
				
			||||||
			   void *(*plugin_alloc)(snd_pcm_plugin_handle_t *handle, size_t size))
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mmap_t *data;
 | 
						mmap_t *data;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
| 
						 | 
					@ -221,8 +220,7 @@ static int mmap_src_voices(snd_pcm_plugin_t *plugin,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
 | 
					static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
 | 
				
			||||||
			   snd_pcm_plugin_voice_t **voices,
 | 
								   snd_pcm_plugin_voice_t **voices,
 | 
				
			||||||
			   size_t samples,
 | 
								   size_t samples)
 | 
				
			||||||
			   void *(*plugin_alloc)(snd_pcm_plugin_handle_t *handle, size_t size))
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mmap_t *data;
 | 
						mmap_t *data;
 | 
				
			||||||
	int voice;
 | 
						int voice;
 | 
				
			||||||
| 
						 | 
					@ -275,7 +273,7 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
 | 
				
			||||||
		size = snd_pcm_plugin_src_samples_to_size(plugin, samples);
 | 
							size = snd_pcm_plugin_src_samples_to_size(plugin, samples);
 | 
				
			||||||
		if (size != data->frag_size)
 | 
							if (size != data->frag_size)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		if (src_voices != data->voices) {
 | 
							if (plugin->prev == NULL) {
 | 
				
			||||||
			if (plugin->src_format.interleave) {
 | 
								if (plugin->src_format.interleave) {
 | 
				
			||||||
				void *dst = data->voices[0].addr + data->frag * data->frag_size;
 | 
									void *dst = data->voices[0].addr + data->frag * data->frag_size;
 | 
				
			||||||
				/* Paranoia: add check for src_voices */
 | 
									/* Paranoia: add check for src_voices */
 | 
				
			||||||
| 
						 | 
					@ -306,7 +304,7 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
 | 
				
			||||||
		size = snd_pcm_plugin_dst_samples_to_size(plugin, samples);
 | 
							size = snd_pcm_plugin_dst_samples_to_size(plugin, samples);
 | 
				
			||||||
		if (size != data->frag_size)
 | 
							if (size != data->frag_size)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		if (dst_voices != data->voices) {
 | 
							if (plugin->next == NULL) {
 | 
				
			||||||
			if (plugin->dst_format.interleave) {
 | 
								if (plugin->dst_format.interleave) {
 | 
				
			||||||
				void *src = data->voices[0].addr + data->frag * data->frag_size;
 | 
									void *src = data->voices[0].addr + data->frag * data->frag_size;
 | 
				
			||||||
				/* Paranoia: add check for dst_voices */
 | 
									/* Paranoia: add check for dst_voices */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue