mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-10-29 05:40:25 -04: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
				
			
		|  | @ -114,6 +114,13 @@ int snd_async_handler_get_fd(snd_async_handler_t *handler); | |||
| int snd_async_handler_get_signo(snd_async_handler_t *handler); | ||||
| void *snd_async_handler_get_callback_private(snd_async_handler_t *handler); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Internal structure for an IPC shm area manager. | ||||
|  */ | ||||
| struct snd_shm_area *snd_shm_area_create(int shmid, void *ptr); | ||||
| struct snd_shm_area *snd_shm_area_share(struct snd_shm_area *area); | ||||
| int snd_shm_area_destroy(struct snd_shm_area *area); | ||||
| 
 | ||||
| /** Timestamp */ | ||||
| typedef struct timeval snd_timestamp_t; | ||||
| /** Hi-res timestamp */ | ||||
|  |  | |||
|  | @ -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 | ||||
|  | @ -955,6 +962,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) { | ||||
| 			SNDERR("unable to create server"); | ||||
|  | @ -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,16 +378,17 @@ 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); | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} else { | ||||
| 					ptr = shmat(i->u.shm.shmid, 0, 0); | ||||
| 					if (ptr == (void*) -1) { | ||||
| 						SYSERR("shmat failed"); | ||||
| 						return -errno; | ||||
| 					} | ||||
| 				} | ||||
| 				i->addr = ptr; | ||||
| 				break; | ||||
| 			default: | ||||
|  | @ -446,18 +455,15 @@ int snd_pcm_munmap(snd_pcm_t *pcm) | |||
| 			errno = 0; | ||||
| 			break; | ||||
| 		case SND_PCM_AREA_SHM: | ||||
| 			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; | ||||
| 				} | ||||
| 			if (i->u.shm.remove) { | ||||
| 				if (shmctl(i->u.shm.shmid, IPC_RMID, 0) < 0) { | ||||
| 					SYSERR("shmctl IPC_RMID 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
	
	 Jaroslav Kysela
						Jaroslav Kysela