[Sound-open-firmware] [PATCH] pipeline: xrun: Add XRUN initial handler into pipeline

Liam Girdwood liam.r.girdwood at linux.intel.com
Tue Aug 22 23:35:05 CEST 2017


Add an XRUN handler into the pipeline to report bag overrun and underrun
from component buffers to the host. An XRUN on a component will now cause
a IPC XRUN message to each PCM interface source/sink to the component.

Signed-off-by: Liam Girdwood <liam.r.girdwood at linux.intel.com>
---
 src/audio/pipeline.c              | 116 +++++++++++++++++++++++++++++++++++++-
 src/include/reef/audio/pipeline.h |   6 ++
 src/include/reef/ipc.h            |   3 +
 src/include/uapi/ipc.h            |  12 +++-
 src/ipc/intel-ipc.c               |  14 +++++
 5 files changed, 148 insertions(+), 3 deletions(-)

diff --git a/src/audio/pipeline.c b/src/audio/pipeline.c
index 282bec5..f213dc4 100644
--- a/src/audio/pipeline.c
+++ b/src/audio/pipeline.c
@@ -183,6 +183,28 @@ static void disconnect_downstream(struct pipeline *p, struct comp_dev *start,
 	spin_unlock(&current->lock);
 }
 
+/* update pipeline state based on cmd */
+static void pipeline_cmd_update(struct pipeline *p, int cmd)
+{
+	switch (cmd) {
+	case COMP_CMD_PAUSE:
+		break;
+	case COMP_CMD_STOP:
+		break;
+	case COMP_CMD_RELEASE:
+		p->xrun_bytes = 0;
+		break;
+	case COMP_CMD_START:
+		p->xrun_bytes = 0;
+		break;
+	case COMP_CMD_SUSPEND:
+		break;
+	case COMP_CMD_RESUME:
+		p->xrun_bytes = 0;
+		break;
+	}
+}
+
 /* create new pipeline - returns pipeline id or negative error */
 struct pipeline *pipeline_new(struct sof_ipc_pipe_new *pipe_desc,
 	struct comp_dev *cd)
