mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-10-29 05:40:25 -04:00 
			
		
		
		
	Direct plugins update:
- moved more common code to pcm_direct.c - added missing initialization of some variables in hw_params
This commit is contained in:
		
							parent
							
								
									c0e493eb5a
								
							
						
					
					
						commit
						95418afc67
					
				
					 5 changed files with 244 additions and 585 deletions
				
			
		|  | @ -374,6 +374,199 @@ int snd_pcm_direct_client_discard(snd_pcm_direct_t *dmix) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  *  plugin helpers | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | int snd_pcm_direct_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) | ||||||
|  | { | ||||||
|  | 	/* value is cached for us in pcm->mode (SND_PCM_NONBLOCK flag) */ | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid) | ||||||
|  | { | ||||||
|  | 	snd_pcm_direct_t *dmix = pcm->private_data; | ||||||
|  | 	return snd_timer_async(dmix->timer, sig, pid); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) | ||||||
|  | { | ||||||
|  | 	snd_pcm_direct_t *dmix = pcm->private_data; | ||||||
|  | 	unsigned short events; | ||||||
|  | 	static snd_timer_read_t rbuf[5];	/* can be overwriten by multiple plugins, we don't need the value */ | ||||||
|  | 
 | ||||||
|  | 	assert(pfds && nfds == 1 && revents); | ||||||
|  | 	events = pfds[0].revents; | ||||||
|  | 	if (events & POLLIN) { | ||||||
|  | 		events |= POLLOUT; | ||||||
|  | 		events &= ~POLLIN; | ||||||
|  | 		/* empty the timer read queue */ | ||||||
|  | 		while (snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) == sizeof(rbuf)) ; | ||||||
|  | 	} | ||||||
|  | 	*revents = events; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info) | ||||||
|  | { | ||||||
|  | 	// snd_pcm_direct_t *dmix = pcm->private_data;
 | ||||||
|  | 
 | ||||||
|  | 	memset(info, 0, sizeof(*info)); | ||||||
|  | 	info->stream = pcm->stream; | ||||||
|  | 	info->card = -1; | ||||||
|  | 	/* FIXME: fill this with something more useful: we know the hardware name */ | ||||||
|  | 	if (pcm->name) { | ||||||
|  | 		strncpy(info->id, pcm->name, sizeof(info->id)); | ||||||
|  | 		strncpy(info->name, pcm->name, sizeof(info->name)); | ||||||
|  | 		strncpy(info->subname, pcm->name, sizeof(info->subname)); | ||||||
|  | 	} | ||||||
|  | 	info->subdevices_count = 1; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params, | ||||||
|  | 					snd_pcm_hw_param_t var) | ||||||
|  | { | ||||||
|  | 	return ¶ms->masks[var - SND_PCM_HW_PARAM_FIRST_MASK]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params, | ||||||
|  | 						snd_pcm_hw_param_t var) | ||||||
|  | { | ||||||
|  | 	return ¶ms->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int hw_param_interval_refine_one(snd_pcm_hw_params_t *params, | ||||||
|  | 					snd_pcm_hw_param_t var, | ||||||
|  | 					snd_pcm_hw_params_t *src) | ||||||
|  | { | ||||||
|  | 	snd_interval_t *i; | ||||||
|  | 
 | ||||||
|  | 	if (!(params->rmask & (1<<var)))	/* nothing to do? */ | ||||||
|  | 		return 0; | ||||||
|  | 	i = hw_param_interval(params, var); | ||||||
|  | 	if (snd_interval_empty(i)) { | ||||||
|  | 		SNDERR("dshare interval %i empty?", (int)var); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 	if (snd_interval_refine(i, hw_param_interval(src, var))) | ||||||
|  | 		params->cmask |= 1<<var; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #undef REFINE_DEBUG | ||||||
|  | 
 | ||||||
|  | int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) | ||||||
|  | { | ||||||
|  | 	snd_pcm_direct_t *dshare = pcm->private_data; | ||||||
|  | 	snd_pcm_hw_params_t *hw_params = &dshare->shmptr->hw_params; | ||||||
|  | 	static snd_mask_t access = { .bits = {  | ||||||
|  | 					(1<<SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) | | ||||||
|  | 					(1<<SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) | | ||||||
|  | 					(1<<SNDRV_PCM_ACCESS_RW_INTERLEAVED) | | ||||||
|  | 					(1<<SNDRV_PCM_ACCESS_RW_NONINTERLEAVED), | ||||||
|  | 					0, 0, 0 } }; | ||||||
|  | 	int err; | ||||||
|  | 
 | ||||||
|  | #ifdef REFINE_DEBUG | ||||||
|  | 	snd_output_t *log; | ||||||
|  | 	snd_output_stdio_attach(&log, stderr, 0); | ||||||
|  | 	snd_output_puts(log, "DMIX REFINE (begin):\n"); | ||||||
|  | 	snd_pcm_hw_params_dump(params, log); | ||||||
|  | #endif | ||||||
|  | 	if (params->rmask & (1<<SND_PCM_HW_PARAM_ACCESS)) { | ||||||
|  | 		if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS))) { | ||||||
|  | 			SNDERR("dshare access mask empty?"); | ||||||
|  | 			return -EINVAL; | ||||||
|  | 		} | ||||||
|  | 		if (snd_mask_refine(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS), &access)) | ||||||
|  | 			params->cmask |= 1<<SND_PCM_HW_PARAM_ACCESS; | ||||||
|  | 	} | ||||||
|  | 	if (params->rmask & (1<<SND_PCM_HW_PARAM_FORMAT)) { | ||||||
|  | 		if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT))) { | ||||||
|  | 			SNDERR("dshare format mask empty?"); | ||||||
|  | 			return -EINVAL; | ||||||
|  | 		} | ||||||
|  | 		if (snd_mask_refine_set(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT), | ||||||
|  | 				        snd_mask_value(hw_param_mask(hw_params, SND_PCM_HW_PARAM_FORMAT)))) | ||||||
|  | 			params->cmask |= 1<<SND_PCM_HW_PARAM_FORMAT; | ||||||
|  | 	} | ||||||
|  | 	//snd_mask_none(hw_param_mask(params, SND_PCM_HW_PARAM_SUBFORMAT));
 | ||||||
