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

Liam Girdwood liam.r.girdwood at linux.intel.com
Thu Nov 16 23:01:29 CET 2017


WiP: The DAI should not be stopped and the restarted on XRUNs

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);
-- 
2.11.0



More information about the Sound-open-firmware mailing list