@@ -311,8 +333,10 @@ static int component_op_downstream(struct op_data *op_data,
 		err = comp_params(current);
 		break;
 	case COMP_OPS_CMD:
-		/* send command to the component */
+		/* send command to the component and update pipeline state  */
 		err = comp_cmd(current, op_data->cmd, op_data->cmd_data);
+		if (err == 0)
+			pipeline_cmd_update(current->pipeline, op_data->cmd);
 		break;
 	case COMP_OPS_PREPARE:
 		/* prepare the component */
@@ -383,8 +407,10 @@ static int component_op_upstream(struct op_data *op_data,
 		err = comp_params(current);
 		break;
 	case COMP_OPS_CMD:
-		/* send command to the component */
+		/* send command to the component and update pipeline state  */
 		err = comp_cmd(current, op_data->cmd, op_data->cmd_data);
+		if (err == 0)
+			pipeline_cmd_update(current->pipeline, op_data->cmd);
 		break;
 	case COMP_OPS_PREPARE:
 		/* prepare the component */
@@ -818,6 +844,92 @@ void pipeline_get_timestamp(struct pipeline *p, struct comp_dev *host,
 	}
 }
 
+static void xrun(struct comp_dev *dev, void *data)
+{
+	struct sof_ipc_stream_posn *posn = data;
+
+	/* get host timestamps */
+	platform_host_timestamp(dev, posn);
+
+	/* send XRUN to host */
+	ipc_stream_send_xrun(dev, posn);
+}
+
+
+/* travel down stream from start and run func for each component of type */
+static void pipeline_for_each_downstream(struct pipeline *p,
+	enum sof_comp_type type, struct comp_dev *current,
+	void (*func)(struct comp_dev *, void *), void *data)
+{
+	struct list_item *clist;
+
+	if (current->comp.type == type)
+		func(current, data);
+
+	/* travel downstream to sink end point(s) */
+	list_for_item(clist, &current->bsink_list) {
+		struct comp_buffer *buffer;
+
+		buffer = container_of(clist, struct comp_buffer, source_list);
+
+		/* dont go downstream if this component is not connected */
+		if (!buffer->connected)
+			continue;
+
+		/* continue downstream */
+		pipeline_for_each_downstream(p, type, buffer->sink,
+			func, data);
+	}
+}
+
+/* travel up stream from start and run func for each component of type */
+static void pipeline_for_each_upstream(struct pipeline *p,
+	enum sof_comp_type type, struct comp_dev *current,
+	void (*func)(struct comp_dev *, void *), void *data)
+{
+	struct list_item *clist;
+
+	if (current->comp.type == type)
+		func(current, data);
+
+	/* travel upstream to sink end point(s) */
+	list_for_item(clist, &current->bsource_list) {
+		struct comp_buffer *buffer;
+
+		buffer = container_of(clist, struct comp_buffer, sink_list);
+
+		/* dont go downstream if this component is not connected */
+		if (!buffer->connected)
+			continue;
+
+		/* continue downstream */
+		pipeline_for_each_upstream(p, type, buffer->source,
+			func, data);
+	}
+}
+
+/*
+ * Send an XRUN to each host for this component.
+ */
+void pipeline_xrun(struct pipeline *p, struct comp_dev *dev,
+	int32_t bytes)
+{
+	struct sof_ipc_stream_posn posn;
+
+	/* dont flood host */
+	if (p->xrun_bytes)
+		return;
+
+	memset(&posn, 0, sizeof(posn));
+	p->xrun_bytes = posn.xrun_size = bytes;
+	posn.xrun_comp_id = dev->comp.id;
+
+	if (dev->params.direction == SOF_IPC_STREAM_PLAYBACK) {
+		pipeline_for_each_upstream(p, SOF_COMP_HOST, dev, xrun, &posn);
+	} else {
+		pipeline_for_each_downstream(p, SOF_COMP_HOST, dev, xrun, &posn);
+	}
+}
 
 /* notify pipeline that this component requires buffers emptied/filled */
 void pipeline_schedule_copy(struct pipeline *p, struct comp_dev *dev)
diff --git a/src/include/reef/audio/pipeline.h b/src/include/reef/audio/pipeline.h
index 17e8a34..ad01dfd 100644
--- a/src/include/reef/audio/pipeline.h
+++ b/src/include/reef/audio/pipeline.h
@@ -57,6 +57,9 @@ struct pipeline {
 	spinlock_t lock;
 	struct sof_ipc_pipe_new ipc_pipe;
 
+	/* runtime status */
+	int32_t xrun_bytes;		/* last xrun length */
+
 	/* lists */
 	struct list_item comp_list;		/* list of components */
 	struct list_item buffer_list;		/* list of buffers */
@@ -117,4 +120,7 @@ void pipeline_get_timestamp(struct pipeline *p, struct comp_dev *host_dev,
 
 void pipeline_schedule(void *arg);
 
+/* notify host that we have XRUN */
+void pipeline_xrun(struct pipeline *p, struct comp_dev *dev, int32_t bytes);
+
 #endif
diff --git a/src/include/reef/ipc.h b/src/include/reef/ipc.h
index 253f4f4..3eb94d8 100644
--- a/src/include/reef/ipc.h
+++ b/src/include/reef/ipc.h
@@ -116,6 +116,9 @@ int ipc_process_msg_queue(void);
 
 int ipc_stream_send_position(struct comp_dev *cdev,
 		struct sof_ipc_stream_posn *posn);
+int ipc_stream_send_xrun(struct comp_dev *cdev,
+	struct sof_ipc_stream_posn *posn);
+
 int ipc_queue_host_message(struct ipc *ipc, uint32_t header,
 	void *tx_data, size_t tx_bytes, void *rx_data,
 	size_t rx_bytes, void (*cb)(void*, void*), void *cb_data);
diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h
index ddca551..ae212be 100644
--- a/src/include/uapi/ipc.h
+++ b/src/include/uapi/ipc.h
@@ -412,14 +412,17 @@ struct sof_ipc_stream {
 
 struct sof_ipc_stream_posn {
 	struct sof_ipc_reply rhdr;
-	uint32_t comp_id;
+	uint32_t comp_id;	/* host component ID */
 	uint32_t flags;		/* SOF_TIME_ */
 	uint32_t wallclock_hz;	/* frequency of wallclock in Hz */
 	uint32_t timestamp_ns;	/* resolution of timestamp in ns */
 	uint64_t host_posn;	/* host DMA position in bytes */
 	uint64_t dai_posn;	/* DAI DMA position in bytes */
+	uint64_t comp_posn;	/* comp position in bytes */
 	uint64_t wallclock;	/* audio wall clock */
 	uint64_t timestamp;	/* system time stamp */
+	uint32_t xrun_comp_id;	/* comp ID of XRUN component */
+	int32_t xrun_size;	/* XRUN size in bytes */
 }  __attribute__((packed));
 
 /*
@@ -467,6 +470,11 @@ enum sof_comp_type {
 	SOF_COMP_EQ_FIR,
 };
 
+/* XRUN action for component */
+#define SOF_XRUN_STOP		1 	/* stop stream */
+#define SOF_XRUN_UNDER_ZERO	2	/* send 0s to sink */
+#define SOF_XRUN_OVER_NULL	4	/* send data to NULL */
+
 /* create new generic component - SOF_IPC_TPLG_COMP_NEW */
 struct sof_ipc_comp {
 	struct sof_ipc_hdr hdr;
@@ -492,6 +500,7 @@ struct sof_ipc_comp_config {
 	uint32_t periods_source;	/* 0 means variable */
 	uint32_t preload_count;	/* how many periods to preload */
 	enum sof_ipc_frame frame_fmt;
+	uint32_t xrun_action;
 } __attribute__((packed));
 
 /* generic host component */
@@ -638,6 +647,7 @@ struct sof_ipc_pipe_new {
 	uint32_t priority;	/* priority level 0 (low) to 10 (max) */
 	uint32_t mips;		/* worst case instruction count per period */
 	uint32_t frames_per_sched; /* output frames of pipeline, 0 is variable */
+	uint32_t xrun_limit_usecs; /* report xruns greater than limit */
 }  __attribute__((packed));
 
 /* pipeline construction complete - SOF_IPC_TPLG_PIPE_COMPLETE */
diff --git a/src/ipc/intel-ipc.c b/src/ipc/intel-ipc.c
index 681bf64..db48ef0 100644
--- a/src/ipc/intel-ipc.c
+++ b/src/ipc/intel-ipc.c
@@ -328,6 +328,20 @@ int ipc_stream_send_position(struct comp_dev *cdev,
 		NULL, 0, NULL, NULL);
 }
 
+/* send stream position TODO: send compound message  */
+int ipc_stream_send_xrun(struct comp_dev *cdev,
+	struct sof_ipc_stream_posn *posn)
+{
+	uint32_t header;
+
+	header = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_TRIG_XRUN;
+	posn->rhdr.hdr.cmd = header;
+	posn->rhdr.hdr.size = sizeof(*posn);
+
+	return ipc_queue_host_message(_ipc, header, posn, sizeof(*posn),
+		NULL, 0, NULL, NULL);
+}
+
 static int ipc_stream_trigger(uint32_t header)
 {
 	struct ipc_comp_dev *pcm_dev;
-- 
2.11.0



More information about the Sound-open-firmware mailing list