|  | 	if (params->rmask & (1<<SND_PCM_HW_PARAM_CHANNELS)) { | ||||||
|  | 		if (snd_interval_empty(hw_param_interval(params, SND_PCM_HW_PARAM_CHANNELS))) { | ||||||
|  | 			SNDERR("dshare channels mask empty?"); | ||||||
|  | 			return -EINVAL; | ||||||
|  | 		} | ||||||
|  | 		err = snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_CHANNELS), dshare->channels); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return err; | ||||||
|  | 	} | ||||||
|  | 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_RATE, hw_params); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  | 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE, hw_params); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  | 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_TIME, hw_params); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  | 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, hw_params); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  | 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, hw_params); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  | 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIODS, hw_params); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  | #ifdef REFINE_DEBUG | ||||||
|  | 	snd_output_puts(log, "DMIX REFINE (end):\n"); | ||||||
|  | 	snd_pcm_hw_params_dump(params, log); | ||||||
|  | 	snd_output_close(log); | ||||||
|  | #endif | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int snd_pcm_direct_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) | ||||||
|  | { | ||||||
|  | 	snd_pcm_direct_t *dmix = pcm->private_data; | ||||||
|  | 
 | ||||||
|  | 	params->info = dmix->shmptr->s.info; | ||||||
|  | 	params->rate_num = dmix->shmptr->s.rate; | ||||||
|  | 	params->rate_den = 1; | ||||||
|  | 	params->fifo_size = 0; | ||||||
|  | 	params->msbits = dmix->shmptr->s.msbits; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int snd_pcm_direct_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED) | ||||||
|  | { | ||||||
|  | 	/* values are cached in the pcm structure */ | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int snd_pcm_direct_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED) | ||||||
|  | { | ||||||
|  | 	/* values are cached in the pcm structure */ | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) | ||||||
|  | { | ||||||
|  |         return snd_pcm_channel_info_shm(pcm, info, -1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int snd_pcm_direct_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) | ||||||
|  | { | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |          | ||||||
|  | int snd_pcm_direct_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) | ||||||
|  | { | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * this function initializes hardware and starts playback operation with |  * this function initializes hardware and starts playback operation with | ||||||
|  * no stop threshold (it operates all time without xrun checking) |  * no stop threshold (it operates all time without xrun checking) | ||||||
|  | @ -578,6 +771,8 @@ int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, str | ||||||
| 	dmix->shmptr->s.rate = spcm->rate; | 	dmix->shmptr->s.rate = spcm->rate; | ||||||
| 	dmix->shmptr->s.format = spcm->format; | 	dmix->shmptr->s.format = spcm->format; | ||||||
| 	dmix->shmptr->s.boundary = spcm->boundary; | 	dmix->shmptr->s.boundary = spcm->boundary; | ||||||
|  | 	dmix->shmptr->s.info = spcm->info; | ||||||
|  | 	dmix->shmptr->s.msbits = spcm->msbits; | ||||||
| 
 | 
 | ||||||
| 	spcm->donot_close = 1; | 	spcm->donot_close = 1; | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -64,6 +64,8 @@ typedef struct { | ||||||
| 		unsigned int sample_bits; | 		unsigned int sample_bits; | ||||||
| 		unsigned int rate; | 		unsigned int rate; | ||||||
| 		snd_pcm_format_t format; | 		snd_pcm_format_t format; | ||||||
|  | 		unsigned int info; | ||||||
|  | 		unsigned int msbits; | ||||||
| 	} s; | 	} s; | ||||||
| 	union { | 	union { | ||||||
| 		struct { | 		struct { | ||||||
|  | @ -128,6 +130,17 @@ int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, str | ||||||
| int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix); | int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix); | ||||||
| int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm); | int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm); | ||||||
| int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, snd_config_t *cfg); | int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, snd_config_t *cfg); | ||||||
|  | int snd_pcm_direct_nonblock(snd_pcm_t *pcm, int nonblock); | ||||||
|  | int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid); | ||||||
|  | int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); | ||||||
|  | int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info); | ||||||
|  | int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); | ||||||
|  | int snd_pcm_direct_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params); | ||||||
|  | int snd_pcm_direct_hw_free(snd_pcm_t *pcm); | ||||||
|  | int snd_pcm_direct_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params); | ||||||
|  | int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info); | ||||||
|  | int snd_pcm_direct_mmap(snd_pcm_t *pcm); | ||||||
|  | int snd_pcm_direct_munmap(snd_pcm_t *pcm); | ||||||
| 
 | 
 | ||||||
| int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid); | int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid); | ||||||
| struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm); | struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm); | ||||||
|  |  | ||||||
|  | @ -376,180 +376,6 @@ static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) | ||||||
|  *  plugin implementation |  *  plugin implementation | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| static int snd_pcm_dmix_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	/* value is cached for us in pcm->mode (SND_PCM_NONBLOCK flag) */ |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dmix_async(snd_pcm_t *pcm, int sig, pid_t pid) |  | ||||||
| { |  | ||||||
| 	snd_pcm_direct_t *dmix = pcm->private_data; |  | ||||||
| 	return snd_timer_async(dmix->timer, sig, pid); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) |  | ||||||
| { |  | ||||||
| 	snd_pcm_direct_t *dmix = pcm->private_data; |  | ||||||
| 	unsigned short events; |  | ||||||
| 	static snd_timer_read_t rbuf[5];	/* can be overwriten by multiple plugins, we don't need the value */ |  | ||||||
| 
 |  | ||||||
| 	assert(pfds && nfds == 1 && revents); |  | ||||||
| 	events = pfds[0].revents; |  | ||||||
| 	if (events & POLLIN) { |  | ||||||
| 		events |= POLLOUT; |  | ||||||
| 		events &= ~POLLIN; |  | ||||||
| 		/* empty the timer read queue */ |  | ||||||
| 		while (snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) == sizeof(rbuf)) ; |  | ||||||
| 	} |  | ||||||
| 	*revents = events; |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dmix_info(snd_pcm_t *pcm, snd_pcm_info_t * info) |  | ||||||
| { |  | ||||||
| 	// snd_pcm_direct_t *dmix = pcm->private_data;
 |  | ||||||
| 
 |  | ||||||
| 	memset(info, 0, sizeof(*info)); |  | ||||||
| 	info->stream = pcm->stream; |  | ||||||
| 	info->card = -1; |  | ||||||
| 	/* FIXME: fill this with something more useful: we know the hardware name */ |  | ||||||
| 	if (pcm->name) { |  | ||||||
| 		strncpy(info->id, pcm->name, sizeof(info->id)); |  | ||||||
| 		strncpy(info->name, pcm->name, sizeof(info->name)); |  | ||||||
| 		strncpy(info->subname, pcm->name, sizeof(info->subname)); |  | ||||||
| 	} |  | ||||||
| 	info->subdevices_count = 1; |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params, |  | ||||||
| 					snd_pcm_hw_param_t var) |  | ||||||
| { |  | ||||||
| 	return ¶ms->masks[var - SND_PCM_HW_PARAM_FIRST_MASK]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params, |  | ||||||
| 						snd_pcm_hw_param_t var) |  | ||||||
| { |  | ||||||
| 	return ¶ms->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int hw_param_interval_refine_one(snd_pcm_hw_params_t *params, |  | ||||||
| 					snd_pcm_hw_param_t var, |  | ||||||
| 					snd_pcm_hw_params_t *src) |  | ||||||
| { |  | ||||||
| 	snd_interval_t *i; |  | ||||||
| 
 |  | ||||||
| 	if (!(params->rmask & (1<<var)))	/* nothing to do? */ |  | ||||||
| 		return 0; |  | ||||||
| 	i = hw_param_interval(params, var); |  | ||||||
| 	if (snd_interval_empty(i)) { |  | ||||||
| 		SNDERR("dmix interval %i empty?", (int)var); |  | ||||||
| 		return -EINVAL; |  | ||||||
| 	} |  | ||||||
| 	if (snd_interval_refine(i, hw_param_interval(src, var))) |  | ||||||
| 		params->cmask |= 1<<var; |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #undef REFINE_DEBUG |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dmix_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) |  | ||||||
| { |  | ||||||
| 	snd_pcm_direct_t *dmix = pcm->private_data; |  | ||||||
| 	snd_pcm_hw_params_t *hw_params = &dmix->shmptr->hw_params; |  | ||||||
| 	static snd_mask_t access = { .bits = {  |  | ||||||
| 					(1<<SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) | |  | ||||||
| 					(1<<SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) | |  | ||||||
| 					(1<<SNDRV_PCM_ACCESS_RW_INTERLEAVED) | |  | ||||||
| 					(1<<SNDRV_PCM_ACCESS_RW_NONINTERLEAVED), |  | ||||||
| 					0, 0, 0 } }; |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| #ifdef REFINE_DEBUG |  | ||||||
| 	snd_output_t *log; |  | ||||||
| 	snd_output_stdio_attach(&log, stderr, 0); |  | ||||||
| 	snd_output_puts(log, "DMIX REFINE (begin):\n"); |  | ||||||
| 	snd_pcm_hw_params_dump(params, log); |  | ||||||
| #endif |  | ||||||
| 	if (params->rmask & (1<<SND_PCM_HW_PARAM_ACCESS)) { |  | ||||||
| 		if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS))) { |  | ||||||
| 			SNDERR("dmix access mask empty?"); |  | ||||||
| 			return -EINVAL; |  | ||||||
| 		} |  | ||||||
| 		if (snd_mask_refine(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS), &access)) |  | ||||||
| 			params->cmask |= 1<<SND_PCM_HW_PARAM_ACCESS; |  | ||||||
| 	} |  | ||||||
| 	if (params->rmask & (1<<SND_PCM_HW_PARAM_FORMAT)) { |  | ||||||
| 		if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT))) { |  | ||||||
| 			SNDERR("dmix format mask empty?"); |  | ||||||
| 			return -EINVAL; |  | ||||||
| 		} |  | ||||||
| 		if (snd_mask_refine_set(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT), |  | ||||||
| 				        snd_mask_value(hw_param_mask(hw_params, SND_PCM_HW_PARAM_FORMAT)))) |  | ||||||
| 			params->cmask |= 1<<SND_PCM_HW_PARAM_FORMAT; |  | ||||||
| 	} |  | ||||||
| 	//snd_mask_none(hw_param_mask(params, SND_PCM_HW_PARAM_SUBFORMAT));
 |  | ||||||
