From 95372a0bb00d78c66056883a8eeebc419e8732ba Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Fri, 7 Jun 2019 10:17:26 +0200 Subject: [PATCH] dai: fix xrun handling Fixes xrun handling by moving check from callback to copy. Check in callback wasn't making any sense, because bytes passed there have been already calculated based on avail/free. Signed-off-by: Tomasz Lauda --- src/audio/dai.c | 52 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/src/audio/dai.c b/src/audio/dai.c index 41b040908..5193b94c1 100644 --- a/src/audio/dai.c +++ b/src/audio/dai.c @@ -101,29 +101,11 @@ static void dai_buffer_process(struct comp_dev *dev, struct dma_sg_elem *next) } if (dev->params.direction == SOF_IPC_STREAM_PLAYBACK) { - /* make sure there are available bytes for next period */ - if (dd->dma_buffer->avail < bytes) { - trace_dai_error_with_ids(dev, "dai_buffer_process() " - "error: Insufficient bytes for" - " next period. " - "comp_underrun()"); - comp_underrun(dev, dd->dma_buffer, bytes, 0); - } - /* recalc available buffer space */ comp_update_buffer_consume(dd->dma_buffer, bytes); buffer_ptr = dd->dma_buffer->r_ptr; } else { - /* make sure there are free bytes for next period */ - if (dd->dma_buffer->free < bytes) { - trace_dai_error_with_ids(dev, "dai_buffer_process() " - "error: Insufficient free " - "bytes for next period. " - "comp_overrun()"); - comp_overrun(dev, dd->dma_buffer, bytes, 0); - } - /* recalc available buffer space */ comp_update_buffer_produce(dd->dma_buffer, bytes); @@ -558,6 +540,35 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd) return ret; } +/* check if xrun occurred */ +static int dai_check_for_xrun(struct comp_dev *dev, uint32_t copy_bytes) +{ + struct dai_data *dd = comp_get_drvdata(dev); + + /* data available for copy */ + if (copy_bytes) + return 0; + + /* no data yet, we're just starting */ + if (!dev->position) + return PPL_STATUS_PATH_STOP; + + /* xrun occurred */ + if (dev->params.direction == SOF_IPC_STREAM_PLAYBACK) { + trace_dai_error_with_ids(dev, "dai_check_for_xrun() " + "error: underrun due to no data " + "available"); + comp_underrun(dev, dd->dma_buffer, copy_bytes, 0); + } else { + trace_dai_error_with_ids(dev, "dai_check_for_xrun() " + "error: overrun due to no data " + "available"); + comp_overrun(dev, dd->dma_buffer, copy_bytes, 0); + } + + return -ENODATA; +} + /* copy and process stream data from source to sink buffers */ static int dai_copy(struct comp_dev *dev) { @@ -595,6 +606,11 @@ static int dai_copy(struct comp_dev *dev) tracev_dai_with_ids(dev, "dai_copy(), copy_bytes = 0x%x", copy_bytes); + /* check for underrun or overrun */ + ret = dai_check_for_xrun(dev, copy_bytes); + if (ret < 0 || ret == PPL_STATUS_PATH_STOP) + return ret; + ret = dma_copy(dd->dma, dd->chan, copy_bytes, 0); if (ret < 0) trace_dai_error("dai_copy() error: ret = %u", ret);