[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