mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	- added shm area manager code
- fixed parsing of period_size/buffer_size options for dmix, dsnoop and dshare plugins
This commit is contained in:
		
							parent
							
								
									7340d20729
								
							
						
					
					
						commit
						573f85dc1d
					
				
					 11 changed files with 67 additions and 58 deletions
				
			
		| 
						 | 
				
			
			@ -9,7 +9,7 @@ VSYMS =
 | 
			
		|||
endif
 | 
			
		||||
 | 
			
		||||
lib_LTLIBRARIES = libasound.la
 | 
			
		||||
libasound_la_SOURCES = conf.c confmisc.c input.c output.c async.c error.c dlmisc.c socket.c
 | 
			
		||||
libasound_la_SOURCES = conf.c confmisc.c input.c output.c async.c error.c dlmisc.c socket.c shmarea.c
 | 
			
		||||
libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \
 | 
			
		||||
                      rawmidi/librawmidi.la timer/libtimer.la \
 | 
			
		||||
		      hwdep/libhwdep.la seq/libseq.la instr/libinstr.la \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6246,7 +6246,10 @@ static const char *names[SND_PCM_HW_PARAM_LAST_INTERVAL + 1] = {
 | 
			
		|||
	[SND_PCM_HW_PARAM_CHANNELS] = "channels",
 | 
			
		||||
	[SND_PCM_HW_PARAM_RATE] = "rate",
 | 
			
		||||
	[SND_PCM_HW_PARAM_PERIOD_TIME] = "period_time",
 | 
			
		||||
	[SND_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time"
 | 
			
		||||
	[SND_PCM_HW_PARAM_PERIOD_SIZE] = "period_size",
 | 
			
		||||
	[SND_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time",
 | 
			
		||||
	[SND_PCM_HW_PARAM_BUFFER_SIZE] = "buffer_size",
 | 
			
		||||
	[SND_PCM_HW_PARAM_PERIODS] = "periods"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -278,6 +278,8 @@ static void server_job(snd_pcm_direct_t *dmix)
 | 
			
		|||
	}
 | 
			
		||||
	close(dmix->server_fd);
 | 
			
		||||
	close(dmix->hw_fd);
 | 
			
		||||
	if (dmix->server_free)
 | 
			
		||||
		dmix->server_free(dmix);
 | 
			
		||||
	snd_pcm_direct_shm_discard(dmix);
 | 
			
		||||
	snd_pcm_direct_semaphore_discard(dmix);
 | 
			
		||||
	server_printf("DIRECT SERVER EXIT\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,7 +72,9 @@ typedef struct {
 | 
			
		|||
	} u;
 | 
			
		||||
} snd_pcm_direct_share_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
typedef struct snd_pcm_direct snd_pcm_direct_t;
 | 
			
		||||
 | 
			
		||||
struct snd_pcm_direct {
 | 
			
		||||
	snd_pcm_type_t type;		/* type (dmix, dsnoop, dshare) */
 | 
			
		||||
	key_t ipc_key;			/* IPC key for semaphore and memory */
 | 
			
		||||
	int semid;			/* IPC global semaphore identification */
 | 
			
		||||
| 
						 | 
				
			
			@ -109,7 +111,8 @@ typedef struct {
 | 
			
		|||
			unsigned long long chn_mask;
 | 
			
		||||
		} dshare;
 | 
			
		||||
	} u;
 | 
			
		||||
} snd_pcm_direct_t;
 | 
			
		||||
	void (*server_free)(snd_pcm_direct_t *direct);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix);
 | 
			
		||||
