[Sound-open-firmware] [PATCH] dai: xrun: dont stop and restart DAI on XRUN recovery

Pierre-Louis Bossart pierre-louis.bossart at linux.intel.com
Fri Nov 17 15:35:34 CET 2017


On 11/16/17 4:01 PM, Liam Girdwood wrote:
> WiP: The DAI should not be stopped and the restarted on XRUNs

Are you sure about this one? if you have an xrun leading to a channel 
swap, that's not something you could ever recover from?

> 
> Signed-off-by: Liam Girdwood <liam.r.girdwood at linux.intel.com>
> ---
>   src/audio/dai.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++------
>   1 file changed, 48 insertions(+), 6 deletions(-)
> 
> diff --git a/src/audio/dai.c b/src/audio/dai.c
> index afa4aa2..13f7e10 100644
> --- a/src/audio/dai.c
> +++ b/src/audio/dai.c
> @@ -63,6 +63,7 @@ struct dai_data {
>   	struct dma *dma;
>   	uint32_t period_bytes;
>   	completion_t complete;
> +	int xrun;		/* true if we are doing xrun recovery */
>   
>   	uint32_t last_bytes;    /* the last bytes(<period size) it copies. */
>   	uint32_t dai_pos_blks;	/* position in bytes (nearest block) */
> @@ -83,8 +84,8 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
>   
>   	tracev_dai("irq");
>   
> -	/* is stream stopped or paused ? */
> -	if (dev->state != COMP_STATE_ACTIVE) {
> +	/* is stream stopped or paused and we are not handling XRUN ? */
> +	if (dev->state != COMP_STATE_ACTIVE && dd->xrun == 0) {
>   
>   		/* stop the DAI */
>   		dai_trigger(dd->dai, COMP_CMD_STOP, dev->params.direction);
> @@ -97,6 +98,28 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
>   		return;
>   	}
>   
> +	/* is our pipeline handling an XRUN ? */
> +	if (dd->xrun) {
> +
> +		/* make sure we only playback silence during an XRUN */
> +		if (dev->params.direction == SOF_IPC_STREAM_PLAYBACK) {
> +
> +			dma_buffer = list_first_item(&dev->bsource_list,
> +				struct comp_buffer, sink_list);
> +
> +			/* fill buffer with silence */
> +			bzero(dma_buffer->addr, dma_buffer->size);
> +
> +			/* writeback buffer contents from cache */
> +			dcache_writeback_region(dma_buffer->addr,
> +				dma_buffer->size);
> +		}
> +
> +		/* inform waiters */
> +		wait_completed(&dd->complete);
> +		return;
> +	}
> +
>   	if (dev->params.direction == SOF_IPC_STREAM_PLAYBACK) {
>   		dma_buffer = list_first_item(&dev->bsource_list,
>   			struct comp_buffer, sink_list);
> @@ -195,6 +218,7 @@ static struct comp_dev *dai_new(struct sof_ipc_comp *comp)
>   	dd->dai_pos = NULL;
>   	dd->dai_pos_blks = 0;
>   	dd->last_bytes = 0;
> +	dd->xrun = 0;
>   
>   	/* get DMA channel from DMAC1 */
>   	dd->chan = dma_channel_get(dd->dma);
> @@ -423,9 +447,16 @@ static int dai_prepare(struct comp_dev *dev)
>   		dma_buffer = list_first_item(&dev->bsource_list,
>   			struct comp_buffer, sink_list);
>   
> +		/* fill playback periods with silence */
> +		bzero(dma_buffer->r_ptr, dma_buffer->avail);
> +
>   		dcache_writeback_region(dma_buffer->r_ptr, dma_buffer->avail);
>   	}
>   
> +	/* dma reconfig not required if XRUN handling */
> +	if (dd->xrun)
> +		return ret;
> +
>   	ret = dma_set_config(dd->dma, dd->chan, &dd->config);
>   	if (ret < 0)
>   		comp_set_state(dev, COMP_CMD_RESET);
> @@ -456,6 +487,7 @@ static int dai_reset(struct comp_dev *dev)
>   	dd->last_bytes = 0;
>   	dd->wallclock = 0;
>   	dev->position = 0;
> +	dd->xrun = 0;
>   	comp_set_state(dev, COMP_CMD_RESET);
>   
>   	return 0;
> @@ -479,14 +511,24 @@ static int dai_cmd(struct comp_dev *dev, int cmd, void *data)
>   	switch (cmd) {
>   	case COMP_CMD_RELEASE:
>   	case COMP_CMD_START:
> -		ret = dma_start(dd->dma, dd->chan);
> -		if (ret < 0)
> -			return ret;
> -		dai_trigger(dd->dai, cmd, dev->params.direction);
> +
> +		/* only start the DAI if we are not XRUN handling */
> +		if (dd->xrun == 0) {
> +
> +			/* start the DAI */
> +			ret = dma_start(dd->dma, dd->chan);
> +			if (ret < 0)
> +				return ret;
> +			dai_trigger(dd->dai, cmd, dev->params.direction);
> +		} else {
> +			dd->xrun = 0;
> +		}
>   
>   		/* update starting wallclock */
>   		platform_dai_wallclock(dev, &dd->wallclock);
>   		break;
> +	case COMP_CMD_XRUN:
> +		dd->xrun = 1;
>   	case COMP_CMD_PAUSE:
>   	case COMP_CMD_STOP:
>   		wait_init(&dd->complete);
> 



More information about the Sound-open-firmware mailing list