[Sound-open-firmware] [PATCH v4 2/5] testbench fileread and filewrite component update

Ranjani Sridharan ranjani.sridharan at linux.intel.com
Thu Sep 7 17:01:28 CEST 2017


This patch does the following:

Fixes the bug in fileread component's nread count when EOF is reached.

Updates the copy method in the components to return the number of frames
read/written

Updates the buffer produce and consume calls with the number of bytes
read/written

Signed-off-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
---
 tune/c/include/common_test.h | 185 +++++++++++++++++++++++++++++
 tune/c/src/fileread.c        | 266 ++++++++++++++++++++++++++++++++++++++++++
 tune/c/src/filewrite.c       | 271 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 722 insertions(+)
 create mode 100644 tune/c/include/common_test.h
 create mode 100644 tune/c/src/fileread.c
 create mode 100644 tune/c/src/filewrite.c

diff --git a/tune/c/include/common_test.h b/tune/c/include/common_test.h
new file mode 100644
index 0000000..73d6fe5
--- /dev/null
+++ b/tune/c/include/common_test.h
@@ -0,0 +1,185 @@
+#ifndef _COMMON_TEST_H
+#define _COMMON_TEST_H
+
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *   * Neither the name of the Intel Corporation nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo at linux.intel.com>
+ *         Liam Girdwood <liam.r.girdwood at linux.intel.com>
+ *         Keyon Jie <yang.jie at linux.intel.com>
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <time.h>
+#include <stdio.h>
+
+#include <reef/ipc.h>
+#include <reef/audio/pipeline.h>
+#include <reef/audio/format.h>
+
+/*
+ * Static Buffer Convenience Constructors.
+ */
+#define SPIPE_BUFFER(bid, bsize) \
+	{.comp.id = bid, .size = bsize}
+#define SPIPE_COMP_CONNECT(source, sink) \
+	{.source_id = source, .sink_id = sink}
+
+/*
+ * Static Component Convenience Constructors.
+ */
+#define SCONFIG {.frame_fmt = SOF_IPC_FRAME_S32_LE, .periods_sink = 2,\
+	.periods_source = 2, .preload_count = 1}
+#define SPIPE_COMP(cid, ctype, csize) \
+	{.id = cid, .type = ctype, .hdr.size = sizeof(struct csize)}
+#define SPIPE_HOST(scomp, hno_irq, hdmac, hchan, hconfig) \
+	{.comp = scomp, .no_irq = hno_irq, .dmac_id = hdmac,\
+	.dmac_chan = hchan, .dmac_config = hconfig,\
+	.config = SCONFIG}
+#define SPIPE_DAI(scomp, ddai_type, ddai_idx, ddmac, dchan, dconfig) \
+	{.comp = scomp, .type = ddai_type, .index = ddai_idx, \
+	.dmac_id = ddmac, .dmac_chan = dchan, .dmac_config = dconfig, \
+	.config = SCONFIG}
+#define SPIPE_VOL(scomp, vmin, vmax) \
+	{.comp = scomp, .min_value = vmin, .max_value = vmax,\
+	.config = SCONFIG}
+#define SPIPE_MIX(scomp) {.comp = scomp, .config = SCONFIG}
+#define SPIPE_SRC(scomp) {.comp = scomp, .config = SCONFIG}
+#define SPIPE_EQ_FIR(scomp) {.comp = scomp, .config = SCONFIG}
+#define SPIPE_EQ_IIR(scomp) {.comp = scomp, .config = SCONFIG}
+#define SPIPE_TONE(scomp) {.comp = scomp, .config = SCONFIG}
+#define SPIPE_FILEREAD(scomp, fn_in) {.comp = scomp, .config = SCONFIG, .fn = fn_in}
+#define SPIPE_FILEWRITE(scomp, fn_out) {.comp = scomp, .config = SCONFIG, .fn = fn_out}
+
+
+/*
+ * Static Pipeline Convenience Constructor
+ */
+#define SPIPE_PIPE(pid, pcore, pcid, psid, pdeadline, ppriority, pframes) \
+	{.pipeline_id = pid, .core = pcore, .deadline = pdeadline, \
+        .priority = ppriority, .comp_id = pcid, .sched_id = psid, \
+	.frames_per_sched = pframes}
+#define SPIPE_PIPE_CONNECT(psource, bsource, bid, psink, bsink) \
+	{.pipeline_source_id = psource, .comp_source_id = bsource, \
+	.buffer_id = bid, .pipeline_sink_id = psink, .comp_sink_id = bsink}
+
+/*
+ * Static pipeline container and constructor
+ */
+
+#define SCOMP(ccomps) \
+	{.comps = (struct sof_ipc_comp *)ccomps, .num_comps \
+		= ARRAY_SIZE(ccomps)}
+
+
+#define SPIPE(ncomp, sbuffer, sconnect) \
+	{.scomps = ncomp, .num_scomps = ARRAY_SIZE(ncomp), \
+	.buffer = sbuffer, .num_buffers = ARRAY_SIZE(sbuffer), \
+	.connect = sconnect, .num_connections = ARRAY_SIZE(sconnect)}
+
+#define FILEREAD_FN_MAXLENGTH 256
+#define FILEWRITE_FN_MAXLENGTH 256
+
+struct scomps {
+	struct sof_ipc_comp *comps;
+	uint32_t num_comps;
+};
+
+struct spipe {
+	struct scomps *scomps;
+	uint32_t num_scomps;
+	struct sof_ipc_buffer *buffer;
+	uint32_t num_buffers;
+	struct sof_ipc_pipe_comp_connect *connect;
+	uint32_t num_connections;
+};
+
+struct fileread_state {
+	char fn[FILEREAD_FN_MAXLENGTH];
+	FILE *fh;
+	int reached_eof;
+	int n;
+};
+
+struct fileread_comp_data {
+	uint32_t period_bytes;
+	uint32_t channels;
+	uint32_t frame_bytes;
+	uint32_t rate;
+	struct fileread_state frs;
+	int (*fileread_func)(struct comp_dev *dev, struct comp_buffer *sink,
+		struct comp_buffer *source, uint32_t frames);
+
+};
+
+struct filewrite_state {
+	char fn[FILEWRITE_FN_MAXLENGTH];
+	FILE *fh;
+	int write_fail;
+	int n;
+};
+
+struct filewrite_comp_data {
+	uint32_t period_bytes;
+	uint32_t channels;
+	uint32_t frame_bytes;
+	uint32_t rate;
+	struct filewrite_state fws;
+	int (*filewrite_func)(struct comp_dev *dev, struct comp_buffer *sink,
+		struct comp_buffer *source, uint32_t frames);
+
+};
+
+/* Test bench component IPC */
+
+struct sof_ipc_comp_fileread {
+	struct sof_ipc_comp comp;
+	struct sof_ipc_comp_config config;
+	char *fn;
+} __attribute__((packed));
+
+struct sof_ipc_comp_filewrite {
+	struct sof_ipc_comp comp;
+	struct sof_ipc_comp_config config;
+	char *fn;
+} __attribute__((packed));
+
+int scheduler_init(struct reef *reef);
+void sys_comp_fileread_init(void);
+void sys_comp_filewrite_init(void);
+
+int test_bench_pipeline_setup(struct reef *reef,
+	struct sof_ipc_pipe_new pipeline[], struct spipe spipe[]);
+
+int test_bench_pipeline_params_unmute_start(struct ipc *ipc,
+	int32_t fs, int nch, int deadline, int sched_id, int pipe_id);
+
+void test_bench_enable_trace(void);
+void test_bench_disable_trace(void);
+
+#endif
diff --git a/tune/c/src/fileread.c b/tune/c/src/fileread.c
new file mode 100644
index 0000000..e771e20
--- /dev/null
+++ b/tune/c/src/fileread.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *   * Neither the name of the Intel Corporation nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo at linux.intel.com>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <errno.h>
+#include <reef/reef.h>
+#include <reef/lock.h>
+#include <reef/list.h>
+#include <reef/stream.h>
+#include <reef/work.h>
+#include <reef/clock.h>
+#include <reef/audio/component.h>
+#include <reef/audio/format.h>
+#include <reef/audio/pipeline.h>
+#include "common_test.h"
+
+/* fileread component private data */
+
+static int fileread_s32_default(struct comp_dev *dev, struct comp_buffer *sink,
+	struct comp_buffer *source, uint32_t frames)
+{
+	struct fileread_comp_data *cd = comp_get_drvdata(dev);
+	int32_t *dest = (int32_t *) sink->w_ptr;
+	int i, n, n_wrap_dest, ret;
+	int nch = dev->params.channels;
+	int nread = 0;
+
+	n = frames * nch;
+	while (n > 0) {
+		n_wrap_dest = (int32_t *) sink->end_addr - dest;
+		if (n < n_wrap_dest) {
+			/* No circular wrap need */
+			while (n > 0) {
+				n -= nch;
+				i = 0;
+				for (i = 0; i < nch; i++) {
+					ret = fscanf(cd->frs.fh, "%d", dest);
+					if (ret == EOF)
+						goto read_eof;
+					nread++;
+					dest++;
+				}
+			}
+		} else {
+			/* Process until wrap */
+			while (n_wrap_dest > 0) {
+				n -= nch;
+				n_wrap_dest -= nch;
+				for (i = 0; i < nch; i++) {
+					ret = fscanf(cd->frs.fh, "%d", dest);
+					nread++;
+					dest++;
+					if (ret == EOF)
+						goto read_eof;
+				}
+			}
+			/* No need to check if past end_addr,
+			 * it is so just subtract buffer size.
+			 */
+			dest = (int32_t *) ((size_t) dest - sink->alloc_size);
+		}
+	}
+
+	cd->frs.n += nread;
+	return nread;
+
+read_eof:
+	cd->frs.n += nread;
+	cd->frs.reached_eof = 1;
+	sink->w_ptr = dest;
+}
+
+static struct comp_dev *fileread_new(struct sof_ipc_comp *comp)
+{
+	struct comp_dev *dev;
+	struct sof_ipc_comp_fileread *fileread;
+	struct sof_ipc_comp_fileread *ipc_fileread
+		= (struct sof_ipc_comp_fileread *) comp;
+	struct fileread_comp_data *cd;
+
+	dev = malloc(COMP_SIZE(struct sof_ipc_comp_fileread));
+	if (dev == NULL)
+		return NULL;
+
+	fileread = (struct sof_ipc_comp_fileread *) &dev->comp;
+	memcpy(fileread, ipc_fileread, sizeof(struct sof_ipc_comp_fileread));
+
+	cd = malloc(sizeof(*cd));
+	if (cd == NULL) {
+		free(dev);
+		return NULL;
+	}
+
+	comp_set_drvdata(dev, cd);
+	cd->fileread_func = fileread_s32_default;
+
+	/* Get filename from IPC and open file */
+	strncpy(cd->frs.fn, ipc_fileread->fn, FILEREAD_FN_MAXLENGTH);
+	cd->frs.fh = fopen(cd->frs.fn, "r");
+	if (cd->frs.fh == NULL) {
+		fprintf(stderr, "Error: File %s open for read failed.\n",
+			cd->frs.fn);
+		free(cd);
+		free(dev);
+		return NULL;
+	}
+	cd->frs.reached_eof = 0;
+	cd->frs.n = 0;
+
+	return dev;
+}
+
+static void fileread_free(struct comp_dev *dev)
+{
+	struct fileread_data *td = comp_get_drvdata(dev);
+	struct fileread_comp_data *cd = comp_get_drvdata(dev);
+
+	fclose(cd->frs.fh);
+	free(td);
+	free(dev);
+}
+
+/* set component audio stream parameters */
+static int fileread_params(struct comp_dev *dev)
+{
+	struct fileread_comp_data *cd = comp_get_drvdata(dev);
+	struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
+
+	/* Need to compute this in non-host endpoint */
+	dev->frame_bytes =
+		dev->params.sample_container_bytes * dev->params.channels;
+
+	/* calculate period size based on config */
+	cd->period_bytes = dev->frames * dev->frame_bytes;
+
+	/* File to sink supports only S32_LE PCM format */
+	if (config->frame_fmt != SOF_IPC_FRAME_S32_LE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* used to pass standard and bespoke commands (with data) to component */
+static int fileread_cmd(struct comp_dev *dev, int cmd, void *data)
+{
+	switch (cmd) {
+	case COMP_CMD_START:
+		dev->state = COMP_STATE_RUNNING;
+		break;
+	case COMP_CMD_STOP:
+		if (dev->state == COMP_STATE_RUNNING ||
+			dev->state == COMP_STATE_DRAINING ||
+			dev->state == COMP_STATE_PAUSED) {
+			comp_buffer_reset(dev);
+			dev->state = COMP_STATE_SETUP;
+		}
+		break;
+	case COMP_CMD_PAUSE:
+		/* only support pausing for running */
+		if (dev->state == COMP_STATE_RUNNING)
+			dev->state = COMP_STATE_PAUSED;
+
+		break;
+	case COMP_CMD_RELEASE:
+		dev->state = COMP_STATE_RUNNING;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/* copy and process stream data from source to sink buffers
+ * returns the number of bytes copied
+ */
+static int fileread_copy(struct comp_dev *dev)
+{
+	struct comp_buffer *sink;
+	struct comp_buffer *source = NULL;
+	struct fileread_comp_data *cd = comp_get_drvdata(dev);
+	int ret = 0;
+
+	/* fileread component sink buffer */
+	sink = list_first_item(&dev->bsink_list, struct comp_buffer,
+		source_list);
+
+	/* Test that sink has enough free frames */
+	if (sink->free >= cd->period_bytes  && !cd->frs.reached_eof) {
+		/* Read PCM samples from file */
+		ret = cd->fileread_func(dev, sink, source, dev->frames);
+		if (ret > 0)
+			comp_update_buffer_produce(sink, ret *
+				dev->params.sample_container_bytes);
+	}
+
+	return ret;
+}
+
+static int fileread_prepare(struct comp_dev *dev)
+{
+	dev->state = COMP_STATE_PREPARE;
+
+	return 0;
+}
+
+static int fileread_preload(struct comp_dev *dev)
+{
+	return fileread_copy(dev);
+}
+
+static int fileread_reset(struct comp_dev *dev)
+{
+	dev->state = COMP_STATE_INIT;
+
+	return 0;
+}
+
+struct comp_driver comp_fileread = {
+	.type = SOF_COMP_FILEREAD,
+	.ops =
+	{
+		.new = fileread_new,
+		.free = fileread_free,
+		.params = fileread_params,
+		.cmd = fileread_cmd,
+		.copy = fileread_copy,
+		.prepare = fileread_prepare,
+		.reset = fileread_reset,
+		.preload = fileread_preload,
+	},
+};
+
+void sys_comp_fileread_init(void)
+{
+	comp_register(&comp_fileread);
+}
diff --git a/tune/c/src/filewrite.c b/tune/c/src/filewrite.c
new file mode 100644
index 0000000..8beee24
--- /dev/null
+++ b/tune/c/src/filewrite.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *   * Neither the name of the Intel Corporation nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Seppo Ingalsuo <seppo.ingalsuo at linux.intel.com>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <errno.h>
+#include <reef/reef.h>
+#include <reef/lock.h>
+#include <reef/list.h>
+#include <reef/stream.h>
+#include <reef/work.h>
+#include <reef/clock.h>
+#include <reef/audio/component.h>
+#include <reef/audio/format.h>
+#include <reef/audio/pipeline.h>
+#include "common_test.h"
+
+/* filewrite component private data */
+
+static int filewrite_s32_default(struct comp_dev *dev,
+	struct comp_buffer *sink, struct comp_buffer *source, uint32_t frames)
+{
+	struct filewrite_comp_data *cd = comp_get_drvdata(dev);
+	int32_t *src = (int32_t *) source->r_ptr;
+	int i, n, n_wrap_src, ret;
+	int nch = dev->params.channels;
+	int nwrite = 0;
+
+	if (cd->fws.write_fail)
+		return;
+
+	n = frames * nch;
+
+	while (n > 0) {
+		n_wrap_src = (int32_t *) source->end_addr - src;
+		if (n < n_wrap_src) {
+			/* No circular wrap need */
+			while (n > 0) {
+				n -= nch;
+				i = 0;
+				for (i = 0; i < nch; i++) {
+					ret = fprintf(cd->fws.fh, "%d\n", *src);
+					nwrite++;
+					src++;
+					if (ret < 0) {
+						cd->fws.write_fail = 1;
+						goto quit;
+					}
+				}
+			}
+		} else {
+			/* Process until wrap */
+			while (n_wrap_src > 0) {
+				n -= nch;
+				n_wrap_src -= nch;
+				for (i = 0; i < nch; i++) {
+					ret = fprintf(cd->fws.fh, "%d\n", *src);
+					nwrite++;
+					src++;
+					if (ret < 0) {
+						cd->fws.write_fail = 1;
+						goto quit;
+					}
+				}
+			}
+			/* No need to check if past end_addr,
+			 * it is so just subtract buffer size.
+			 */
+			src = (int32_t *) ((size_t) src - source->alloc_size);
+		}
+	}
+
+quit:
+	cd->fws.n += nwrite;
+	return nwrite;
+}
+
+static struct comp_dev *filewrite_new(struct sof_ipc_comp *comp)
+{
+	struct comp_dev *dev;
+	struct sof_ipc_comp_filewrite *filewrite;
+	struct sof_ipc_comp_filewrite *ipc_filewrite
+		= (struct sof_ipc_comp_filewrite *) comp;
+	struct filewrite_comp_data *cd;
+
+	dev = malloc(COMP_SIZE(struct sof_ipc_comp_filewrite));
+	if (dev == NULL)
+		return NULL;
+
+	filewrite = (struct sof_ipc_comp_filewrite *) &dev->comp;
+	memcpy(filewrite, ipc_filewrite, sizeof(struct sof_ipc_comp_filewrite));
+
+	cd = malloc(sizeof(*cd));
+	if (cd == NULL) {
+		free(dev);
+		return NULL;
+	}
+
+	comp_set_drvdata(dev, cd);
+	cd->filewrite_func = filewrite_s32_default;
+
+	strncpy(cd->fws.fn, ipc_filewrite->fn, FILEWRITE_FN_MAXLENGTH);
+	cd->fws.fh = fopen(cd->fws.fn, "w");
+	if (cd->fws.fh == NULL) {
+		fprintf(stderr, "Error: File %s open for write failed.\n",
+			cd->fws.fn);
+		free(cd);
+		free(dev);
+		return NULL;
+	}
+
+	cd->fws.write_fail = 0;
+	cd->fws.n = 0;
+	return dev;
+}
+
+static void filewrite_free(struct comp_dev *dev)
+{
+	struct filewrite_data *td = comp_get_drvdata(dev);
+	struct filewrite_comp_data *cd = comp_get_drvdata(dev);
+
+	fclose(cd->fws.fh);
+	free(td);
+	free(dev);
+}
+
+/* set component audio stream parameters */
+static int filewrite_params(struct comp_dev *dev)
+{
+	struct filewrite_comp_data *cd = comp_get_drvdata(dev);
+	struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
+
+	/* Need to compute this in non-dai endpoint */
+	dev->frame_bytes =
+		dev->params.sample_container_bytes * dev->params.channels;
+
+	/* calculate period size based on config */
+	cd->period_bytes = dev->frames * dev->frame_bytes;
+
+	/* File to sink supports only S32_LE PCM format */
+	if (config->frame_fmt != SOF_IPC_FRAME_S32_LE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* used to pass standard and bespoke commands (with data) to component */
+static int filewrite_cmd(struct comp_dev *dev, int cmd, void *data)
+{
+	switch (cmd) {
+	case COMP_CMD_START:
+		dev->state = COMP_STATE_RUNNING;
+		break;
+	case COMP_CMD_STOP:
+		if (dev->state == COMP_STATE_RUNNING ||
+			dev->state == COMP_STATE_DRAINING ||
+			dev->state == COMP_STATE_PAUSED) {
+			comp_buffer_reset(dev);
+			dev->state = COMP_STATE_SETUP;
+		}
+		break;
+	case COMP_CMD_PAUSE:
+		/* only support pausing for running */
+		if (dev->state == COMP_STATE_RUNNING)
+			dev->state = COMP_STATE_PAUSED;
+
+		break;
+	case COMP_CMD_RELEASE:
+		dev->state = COMP_STATE_RUNNING;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/* copy and process stream data from source to sink buffers
+ * returns the number of bytes copied
+ */
+static int filewrite_copy(struct comp_dev *dev)
+{
+	struct comp_buffer *sink = NULL;
+	struct comp_buffer *source;
+	struct filewrite_comp_data *cd = comp_get_drvdata(dev);
+	int ret = 0;
+
+	/* Get filewrite component source buffer */
+	source = list_first_item(&dev->bsource_list, struct comp_buffer,
+		sink_list);
+
+	/* Test that source has enough free frames */
+	if (source->avail >= cd->period_bytes) {
+		/* Write PCM samples into file */
+		ret = cd->filewrite_func(dev, sink, source, dev->frames);
+		comp_update_buffer_consume(source, ret *
+			dev->params.sample_container_bytes);
+	}
+
+	if (cd->fws.write_fail)
+		return -EINVAL;
+
+	return ret;
+}
+
+static int filewrite_prepare(struct comp_dev *dev)
+{
+	dev->state = COMP_STATE_PREPARE;
+
+	return 0;
+}
+
+static int filewrite_preload(struct comp_dev *dev)
+{
+	return filewrite_copy(dev);
+}
+
+static int filewrite_reset(struct comp_dev *dev)
+{
+	dev->state = COMP_STATE_INIT;
+
+	return 0;
+}
+
+struct comp_driver comp_filewrite = {
+	.type = SOF_COMP_FILEWRITE,
+	.ops =
+	{
+		.new = filewrite_new,
+		.free = filewrite_free,
+		.params = filewrite_params,
+		.cmd = filewrite_cmd,
+		.copy = filewrite_copy,
+		.prepare = filewrite_prepare,
+		.reset = filewrite_reset,
+		.preload = filewrite_preload,
+	},
+};
+
+void sys_comp_filewrite_init(void)
+{
+	comp_register(&comp_filewrite);
+}
-- 
2.9.3



More information about the Sound-open-firmware mailing list