[alsa-devel] [PATCH v2 1/3] ALSA: core: keep track of boundary wrap-around

Takashi Iwai tiwai at suse.de
Tue Oct 9 11:37:21 CEST 2012


At Mon,  8 Oct 2012 12:11:56 -0500,
Pierre-Louis Bossart wrote:
> 
> Keep track of boundary crossing when hw_ptr
> exceeds boundary limit and wraps-around. This
> will help keep track of total number
> of frames played/received at the kernel level
> 
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
> ---
>  include/sound/pcm.h  |    1 +
>  sound/core/pcm_lib.c |   26 +++++++++++++++++++++-----
>  2 files changed, 22 insertions(+), 5 deletions(-)
> 
> diff --git a/include/sound/pcm.h b/include/sound/pcm.h
> index cdca2ab..ba13e0b 100644
> --- a/include/sound/pcm.h
> +++ b/include/sound/pcm.h
> @@ -281,6 +281,7 @@ struct snd_pcm_runtime {
>  	unsigned long hw_ptr_jiffies;	/* Time when hw_ptr is updated */
>  	unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */
>  	snd_pcm_sframes_t delay;	/* extra delay; typically FIFO size */
> +	u64 hw_ptr_wrap;                /* offset for hw_ptr due to boundary wrap-around */
>  
>  	/* -- HW params -- */
>  	snd_pcm_access_t access;	/* access mode */
> diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
> index 7ae6719..ec996ca 100644
> --- a/sound/core/pcm_lib.c
> +++ b/sound/core/pcm_lib.c
> @@ -315,6 +315,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
>  	unsigned long jdelta;
>  	unsigned long curr_jiffies;
>  	struct timespec curr_tstamp;
> +	int crossed_boundary = 0;
>  
>  	old_hw_ptr = runtime->status->hw_ptr;
>  
> @@ -359,8 +360,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
>  			hdelta = curr_jiffies - runtime->hw_ptr_jiffies;
>  			if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
>  				hw_base += runtime->buffer_size;
> -				if (hw_base >= runtime->boundary)
> +				if (hw_base >= runtime->boundary) {
>  					hw_base = 0;
> +					crossed_boundary++;
> +				}
>  				new_hw_ptr = hw_base + pos;
>  				goto __delta;
>  			}
> @@ -370,8 +373,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
>  	/* pointer crosses the end of the ring buffer */
>  	if (new_hw_ptr < old_hw_ptr) {
>  		hw_base += runtime->buffer_size;
> -		if (hw_base >= runtime->boundary)
> +		if (hw_base >= runtime->boundary) {
>  			hw_base = 0;
> +			crossed_boundary++;
> +		}
>  		new_hw_ptr = hw_base + pos;
>  	}
>        __delta:
> @@ -409,8 +414,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
>  		while (hdelta > xrun_threshold) {
>  			delta += runtime->buffer_size;
>  			hw_base += runtime->buffer_size;
> -			if (hw_base >= runtime->boundary)
> +			if (hw_base >= runtime->boundary) {
>  				hw_base = 0;
> +				crossed_boundary++;
> +			}
>  			new_hw_ptr = hw_base + pos;
>  			hdelta -= runtime->hw_ptr_buffer_jiffies;
>  		}
> @@ -455,8 +462,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
>  		/* the delta value is small or zero in most cases */
>  		while (delta > 0) {
>  			new_hw_ptr += runtime->period_size;
> -			if (new_hw_ptr >= runtime->boundary)
> +			if (new_hw_ptr >= runtime->boundary) {
>  				new_hw_ptr -= runtime->boundary;
> +				crossed_boundary--;
> +			}
>  			delta--;
>  		}
>  		/* align hw_base to buffer_size */
> @@ -506,6 +515,11 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
>  	runtime->hw_ptr_base = hw_base;
>  	runtime->status->hw_ptr = new_hw_ptr;
>  	runtime->hw_ptr_jiffies = curr_jiffies;
> +	if (crossed_boundary) {
> +		BUG_ON(crossed_boundary > 1);
> +		BUG_ON(crossed_boundary < 0);

BUG_ON() is too hard for such sanity checks, since it leads to a
kernel panic without recovery.  Better to use WARN_ON() or
snd_BUG_ON()
		snd_BUG_ON(crossed_boundary != 1);


Takashi

> +		runtime->hw_ptr_wrap += runtime->boundary;
> +	}
>  	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
>  		runtime->status->tstamp = curr_tstamp;
>  
> @@ -1660,8 +1674,10 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
>  	if (snd_pcm_running(substream) &&
>  	    snd_pcm_update_hw_ptr(substream) >= 0)
>  		runtime->status->hw_ptr %= runtime->buffer_size;
> -	else
> +	else {
>  		runtime->status->hw_ptr = 0;
> +		runtime->hw_ptr_wrap = 0;
> +	}
>  	snd_pcm_stream_unlock_irqrestore(substream, flags);
>  	return 0;
>  }
> -- 
> 1.7.9.5
> 
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> 


More information about the Alsa-devel mailing list