int snd_pcm_direct_semaphore_discard(snd_pcm_direct_t *dmix);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,6 +96,13 @@ static int shm_sum_discard(snd_pcm_direct_t *dmix)
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dmix_server_free(snd_pcm_direct_t *dmix)
 | 
			
		||||
{
 | 
			
		||||
	/* remove the memory region */
 | 
			
		||||
	shm_sum_create_or_connect(dmix);
 | 
			
		||||
	shm_sum_discard(dmix);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  the main function of this plugin: mixing
 | 
			
		||||
 *  FIXME: optimize it for different architectures
 | 
			
		||||
| 
						 | 
				
			
			@ -954,6 +961,8 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		dmix->spcm = spcm;
 | 
			
		||||
 | 
			
		||||
		dmix->server_free = dmix_server_free;
 | 
			
		||||
		
 | 
			
		||||
		ret = snd_pcm_direct_server_create(dmix);
 | 
			
		||||
		if (ret < 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -992,7 +1001,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
 | 
			
		|||
 | 
			
		||||
	ret = shm_sum_create_or_connect(dmix);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		SNDERR("unabel to initialize sum ring buffer");
 | 
			
		||||
		SNDERR("unable to initialize sum ring buffer");
 | 
			
		||||
		goto _err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1177,20 +1186,22 @@ int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
 | 
			
		|||
	params.buffer_time = -1;
 | 
			
		||||
	bsize = psize = -1;
 | 
			
		||||
	params.periods = 3;
 | 
			
		||||
 | 
			
		||||
	err = snd_pcm_slave_conf(root, slave, &sconf, 8,
 | 
			
		||||
				 SND_PCM_HW_PARAM_FORMAT, 0, ¶ms.format,
 | 
			
		||||
				 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
 | 
			
		||||
				 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
 | 
			
		||||
				 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
 | 
			
		||||
				 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
 | 
			
		||||
				 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &bsize,
 | 
			
		||||
				 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &psize,
 | 
			
		||||
				 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
 | 
			
		||||
				 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
 | 
			
		||||
				 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	params.period_size = psize;
 | 
			
		||||
	params.buffer_size = bsize;
 | 
			
		||||
 | 
			
		||||
	err = snd_pcm_dmix_open(pcmp, name, ipc_key, ¶ms, bindings, root, sconf, stream, mode);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		snd_config_delete(sconf);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -984,8 +984,8 @@ int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
 | 
			
		|||
				 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
 | 
			
		||||
				 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
 | 
			
		||||
				 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
 | 
			
		||||
				 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &bsize,
 | 
			
		||||
				 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &psize,
 | 
			
		||||
				 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
 | 
			
		||||
				 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
 | 
			
		||||
				 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		return err;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -936,8 +936,8 @@ int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
 | 
			
		|||
				 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
 | 
			
		||||
				 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
 | 
			
		||||
				 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
 | 
			
		||||
				 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &bsize,
 | 
			
		||||
				 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &psize,
 | 
			
		||||
				 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
 | 
			
		||||
				 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
 | 
			
		||||
				 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		return err;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,7 +95,6 @@ typedef struct {
 | 
			
		|||
	    avail_update_flag: 1,
 | 
			
		||||
	    mmap_shm: 1;
 | 
			
		||||
	snd_pcm_uframes_t appl_ptr;
 | 
			
		||||
	int shmid;
 | 
			
		||||
} snd_pcm_hw_t;
 | 
			
		||||
 | 
			
		||||
#define SNDRV_FILE_PCM_STREAM_PLAYBACK		"/dev/snd/pcmC%iD%ip"
 | 
			
		||||
| 
						 | 
				
			
			@ -395,7 +394,7 @@ static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info
 | 
			
		|||
		info->u.mmap.offset = i.offset;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	return snd_pcm_channel_info_shm(pcm, info, hw->shmid);
 | 
			
		||||
	return snd_pcm_channel_info_shm(pcm, info, -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 | 
			
		||||
| 
						 | 
				
			
			@ -733,35 +732,13 @@ static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_pcm_hw_mmap(snd_pcm_t *pcm)
 | 
			
		||||
static int snd_pcm_hw_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_hw_t *hw = pcm->private_data;
 | 
			
		||||
	int err;
 | 
			
		||||
	if (hw->mmap_shm) {
 | 
			
		||||
		snd_pcm_uframes_t size = snd_pcm_frames_to_bytes(pcm, (snd_pcm_sframes_t) pcm->buffer_size);
 | 
			
		||||
		int id = shmget(IPC_PRIVATE, size, 0666);
 | 
			
		||||
		hw->mmap_shm = 1;
 | 
			
		||||
		if (id < 0) {
 | 
			
		||||
			err = -errno;
 | 
			
		||||
			SYSERR("shmget failed");
 | 
			
		||||
			return err;
 | 
			
		||||
		}
 | 
			
		||||
		hw->shmid = id;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_pcm_hw_munmap(snd_pcm_t *pcm)
 | 
			
		||||
static int snd_pcm_hw_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_hw_t *hw = pcm->private_data;
 | 
			
		||||
	int err;
 | 
			
		||||
	if (hw->mmap_shm) {
 | 
			
		||||
		if (shmctl(hw->shmid, IPC_RMID, 0) < 0) {
 | 
			
		||||
			err = -errno;
 | 
			
		||||
			SYSERR("shmctl IPC_RMID failed");
 | 
			
		||||
			return err;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -110,8 +110,8 @@ typedef struct _snd_pcm_channel_info {
 | 
			
		|||
	enum { SND_PCM_AREA_SHM, SND_PCM_AREA_MMAP } type;
 | 
			
		||||
	union {
 | 
			
		||||
		struct {
 | 
			
		||||
			struct snd_shm_area *area;
 | 
			
		||||
			int shmid;
 | 
			
		||||
			int remove;
 | 
			
		||||
		} shm;
 | 
			
		||||
		struct {
 | 
			
		||||
			int fd;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -261,8 +261,7 @@ int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
 | 
			
		|||
	return pcm->ops->channel_info(pcm, info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info,
 | 
			
		||||
			     int shmid)
 | 
			
		||||
int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info, int shmid)
 | 
			
		||||
{
 | 
			
		||||
	switch (pcm->access) {
 | 
			
		||||
	case SND_PCM_ACCESS_MMAP_INTERLEAVED:
 | 
			
		||||
| 
						 | 
				
			
			@ -282,7 +281,7 @@ int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info,
 | 
			
		|||
	info->addr = 0;
 | 
			
		||||
	info->type = SND_PCM_AREA_SHM;
 | 
			
		||||
	info->u.shm.shmid = shmid;
 | 
			
		||||
	info->u.shm.remove = 0;
 | 
			
		||||
	info->u.shm.area = NULL;
 | 
			
		||||
	return 0;
 | 
			
		||||
}	
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -362,7 +361,16 @@ int snd_pcm_mmap(snd_pcm_t *pcm)
 | 
			
		|||
						return -errno;
 | 
			
		||||
					}
 | 
			
		||||
					i->u.shm.shmid = id;
 | 
			
		||||
					i->u.shm.remove = 1;
 | 
			
		||||
					ptr = shmat(i->u.shm.shmid, 0, 0);
 | 
			
		||||
					if (ptr == (void *) -1) {
 | 
			
		||||
						SYSERR("shmat failed");
 | 
			
		||||
						return -errno;
 | 
			
		||||
					}
 | 
			
		||||
					i->u.shm.area = snd_shm_area_create(id, ptr);
 | 
			
		||||
					if (i->u.shm.area == NULL) {
 | 
			
		||||
						SYSERR("snd_shm_area_create failed");
 | 
			
		||||
						return -ENOMEM;
 | 
			
		||||
					}
 | 
			
		||||
					if (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
 | 
			
		||||
					    pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
 | 
			
		||||
					    	unsigned int c1;
 | 
			
		||||
| 
						 | 
				
			
			@ -370,15 +378,16 @@ int snd_pcm_mmap(snd_pcm_t *pcm)
 | 
			
		|||
							snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
 | 
			
		||||
							if (i1->u.shm.shmid < 0) {
 | 
			
		||||
								i1->u.shm.shmid = id;
 | 
			
		||||
								i1->u.shm.remove = 1;
 | 
			
		||||
								i1->u.shm.area = snd_shm_area_share(i->u.shm.area);
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				ptr = shmat(i->u.shm.shmid, 0, 0);
 | 
			
		||||
				if (ptr == (void*) -1) {
 | 
			
		||||
					SYSERR("shmat failed");
 | 
			
		||||
					return -errno;
 | 
			
		||||
				} else {
 | 
			
		||||
					ptr = shmat(i->u.shm.shmid, 0, 0);
 | 
			
		||||
					if (ptr == (void*) -1) {
 | 
			
		||||
						SYSERR("shmat failed");
 | 
			
		||||
						return -errno;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				i->addr = ptr;
 | 
			
		||||
				break;
 | 
			
		||||
| 
						 | 
				
			
			@ -446,18 +455,15 @@ int snd_pcm_munmap(snd_pcm_t *pcm)
 | 
			
		|||
			errno = 0;
 | 
			
		||||
			break;
 | 
			
		||||
		case SND_PCM_AREA_SHM:
 | 
			
		||||
			err = shmdt(i->addr);
 | 
			
		||||
			if (err < 0) {
 | 
			
		||||
				SYSERR("shmdt failed");
 | 
			
		||||
				return -errno;
 | 
			
		||||
			}
 | 
			
		||||
			if (i->u.shm.remove) {
 | 
			
		||||
				if (shmctl(i->u.shm.shmid, IPC_RMID, 0) < 0) {
 | 
			
		||||
					SYSERR("shmctl IPC_RMID failed");
 | 
			
		||||
			if (i->u.shm.area) {
 | 
			
		||||
				snd_shm_area_destroy(i->u.shm.area);
 | 
			
		||||
				i->u.shm.area = NULL;
 | 
			
		||||
			} else {
 | 
			
		||||
				err = shmdt(i->addr);
 | 
			
		||||
				if (err < 0) {
 | 
			
		||||
					SYSERR("shmdt failed");
 | 
			
		||||
					return -errno;
 | 
			
		||||
				}
 | 
			
		||||
				i->u.shm.shmid = -1;
 | 
			
		||||
				i->u.shm.remove = 0;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue