[Sound-open-firmware] [PATCH] pipeline: Add XRUN state and handler within pipeline.

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


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 at 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(&current->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 */
-- 
2.11.0



More information about the Sound-open-firmware mailing list