We need to wait until the last bytes/period is finished in dai, before we can notify host side about that, otherwise, host side will trigger stop too early, and we will miss rendering them.
Signed-off-by: Keyon Jie yang.jie@linux.intel.com --- src/audio/host.c | 38 +++++++++++++++++++++++ src/audio/pipeline.c | 1 + src/include/reef/audio/pipeline.h | 2 ++ src/platform/baytrail/include/platform/platform.h | 6 ++++ 4 files changed, 47 insertions(+)
diff --git a/src/audio/host.c b/src/audio/host.c index 806a505..3074c8e 100644 --- a/src/audio/host.c +++ b/src/audio/host.c @@ -64,6 +64,7 @@ struct host_data { completion_t complete; struct period_desc *period; struct comp_buffer *dma_buffer; + struct work work;
/* local and host DMA buffer info */ struct hc_buf host; @@ -220,6 +221,10 @@ static void host_dma_cb_playback(struct comp_dev *dev, /* end of stream, stop */ next->size = 0; need_copy = 0; + + /* will notify host side once dai tell us */ + wait_init(&dev->pipeline->complete); + work_schedule_default(&hd->work, PLATFORM_HOST_FINISH_DELAY); goto next_copy; }
@@ -354,6 +359,38 @@ static void host_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next) host_dma_cb_capture(dev, next); }
+/* We need to wait until the last bytes/period is finished in dai, before we + * can notify host side about that, otherwise, host side will trigger stop too + * early, and we will miss rendering them. + * This work should be scheduled once the copy for host component is finished, + * and wait a timeout inside the work for pipeline->complete, which should be + * set in the endpoint(dai) rendering finishing callback. + */ +static uint32_t host_finish_work(void *data, uint32_t udelay) +{ + struct comp_dev *dev = (struct comp_dev *)data; + struct host_data *hd = comp_get_drvdata(dev); + int ret; + + dev->pipeline->complete.timeout = PLATFORM_HOST_FINISH_TIMEOUT; + ret = wait_for_completion_timeout(&dev->pipeline->complete); + if (ret < 0) + trace_comp_error("eHf"); + else { + trace_comp("hFw"); + /* update for host side */ + if (hd->host_pos) { + *hd->host_pos = hd->host_pos_read; + /* send the last notification to host */ + ipc_stream_send_notification(dev, &hd->cp); + } + } + + return 0; +} + + + static struct comp_dev *host_new(uint32_t type, uint32_t index, uint32_t direction) { @@ -389,6 +426,7 @@ static struct comp_dev *host_new(uint32_t type, uint32_t index, hd->source = NULL; hd->sink = NULL; hd->split_remaining = 0; + work_init(&hd->work, host_finish_work, dev, WORK_ASYNC);
/* init buffer elems */ list_init(&hd->config.elem_list); diff --git a/src/audio/pipeline.c b/src/audio/pipeline.c index 9d74e37..41693ae 100644 --- a/src/audio/pipeline.c +++ b/src/audio/pipeline.c @@ -141,6 +141,7 @@ struct pipeline *pipeline_new(uint32_t id) list_init(&p->host_ep_list); list_init(&p->dai_ep_list); list_init(&p->buffer_list); + wait_init(&p->complete);
spinlock_init(&p->lock); list_item_prepend(&p->list, &pipe_data->pipeline_list); diff --git a/src/include/reef/audio/pipeline.h b/src/include/reef/audio/pipeline.h index 26c1dd6..e7de501 100644 --- a/src/include/reef/audio/pipeline.h +++ b/src/include/reef/audio/pipeline.h @@ -39,6 +39,7 @@ #include <reef/dma.h> #include <reef/audio/component.h> #include <reef/trace.h> +#include <reef/wait.h>
#define trace_pipe(__e) trace_event(TRACE_CLASS_PIPE, __e) #define trace_pipe_error(__e) trace_error(TRACE_CLASS_PIPE, __e) @@ -50,6 +51,7 @@ struct pipeline { uint32_t id; /* id */ spinlock_t lock; + completion_t complete; /* indicate if the pipeline data is finished*/
/* lists */ struct list_item host_ep_list; /* list of host endpoints */ diff --git a/src/platform/baytrail/include/platform/platform.h b/src/platform/baytrail/include/platform/platform.h index f86019d..7df65b8 100644 --- a/src/platform/baytrail/include/platform/platform.h +++ b/src/platform/baytrail/include/platform/platform.h @@ -86,6 +86,12 @@ /* WorkQ window size in microseconds */ #define PLATFORM_WORKQ_WINDOW 2000
+/* Host finish work schedule delay in microseconds */ +#define PLATFORM_HOST_FINISH_DELAY 100 + +/* Host finish work(drain from host to dai) timeout in microseconds */ +#define PLATFORM_HOST_FINISH_TIMEOUT 50000 + /* Platform defined panic code */ #define platform_panic(__x) \ shim_write(SHIM_IPCXL, ((shim_read(SHIM_IPCXL) & 0xc0000000) |\