mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	pcm: direct: check state before enter poll on timer
To avoid the chances of timeout, we need to check the enter poll in state xrun. Signed-off-by: Andreas Pape <apape@de.adit-jv.com> Signed-off-by: Mounesh Sutar <mounesh_sutar@mentor.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
		
							parent
							
								
									1a9bd0f044
								
							
						
					
					
						commit
						789ee39727
					
				
					 5 changed files with 63 additions and 6 deletions
				
			
		| 
						 | 
					@ -645,6 +645,46 @@ int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This is the only operation guaranteed to be called before entering poll().
 | 
				
			||||||
 | 
					 * Direct plugins use fd of snd_timer to poll on, these timers do NOT check
 | 
				
			||||||
 | 
					 * state of substream in kernel by intention.
 | 
				
			||||||
 | 
					 * Only the enter to xrun might be notified once (SND_TIMER_EVENT_MSTOP).
 | 
				
			||||||
 | 
					 * If xrun event was not correctly handled or was ignored it will never be
 | 
				
			||||||
 | 
					 * evaluated again afterwards.
 | 
				
			||||||
 | 
					 * This will result in snd_pcm_wait() always returning timeout.
 | 
				
			||||||
 | 
					 * In contrast poll() on pcm hardware checks ALSA state and will immediately
 | 
				
			||||||
 | 
					 * return POLLERR on XRUN.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * To prevent timeout and applications endlessly spinning without xrun
 | 
				
			||||||
 | 
					 * detected we add a state check here which may trigger the xrun sequence.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * return count of filled descriptors or negative error code
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds,
 | 
				
			||||||
 | 
									    unsigned int space)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (pcm->poll_fd < 0) {
 | 
				
			||||||
 | 
							SNDMSG("poll_fd < 0");
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (space >= 1 && pfds) {
 | 
				
			||||||
 | 
							pfds->fd = pcm->poll_fd;
 | 
				
			||||||
 | 
							pfds->events = pcm->poll_events | POLLERR | POLLNVAL;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* this will also evaluate slave state and enter xrun if necessary */
 | 
				
			||||||
 | 
						switch (snd_pcm_state(pcm)) {
 | 
				
			||||||
 | 
						case SND_PCM_STATE_XRUN:
 | 
				
			||||||
 | 
							return -EPIPE;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
 | 
					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;
 | 
						snd_pcm_direct_t *dmix = pcm->private_data;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -307,6 +307,8 @@ int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix,
 | 
				
			||||||
				  snd_config_t *cfg);
 | 
									  snd_config_t *cfg);
 | 
				
			||||||
int snd_pcm_direct_nonblock(snd_pcm_t *pcm, int nonblock);
 | 
					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_async(snd_pcm_t *pcm, int sig, pid_t pid);
 | 
				
			||||||
 | 
					int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds,
 | 
				
			||||||
 | 
									    unsigned int space);
 | 
				
			||||||
int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
 | 
					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_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_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -462,17 +462,22 @@ static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
 | 
				
			||||||
static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
 | 
					static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_direct_t *dmix = pcm->private_data;
 | 
						snd_pcm_direct_t *dmix = pcm->private_data;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
	snd_pcm_state_t state;
 | 
						snd_pcm_state_t state;
 | 
				
			||||||
	state = snd_pcm_state(dmix->spcm);
 | 
						state = snd_pcm_state(dmix->spcm);
 | 
				
			||||||
	switch (state) {
 | 
						switch (state) {
 | 
				
			||||||
	case SND_PCM_STATE_XRUN:
 | 
					 | 
				
			||||||
	case SND_PCM_STATE_SUSPENDED:
 | 
						case SND_PCM_STATE_SUSPENDED:
 | 
				
			||||||
	case SND_PCM_STATE_DISCONNECTED:
 | 
						case SND_PCM_STATE_DISCONNECTED:
 | 
				
			||||||
		dmix->state = state;
 | 
							dmix->state = state;
 | 
				
			||||||
		return state;
 | 
							return state;
 | 
				
			||||||
 | 
						case SND_PCM_STATE_XRUN:
 | 
				
			||||||
 | 
							if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						snd_pcm_direct_client_chk_xrun(dmix, pcm);
 | 
				
			||||||
	if (dmix->state == STATE_RUN_PENDING)
 | 
						if (dmix->state == STATE_RUN_PENDING)
 | 
				
			||||||
		return SNDRV_PCM_STATE_RUNNING;
 | 
							return SNDRV_PCM_STATE_RUNNING;
 | 
				
			||||||
	return dmix->state;
 | 
						return dmix->state;
 | 
				
			||||||
| 
						 | 
					@ -968,7 +973,7 @@ static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
 | 
				
			||||||
	.avail_update = snd_pcm_dmix_avail_update,
 | 
						.avail_update = snd_pcm_dmix_avail_update,
 | 
				
			||||||
	.mmap_commit = snd_pcm_dmix_mmap_commit,
 | 
						.mmap_commit = snd_pcm_dmix_mmap_commit,
 | 
				
			||||||
	.htimestamp = snd_pcm_dmix_htimestamp,
 | 
						.htimestamp = snd_pcm_dmix_htimestamp,
 | 
				
			||||||
	.poll_descriptors = NULL,
 | 
						.poll_descriptors = snd_pcm_direct_poll_descriptors,
 | 
				
			||||||
	.poll_descriptors_count = NULL,
 | 
						.poll_descriptors_count = NULL,
 | 
				
			||||||
	.poll_revents = snd_pcm_dmix_poll_revents,
 | 
						.poll_revents = snd_pcm_dmix_poll_revents,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -255,17 +255,22 @@ static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 | 
				
			||||||
static snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm)
 | 
					static snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_direct_t *dshare = pcm->private_data;
 | 
						snd_pcm_direct_t *dshare = pcm->private_data;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
	snd_pcm_state_t state;
 | 
						snd_pcm_state_t state;
 | 
				
			||||||
	state = snd_pcm_state(dshare->spcm);
 | 
						state = snd_pcm_state(dshare->spcm);
 | 
				
			||||||
	switch (state) {
 | 
						switch (state) {
 | 
				
			||||||
	case SND_PCM_STATE_XRUN:
 | 
					 | 
				
			||||||
	case SND_PCM_STATE_SUSPENDED:
 | 
						case SND_PCM_STATE_SUSPENDED:
 | 
				
			||||||
	case SND_PCM_STATE_DISCONNECTED:
 | 
						case SND_PCM_STATE_DISCONNECTED:
 | 
				
			||||||
		dshare->state = state;
 | 
							dshare->state = state;
 | 
				
			||||||
		return state;
 | 
							return state;
 | 
				
			||||||
 | 
						case SND_PCM_STATE_XRUN:
 | 
				
			||||||
 | 
							if ((err = snd_pcm_direct_slave_recover(dshare)) < 0)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						snd_pcm_direct_client_chk_xrun(dshare, pcm);
 | 
				
			||||||
	if (dshare->state == STATE_RUN_PENDING)
 | 
						if (dshare->state == STATE_RUN_PENDING)
 | 
				
			||||||
		return SNDRV_PCM_STATE_RUNNING;
 | 
							return SNDRV_PCM_STATE_RUNNING;
 | 
				
			||||||
	return dshare->state;
 | 
						return dshare->state;
 | 
				
			||||||
| 
						 | 
					@ -646,7 +651,7 @@ static const snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = {
 | 
				
			||||||
	.avail_update = snd_pcm_dshare_avail_update,
 | 
						.avail_update = snd_pcm_dshare_avail_update,
 | 
				
			||||||
	.mmap_commit = snd_pcm_dshare_mmap_commit,
 | 
						.mmap_commit = snd_pcm_dshare_mmap_commit,
 | 
				
			||||||
	.htimestamp = snd_pcm_dshare_htimestamp,
 | 
						.htimestamp = snd_pcm_dshare_htimestamp,
 | 
				
			||||||
	.poll_descriptors = NULL,
 | 
						.poll_descriptors = snd_pcm_direct_poll_descriptors,
 | 
				
			||||||
	.poll_descriptors_count = NULL,
 | 
						.poll_descriptors_count = NULL,
 | 
				
			||||||
	.poll_revents = snd_pcm_direct_poll_revents,
 | 
						.poll_revents = snd_pcm_direct_poll_revents,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -208,17 +208,22 @@ static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 | 
				
			||||||
static snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm)
 | 
					static snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_direct_t *dsnoop = pcm->private_data;
 | 
						snd_pcm_direct_t *dsnoop = pcm->private_data;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
	snd_pcm_state_t state;
 | 
						snd_pcm_state_t state;
 | 
				
			||||||
	state = snd_pcm_state(dsnoop->spcm);
 | 
						state = snd_pcm_state(dsnoop->spcm);
 | 
				
			||||||
	switch (state) {
 | 
						switch (state) {
 | 
				
			||||||
	case SND_PCM_STATE_XRUN:
 | 
					 | 
				
			||||||
	case SND_PCM_STATE_SUSPENDED:
 | 
						case SND_PCM_STATE_SUSPENDED:
 | 
				
			||||||
	case SND_PCM_STATE_DISCONNECTED:
 | 
						case SND_PCM_STATE_DISCONNECTED:
 | 
				
			||||||
		dsnoop->state = state;
 | 
							dsnoop->state = state;
 | 
				
			||||||
		return state;
 | 
							return state;
 | 
				
			||||||
 | 
						case SND_PCM_STATE_XRUN:
 | 
				
			||||||
 | 
							if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						snd_pcm_direct_client_chk_xrun(dsnoop, pcm);
 | 
				
			||||||
	return dsnoop->state;
 | 
						return dsnoop->state;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -531,7 +536,7 @@ static const snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
 | 
				
			||||||
	.avail_update = snd_pcm_dsnoop_avail_update,
 | 
						.avail_update = snd_pcm_dsnoop_avail_update,
 | 
				
			||||||
	.mmap_commit = snd_pcm_dsnoop_mmap_commit,
 | 
						.mmap_commit = snd_pcm_dsnoop_mmap_commit,
 | 
				
			||||||
	.htimestamp = snd_pcm_dsnoop_htimestamp,
 | 
						.htimestamp = snd_pcm_dsnoop_htimestamp,
 | 
				
			||||||
	.poll_descriptors = NULL,
 | 
						.poll_descriptors = snd_pcm_direct_poll_descriptors,
 | 
				
			||||||
	.poll_descriptors_count = NULL,
 | 
						.poll_descriptors_count = NULL,
 | 
				
			||||||
	.poll_revents = snd_pcm_direct_poll_revents,
 | 
						.poll_revents = snd_pcm_direct_poll_revents,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue