[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