| 	if (params->rmask & (1<<SND_PCM_HW_PARAM_CHANNELS)) { |  | ||||||
| 		if (snd_interval_empty(hw_param_interval(params, SND_PCM_HW_PARAM_CHANNELS))) { |  | ||||||
| 			SNDERR("dmix channels mask empty?"); |  | ||||||
| 			return -EINVAL; |  | ||||||
| 		} |  | ||||||
| 		err = snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_CHANNELS), dmix->channels); |  | ||||||
| 		if (err < 0) |  | ||||||
| 			return err; |  | ||||||
| 	} |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_RATE, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_TIME, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIODS, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| #ifdef REFINE_DEBUG |  | ||||||
| 	snd_output_puts(log, "DMIX REFINE (end):\n"); |  | ||||||
| 	snd_pcm_hw_params_dump(params, log); |  | ||||||
| 	snd_output_close(log); |  | ||||||
| #endif |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dmix_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	/* values are cached in the pcm structure */ |  | ||||||
| 	 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dmix_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	/* values are cached in the pcm structure */ |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dmix_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	/* values are cached in the pcm structure */ |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dmix_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) |  | ||||||
| { |  | ||||||
|         return snd_pcm_channel_info_shm(pcm, info, -1); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status) | static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status) | ||||||
| { | { | ||||||
| 	snd_pcm_direct_t *dmix = pcm->private_data; | 	snd_pcm_direct_t *dmix = pcm->private_data; | ||||||
|  | @ -752,16 +578,6 @@ static snd_pcm_sframes_t snd_pcm_dmix_readn(snd_pcm_t *pcm ATTRIBUTE_UNUSED, voi | ||||||
| 	return -ENODEV; | 	return -ENODEV; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int snd_pcm_dmix_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dmix_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dmix_close(snd_pcm_t *pcm) | static int snd_pcm_dmix_close(snd_pcm_t *pcm) | ||||||
| { | { | ||||||
| 	snd_pcm_direct_t *dmix = pcm->private_data; | 	snd_pcm_direct_t *dmix = pcm->private_data; | ||||||
|  | @ -835,18 +651,18 @@ static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out) | ||||||
| 
 | 
 | ||||||
| static snd_pcm_ops_t snd_pcm_dmix_ops = { | static snd_pcm_ops_t snd_pcm_dmix_ops = { | ||||||
| 	.close = snd_pcm_dmix_close, | 	.close = snd_pcm_dmix_close, | ||||||
| 	.info = snd_pcm_dmix_info, | 	.info = snd_pcm_direct_info, | ||||||
| 	.hw_refine = snd_pcm_dmix_hw_refine, | 	.hw_refine = snd_pcm_direct_hw_refine, | ||||||
| 	.hw_params = snd_pcm_dmix_hw_params, | 	.hw_params = snd_pcm_direct_hw_params, | ||||||
| 	.hw_free = snd_pcm_dmix_hw_free, | 	.hw_free = snd_pcm_direct_hw_free, | ||||||
| 	.sw_params = snd_pcm_dmix_sw_params, | 	.sw_params = snd_pcm_direct_sw_params, | ||||||
| 	.channel_info = snd_pcm_dmix_channel_info, | 	.channel_info = snd_pcm_direct_channel_info, | ||||||
| 	.dump = snd_pcm_dmix_dump, | 	.dump = snd_pcm_dmix_dump, | ||||||
| 	.nonblock = snd_pcm_dmix_nonblock, | 	.nonblock = snd_pcm_direct_nonblock, | ||||||
| 	.async = snd_pcm_dmix_async, | 	.async = snd_pcm_direct_async, | ||||||
| 	.poll_revents = snd_pcm_dmix_poll_revents, | 	.poll_revents = snd_pcm_direct_poll_revents, | ||||||
| 	.mmap = snd_pcm_dmix_mmap, | 	.mmap = snd_pcm_direct_mmap, | ||||||
| 	.munmap = snd_pcm_dmix_munmap, | 	.munmap = snd_pcm_direct_munmap, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = { | static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = { | ||||||
|  | @ -999,6 +815,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, | ||||||
| 		spcm->channels = dmix->shmptr->s.channels; | 		spcm->channels = dmix->shmptr->s.channels; | ||||||
| 		spcm->format = dmix->shmptr->s.format; | 		spcm->format = dmix->shmptr->s.format; | ||||||
| 		spcm->boundary = dmix->shmptr->s.boundary; | 		spcm->boundary = dmix->shmptr->s.boundary; | ||||||
|  | 		spcm->info = dmix->shmptr->s.info; | ||||||
| 		ret = snd_pcm_mmap(spcm); | 		ret = snd_pcm_mmap(spcm); | ||||||
| 		if (ret < 0) { | 		if (ret < 0) { | ||||||
| 			SNDERR("unable to mmap channels"); | 			SNDERR("unable to mmap channels"); | ||||||
|  |  | ||||||
|  | @ -163,180 +163,6 @@ static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm) | ||||||
|  *  plugin implementation |  *  plugin implementation | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| static int snd_pcm_dshare_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	/* value is cached for us in pcm->mode (SND_PCM_NONBLOCK flag) */ |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dshare_async(snd_pcm_t *pcm, int sig, pid_t pid) |  | ||||||
| { |  | ||||||
| 	snd_pcm_direct_t *dshare = pcm->private_data; |  | ||||||
| 	return snd_timer_async(dshare->timer, sig, pid); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dshare_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) |  | ||||||
| { |  | ||||||
| 	snd_pcm_direct_t *dshare = pcm->private_data; |  | ||||||
| 	unsigned short events; |  | ||||||
| 	static snd_timer_read_t rbuf[5];	/* can be overwriten by multiple plugins, we don't need the value */ |  | ||||||
| 
 |  | ||||||
| 	assert(pfds && nfds == 1 && revents); |  | ||||||
| 	events = pfds[0].revents; |  | ||||||
| 	if (events & POLLIN) { |  | ||||||
| 		events |= POLLOUT; |  | ||||||
| 		events &= ~POLLIN; |  | ||||||
| 		/* empty the timer read queue */ |  | ||||||
| 		while (snd_timer_read(dshare->timer, &rbuf, sizeof(rbuf)) == sizeof(rbuf)) ; |  | ||||||
| 	} |  | ||||||
| 	*revents = events; |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dshare_info(snd_pcm_t *pcm, snd_pcm_info_t * info) |  | ||||||
| { |  | ||||||
| 	// snd_pcm_direct_t *dshare = pcm->private_data;
 |  | ||||||
| 
 |  | ||||||
| 	memset(info, 0, sizeof(*info)); |  | ||||||
| 	info->stream = pcm->stream; |  | ||||||
| 	info->card = -1; |  | ||||||
| 	/* FIXME: fill this with something more useful: we know the hardware name */ |  | ||||||
| 	if (pcm->name) { |  | ||||||
| 		strncpy(info->id, pcm->name, sizeof(info->id)); |  | ||||||
| 		strncpy(info->name, pcm->name, sizeof(info->name)); |  | ||||||
| 		strncpy(info->subname, pcm->name, sizeof(info->subname)); |  | ||||||
| 	} |  | ||||||
| 	info->subdevices_count = 1; |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params, |  | ||||||
| 					snd_pcm_hw_param_t var) |  | ||||||
| { |  | ||||||
| 	return ¶ms->masks[var - SND_PCM_HW_PARAM_FIRST_MASK]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params, |  | ||||||
| 						snd_pcm_hw_param_t var) |  | ||||||
| { |  | ||||||
| 	return ¶ms->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int hw_param_interval_refine_one(snd_pcm_hw_params_t *params, |  | ||||||
| 					snd_pcm_hw_param_t var, |  | ||||||
| 					snd_pcm_hw_params_t *src) |  | ||||||
| { |  | ||||||
| 	snd_interval_t *i; |  | ||||||
| 
 |  | ||||||
| 	if (!(params->rmask & (1<<var)))	/* nothing to do? */ |  | ||||||
| 		return 0; |  | ||||||
| 	i = hw_param_interval(params, var); |  | ||||||
| 	if (snd_interval_empty(i)) { |  | ||||||
| 		SNDERR("dshare interval %i empty?", (int)var); |  | ||||||
| 		return -EINVAL; |  | ||||||
| 	} |  | ||||||
| 	if (snd_interval_refine(i, hw_param_interval(src, var))) |  | ||||||
| 		params->cmask |= 1<<var; |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #undef REFINE_DEBUG |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dshare_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) |  | ||||||
| { |  | ||||||
| 	snd_pcm_direct_t *dshare = pcm->private_data; |  | ||||||
| 	snd_pcm_hw_params_t *hw_params = &dshare->shmptr->hw_params; |  | ||||||
| 	static snd_mask_t access = { .bits = {  |  | ||||||
| 					(1<<SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) | |  | ||||||
| 					(1<<SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) | |  | ||||||
| 					(1<<SNDRV_PCM_ACCESS_RW_INTERLEAVED) | |  | ||||||
| 					(1<<SNDRV_PCM_ACCESS_RW_NONINTERLEAVED), |  | ||||||
| 					0, 0, 0 } }; |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| #ifdef REFINE_DEBUG |  | ||||||
| 	snd_output_t *log; |  | ||||||
| 	snd_output_stdio_attach(&log, stderr, 0); |  | ||||||
| 	snd_output_puts(log, "DMIX REFINE (begin):\n"); |  | ||||||
| 	snd_pcm_hw_params_dump(params, log); |  | ||||||
| #endif |  | ||||||
| 	if (params->rmask & (1<<SND_PCM_HW_PARAM_ACCESS)) { |  | ||||||
| 		if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS))) { |  | ||||||
| 			SNDERR("dshare access mask empty?"); |  | ||||||
| 			return -EINVAL; |  | ||||||
| 		} |  | ||||||
| 		if (snd_mask_refine(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS), &access)) |  | ||||||
| 			params->cmask |= 1<<SND_PCM_HW_PARAM_ACCESS; |  | ||||||
| 	} |  | ||||||
| 	if (params->rmask & (1<<SND_PCM_HW_PARAM_FORMAT)) { |  | ||||||
| 		if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT))) { |  | ||||||
| 			SNDERR("dshare format mask empty?"); |  | ||||||
| 			return -EINVAL; |  | ||||||
| 		} |  | ||||||
| 		if (snd_mask_refine_set(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT), |  | ||||||
| 				        snd_mask_value(hw_param_mask(hw_params, SND_PCM_HW_PARAM_FORMAT)))) |  | ||||||
| 			params->cmask |= 1<<SND_PCM_HW_PARAM_FORMAT; |  | ||||||
| 	} |  | ||||||
| 	//snd_mask_none(hw_param_mask(params, SND_PCM_HW_PARAM_SUBFORMAT));
 |  | ||||||
| 	if (params->rmask & (1<<SND_PCM_HW_PARAM_CHANNELS)) { |  | ||||||
| 		if (snd_interval_empty(hw_param_interval(params, SND_PCM_HW_PARAM_CHANNELS))) { |  | ||||||
| 			SNDERR("dshare channels mask empty?"); |  | ||||||
| 			return -EINVAL; |  | ||||||
| 		} |  | ||||||
| 		err = snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_CHANNELS), dshare->channels); |  | ||||||
| 		if (err < 0) |  | ||||||
| 			return err; |  | ||||||
| 	} |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_RATE, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_TIME, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIODS, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| #ifdef REFINE_DEBUG |  | ||||||
| 	snd_output_puts(log, "DMIX REFINE (end):\n"); |  | ||||||
| 	snd_pcm_hw_params_dump(params, log); |  | ||||||
| 	snd_output_close(log); |  | ||||||
| #endif |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dshare_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	/* values are cached in the pcm structure */ |  | ||||||
| 	 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dshare_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	/* values are cached in the pcm structure */ |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dshare_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	/* values are cached in the pcm structure */ |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dshare_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) |  | ||||||
| { |  | ||||||
|         return snd_pcm_channel_info_shm(pcm, info, -1); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status) | static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status) | ||||||
| { | { | ||||||
| 	snd_pcm_direct_t *dshare = pcm->private_data; | 	snd_pcm_direct_t *dshare = pcm->private_data; | ||||||
|  | @ -541,16 +367,6 @@ static snd_pcm_sframes_t snd_pcm_dshare_readn(snd_pcm_t *pcm ATTRIBUTE_UNUSED, v | ||||||
| 	return -ENODEV; | 	return -ENODEV; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int snd_pcm_dshare_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dshare_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dshare_close(snd_pcm_t *pcm) | static int snd_pcm_dshare_close(snd_pcm_t *pcm) | ||||||
| { | { | ||||||
| 	snd_pcm_direct_t *dshare = pcm->private_data; | 	snd_pcm_direct_t *dshare = pcm->private_data; | ||||||
|  | @ -625,18 +441,18 @@ static void snd_pcm_dshare_dump(snd_pcm_t *pcm, snd_output_t *out) | ||||||
| 
 | 
 | ||||||
| static snd_pcm_ops_t snd_pcm_dshare_ops = { | static snd_pcm_ops_t snd_pcm_dshare_ops = { | ||||||
| 	.close = snd_pcm_dshare_close, | 	.close = snd_pcm_dshare_close, | ||||||
| 	.info = snd_pcm_dshare_info, | 	.info = snd_pcm_direct_info, | ||||||
| 	.hw_refine = snd_pcm_dshare_hw_refine, | 	.hw_refine = snd_pcm_direct_hw_refine, | ||||||
| 	.hw_params = snd_pcm_dshare_hw_params, | 	.hw_params = snd_pcm_direct_hw_params, | ||||||
| 	.hw_free = snd_pcm_dshare_hw_free, | 	.hw_free = snd_pcm_direct_hw_free, | ||||||
| 	.sw_params = snd_pcm_dshare_sw_params, | 	.sw_params = snd_pcm_direct_sw_params, | ||||||
| 	.channel_info = snd_pcm_dshare_channel_info, | 	.channel_info = snd_pcm_direct_channel_info, | ||||||
| 	.dump = snd_pcm_dshare_dump, | 	.dump = snd_pcm_dshare_dump, | ||||||
| 	.nonblock = snd_pcm_dshare_nonblock, | 	.nonblock = snd_pcm_direct_nonblock, | ||||||
| 	.async = snd_pcm_dshare_async, | 	.async = snd_pcm_direct_async, | ||||||
| 	.poll_revents = snd_pcm_dshare_poll_revents, | 	.poll_revents = snd_pcm_direct_poll_revents, | ||||||
| 	.mmap = snd_pcm_dshare_mmap, | 	.mmap = snd_pcm_direct_mmap, | ||||||
| 	.munmap = snd_pcm_dshare_munmap, | 	.munmap = snd_pcm_direct_munmap, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = { | static snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = { | ||||||
|  | @ -794,6 +610,7 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, | ||||||
| 		spcm->channels = dshare->shmptr->s.channels; | 		spcm->channels = dshare->shmptr->s.channels; | ||||||
| 		spcm->format = dshare->shmptr->s.format; | 		spcm->format = dshare->shmptr->s.format; | ||||||
| 		spcm->boundary = dshare->shmptr->s.boundary; | 		spcm->boundary = dshare->shmptr->s.boundary; | ||||||
|  | 		spcm->info = dshare->shmptr->s.info; | ||||||
| 		ret = snd_pcm_mmap(spcm); | 		ret = snd_pcm_mmap(spcm); | ||||||
| 		if (ret < 0) { | 		if (ret < 0) { | ||||||
| 			SNDERR("unable to mmap channels"); | 			SNDERR("unable to mmap channels"); | ||||||
|  |  | ||||||
|  | @ -146,180 +146,6 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm) | ||||||
|  *  plugin implementation |  *  plugin implementation | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| static int snd_pcm_dsnoop_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	/* value is cached for us in pcm->mode (SND_PCM_NONBLOCK flag) */ |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dsnoop_async(snd_pcm_t *pcm, int sig, pid_t pid) |  | ||||||
| { |  | ||||||
| 	snd_pcm_direct_t *dsnoop = pcm->private_data; |  | ||||||
| 	return snd_timer_async(dsnoop->timer, sig, pid); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dsnoop_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) |  | ||||||
| { |  | ||||||
| 	snd_pcm_direct_t *dsnoop = pcm->private_data; |  | ||||||
| 	unsigned short events; |  | ||||||
| 	static snd_timer_read_t rbuf[5];	/* can be overwriten by multiple plugins, we don't need the value */ |  | ||||||
| 
 |  | ||||||
| 	assert(pfds && nfds == 1 && revents); |  | ||||||
| 	events = pfds[0].revents; |  | ||||||
| 	if (events & POLLIN) { |  | ||||||
| 		events |= POLLOUT; |  | ||||||
| 		events &= ~POLLIN; |  | ||||||
| 		/* empty the timer read queue */ |  | ||||||
| 		while (snd_timer_read(dsnoop->timer, &rbuf, sizeof(rbuf)) == sizeof(rbuf)) ; |  | ||||||
| 	} |  | ||||||
| 	*revents = events; |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dsnoop_info(snd_pcm_t *pcm, snd_pcm_info_t * info) |  | ||||||
| { |  | ||||||
| 	// snd_pcm_direct_t *dsnoop = pcm->private_data;
 |  | ||||||
| 
 |  | ||||||
| 	memset(info, 0, sizeof(*info)); |  | ||||||
| 	info->stream = pcm->stream; |  | ||||||
| 	info->card = -1; |  | ||||||
| 	/* FIXME: fill this with something more useful: we know the hardware name */ |  | ||||||
| 	if (pcm->name) { |  | ||||||
| 		strncpy(info->id, pcm->name, sizeof(info->id)); |  | ||||||
| 		strncpy(info->name, pcm->name, sizeof(info->name)); |  | ||||||
| 		strncpy(info->subname, pcm->name, sizeof(info->subname)); |  | ||||||
| 	} |  | ||||||
| 	info->subdevices_count = 1; |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params, |  | ||||||
| 					snd_pcm_hw_param_t var) |  | ||||||
| { |  | ||||||
| 	return ¶ms->masks[var - SND_PCM_HW_PARAM_FIRST_MASK]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params, |  | ||||||
| 						snd_pcm_hw_param_t var) |  | ||||||
| { |  | ||||||
| 	return ¶ms->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int hw_param_interval_refine_one(snd_pcm_hw_params_t *params, |  | ||||||
| 					snd_pcm_hw_param_t var, |  | ||||||
| 					snd_pcm_hw_params_t *src) |  | ||||||
| { |  | ||||||
| 	snd_interval_t *i; |  | ||||||
| 
 |  | ||||||
| 	if (!(params->rmask & (1<<var)))	/* nothing to do? */ |  | ||||||
| 		return 0; |  | ||||||
| 	i = hw_param_interval(params, var); |  | ||||||
| 	if (snd_interval_empty(i)) { |  | ||||||
| 		SNDERR("dsnoop interval %i empty?", (int)var); |  | ||||||
| 		return -EINVAL; |  | ||||||
| 	} |  | ||||||
| 	if (snd_interval_refine(i, hw_param_interval(src, var))) |  | ||||||
| 		params->cmask |= 1<<var; |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #undef REFINE_DEBUG |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dsnoop_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) |  | ||||||
| { |  | ||||||
| 	snd_pcm_direct_t *dsnoop = pcm->private_data; |  | ||||||
| 	snd_pcm_hw_params_t *hw_params = &dsnoop->shmptr->hw_params; |  | ||||||
| 	static snd_mask_t access = { .bits = {  |  | ||||||
| 					(1<<SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) | |  | ||||||
| 					(1<<SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) | |  | ||||||
| 					(1<<SNDRV_PCM_ACCESS_RW_INTERLEAVED) | |  | ||||||
| 					(1<<SNDRV_PCM_ACCESS_RW_NONINTERLEAVED), |  | ||||||
| 					0, 0, 0 } }; |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| #ifdef REFINE_DEBUG |  | ||||||
| 	snd_output_t *log; |  | ||||||
| 	snd_output_stdio_attach(&log, stderr, 0); |  | ||||||
| 	snd_output_puts(log, "DMIX REFINE (begin):\n"); |  | ||||||
| 	snd_pcm_hw_params_dump(params, log); |  | ||||||
| #endif |  | ||||||
| 	if (params->rmask & (1<<SND_PCM_HW_PARAM_ACCESS)) { |  | ||||||
| 		if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS))) { |  | ||||||
| 			SNDERR("dsnoop access mask empty?"); |  | ||||||
| 			return -EINVAL; |  | ||||||
| 		} |  | ||||||
| 		if (snd_mask_refine(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS), &access)) |  | ||||||
| 			params->cmask |= 1<<SND_PCM_HW_PARAM_ACCESS; |  | ||||||
| 	} |  | ||||||
| 	if (params->rmask & (1<<SND_PCM_HW_PARAM_FORMAT)) { |  | ||||||
| 		if (snd_mask_empty(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT))) { |  | ||||||
| 			SNDERR("dsnoop format mask empty?"); |  | ||||||
| 			return -EINVAL; |  | ||||||
| 		} |  | ||||||
| 		if (snd_mask_refine_set(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT), |  | ||||||
| 				        snd_mask_value(hw_param_mask(hw_params, SND_PCM_HW_PARAM_FORMAT)))) |  | ||||||
| 			params->cmask |= 1<<SND_PCM_HW_PARAM_FORMAT; |  | ||||||
| 	} |  | ||||||
| 	//snd_mask_none(hw_param_mask(params, SND_PCM_HW_PARAM_SUBFORMAT));
 |  | ||||||
| 	if (params->rmask & (1<<SND_PCM_HW_PARAM_CHANNELS)) { |  | ||||||
| 		if (snd_interval_empty(hw_param_interval(params, SND_PCM_HW_PARAM_CHANNELS))) { |  | ||||||
| 			SNDERR("dsnoop channels mask empty?"); |  | ||||||
| 			return -EINVAL; |  | ||||||
| 		} |  | ||||||
| 		err = snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_CHANNELS), dsnoop->channels); |  | ||||||
| 		if (err < 0) |  | ||||||
| 			return err; |  | ||||||
| 	} |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_RATE, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_TIME, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| 	err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIODS, hw_params); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
| #ifdef REFINE_DEBUG |  | ||||||
| 	snd_output_puts(log, "DMIX REFINE (end):\n"); |  | ||||||
| 	snd_pcm_hw_params_dump(params, log); |  | ||||||
| 	snd_output_close(log); |  | ||||||
| #endif |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dsnoop_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	/* values are cached in the pcm structure */ |  | ||||||
| 	 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dsnoop_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	/* values are cached in the pcm structure */ |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dsnoop_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	/* values are cached in the pcm structure */ |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dsnoop_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) |  | ||||||
| { |  | ||||||
|         return snd_pcm_channel_info_shm(pcm, info, -1); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status) | static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status) | ||||||
| { | { | ||||||
| 	snd_pcm_direct_t *dsnoop = pcm->private_data; | 	snd_pcm_direct_t *dsnoop = pcm->private_data; | ||||||
|  | @ -514,16 +340,6 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_writen(snd_pcm_t *pcm ATTRIBUTE_UNUSED, | ||||||
| 	return -ENODEV; | 	return -ENODEV; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int snd_pcm_dsnoop_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dsnoop_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) |  | ||||||
| { |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int snd_pcm_dsnoop_close(snd_pcm_t *pcm) | static int snd_pcm_dsnoop_close(snd_pcm_t *pcm) | ||||||
| { | { | ||||||
| 	snd_pcm_direct_t *dsnoop = pcm->private_data; | 	snd_pcm_direct_t *dsnoop = pcm->private_data; | ||||||
|  | @ -593,18 +409,18 @@ static void snd_pcm_dsnoop_dump(snd_pcm_t *pcm, snd_output_t *out) | ||||||
| 
 | 
 | ||||||
| static snd_pcm_ops_t snd_pcm_dsnoop_ops = { | static snd_pcm_ops_t snd_pcm_dsnoop_ops = { | ||||||
| 	.close = snd_pcm_dsnoop_close, | 	.close = snd_pcm_dsnoop_close, | ||||||
| 	.info = snd_pcm_dsnoop_info, | 	.info = snd_pcm_direct_info, | ||||||
| 	.hw_refine = snd_pcm_dsnoop_hw_refine, | 	.hw_refine = snd_pcm_direct_hw_refine, | ||||||
| 	.hw_params = snd_pcm_dsnoop_hw_params, | 	.hw_params = snd_pcm_direct_hw_params, | ||||||
| 	.hw_free = snd_pcm_dsnoop_hw_free, | 	.hw_free = snd_pcm_direct_hw_free, | ||||||
| 	.sw_params = snd_pcm_dsnoop_sw_params, | 	.sw_params = snd_pcm_direct_sw_params, | ||||||
| 	.channel_info = snd_pcm_dsnoop_channel_info, | 	.channel_info = snd_pcm_direct_channel_info, | ||||||
| 	.dump = snd_pcm_dsnoop_dump, | 	.dump = snd_pcm_dsnoop_dump, | ||||||
| 	.nonblock = snd_pcm_dsnoop_nonblock, | 	.nonblock = snd_pcm_direct_nonblock, | ||||||
| 	.async = snd_pcm_dsnoop_async, | 	.async = snd_pcm_direct_async, | ||||||
| 	.poll_revents = snd_pcm_dsnoop_poll_revents, | 	.poll_revents = snd_pcm_direct_poll_revents, | ||||||
| 	.mmap = snd_pcm_dsnoop_mmap, | 	.mmap = snd_pcm_direct_mmap, | ||||||
| 	.munmap = snd_pcm_dsnoop_munmap, | 	.munmap = snd_pcm_direct_munmap, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = { | static snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = { | ||||||
|  | @ -754,6 +570,7 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, | ||||||
| 		spcm->channels = dsnoop->shmptr->s.channels; | 		spcm->channels = dsnoop->shmptr->s.channels; | ||||||
| 		spcm->format = dsnoop->shmptr->s.format; | 		spcm->format = dsnoop->shmptr->s.format; | ||||||
| 		spcm->boundary = dsnoop->shmptr->s.boundary; | 		spcm->boundary = dsnoop->shmptr->s.boundary; | ||||||
|  | 		spcm->info = dsnoop->shmptr->s.info; | ||||||
| 		ret = snd_pcm_mmap(spcm); | 		ret = snd_pcm_mmap(spcm); | ||||||
| 		if (ret < 0) { | 		if (ret < 0) { | ||||||
| 			SNDERR("unable to mmap channels"); | 			SNDERR("unable to mmap channels"); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jaroslav Kysela
						Jaroslav Kysela