Add an XRUN handler to notify components that an XRUN has occurred and to take any remedial action. The pipeline itself will handle an XRUN by re-preparing the components and then send start again from the pipeline source component.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/audio/component.c | 1 + src/audio/pipeline.c | 70 ++++++++++++++++++++++++++++++++++++-- src/include/reef/audio/component.h | 1 + src/include/reef/audio/pipeline.h | 3 +- 4 files changed, 71 insertions(+), 4 deletions(-)
diff --git a/src/audio/component.c b/src/audio/component.c index 5815fad..54a7da8 100644 --- a/src/audio/component.c +++ b/src/audio/component.c @@ -141,6 +141,7 @@ int comp_set_state(struct comp_dev *dev, int cmd) } break; case COMP_CMD_STOP: + case COMP_CMD_XRUN: if (dev->state == COMP_STATE_ACTIVE) { dev->state = COMP_STATE_PREPARE; } else { diff --git a/src/audio/pipeline.c b/src/audio/pipeline.c index bec7519..ccd6094 100644 --- a/src/audio/pipeline.c +++ b/src/audio/pipeline.c @@ -76,6 +76,9 @@ static void connect_upstream(struct pipeline *p, struct comp_dev *start, /* we are an endpoint if we have 0 source components */ if (list_is_empty(¤t->bsource_list)) { current->is_endpoint = 1; + + /* pipeline source comp is current */ + p->source_comp = current; return; }
@@ -86,8 +89,13 @@ static void connect_upstream(struct pipeline *p, struct comp_dev *start, buffer = container_of(clist, struct comp_buffer, sink_list);
/* don't go upstream if this source is from another pipeline */ - if (buffer->source->comp.pipeline_id != p->ipc_pipe.pipeline_id) + if (buffer->source->comp.pipeline_id != p->ipc_pipe.pipeline_id) { + + /* pipeline source comp is current unless we go upstream */ + p->source_comp = current; + continue; + }
connect_upstream(p, start, buffer->source); } @@ -210,6 +218,7 @@ static void pipeline_cmd_update(struct pipeline *p, struct comp_dev *comp, break; case COMP_CMD_SUSPEND: case COMP_CMD_RESUME: + case COMP_CMD_XRUN: default: break; } @@ -1001,6 +1010,38 @@ void pipeline_xrun(struct pipeline *p, struct comp_dev *dev, } }
+/* recover the pipeline from a XRUN condition */ +static int pipeline_xrun_recover(struct pipeline *p) +{ + int ret; + + trace_pipe_error("pxr"); + + /* notify all pipeline comps we are in XRUN */ + ret = pipeline_cmd(p, p->source_comp, COMP_CMD_XRUN, NULL); + if (ret < 0) { + trace_pipe_error("px0"); + return ret; + } + p->xrun_bytes = 0; + + /* prepare the pipeline */ + pipeline_prepare(p, p->source_comp); + if (ret < 0) { + trace_pipe_error("px1"); + return ret; + } + + /* restart pipeline comps */ + pipeline_cmd(p, p->source_comp, COMP_CMD_START, NULL); + if (ret < 0) { + trace_pipe_error("px2"); + return ret; + } + + return 0; +} + /* notify pipeline that this component requires buffers emptied/filled */ void pipeline_schedule_copy(struct pipeline *p, uint64_t start) { @@ -1025,13 +1066,36 @@ static void pipeline_task(void *arg) { struct pipeline *p = arg; struct comp_dev *dev = p->sched_comp; + int err;
tracev_pipe("PWs");
+ /* are we in xrun ? */ + if (p->xrun_bytes) { + err = pipeline_xrun_recover(p); + if (err < 0) + return; /* failed - host will stop this pipeline */ + goto sched; + } + /* copy data from upstream source endpoints to downstream endpoints */ - pipeline_copy_from_upstream(dev, dev); - pipeline_copy_to_downstream(dev, dev); + err = pipeline_copy_from_upstream(dev, dev); + if (err < 0) { + err = pipeline_xrun_recover(p); + if (err < 0) + return; /* failed - host will stop this pipeline */ + goto sched; + } + + err = pipeline_copy_to_downstream(dev, dev); + if (err < 0) { + err = pipeline_xrun_recover(p); + if (err < 0) + return; /* failed - host will stop this pipeline */ + goto sched; + }
+sched: tracev_pipe("PWe");
/* now reschedule the task */ diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h index afd5461..5d15fdb 100644 --- a/src/include/reef/audio/component.h +++ b/src/include/reef/audio/component.h @@ -80,6 +80,7 @@ #define COMP_CMD_RESUME 6 /* resume component */ #define COMP_CMD_RESET 6 /* reset component */ #define COMP_CMD_PREPARE 7 /* prepare component */ +#define COMP_CMD_XRUN 8 /* XRUN component */
/* * standard component control commands diff --git a/src/include/reef/audio/pipeline.h b/src/include/reef/audio/pipeline.h index c5ba49f..08a3f30 100644 --- a/src/include/reef/audio/pipeline.h +++ b/src/include/reef/audio/pipeline.h @@ -67,7 +67,8 @@ struct pipeline {
/* scheduling */ struct task pipe_task; /* pipeline processing task */ - struct comp_dev *sched_comp; + struct comp_dev *sched_comp; /* component that drives scheduling in this pipe */ + struct comp_dev *source_comp; /* source component for this pipe */ };
/* static pipeline */