[Sound-open-firmware] [PATCH 2/3] [RFC]tune: add fileread and filewrite components

Seppo Ingalsuo seppo.ingalsuo at linux.intel.com
Thu May 3 09:42:48 CEST 2018


Hi,

A feature proposal below:


Thanks,
Seppo

On 03.05.2018 07:31, Ranjani Sridharan wrote:
> This patch adds the fileread and filewrite components that testbench
> can liaise with to read in samples and write out processed samples.
>
> Signed-off-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> ---
>   tune/common/fileread.c  | 385 ++++++++++++++++++++++++++++++++++++++++++++++
>   tune/common/filewrite.c | 395 ++++++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 780 insertions(+)
>   create mode 100644 tune/common/fileread.c
>   create mode 100644 tune/common/filewrite.c
>
> diff --git a/tune/common/fileread.c b/tune/common/fileread.c
> new file mode 100644
> index 0000000..0435fcf
> --- /dev/null
> +++ b/tune/common/fileread.c
> @@ -0,0 +1,385 @@
> +/*
> + * 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>
> + *	   Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> + */
> +
> +#include <stdio.h>
> +#include <stdint.h>
> +#include <stddef.h>
> +#include <errno.h>
> +#include <inttypes.h>
> +#include <sof/sof.h>
> +#include <sof/lock.h>
> +#include <sof/list.h>
> +#include <sof/stream.h>
> +#include <sof/work.h>
> +#include <sof/clock.h>
> +#include <sof/audio/component.h>
> +#include <sof/audio/format.h>
> +#include <sof/audio/pipeline.h>
> +#include <uapi/ipc.h>
> +#include "common_test.h"
> +
> +#define SHRINK_SINK 0
> +
> +static inline void circular_inc_wrap(int32_t **ptr, int32_t *end, size_t size)
> +{
> +	if (*ptr >= end)
> +		*ptr = (int32_t *) ((size_t)*ptr - size);
> +}
> +
> +static inline void circular_inc_wrap_16(int16_t **ptr, int16_t *end,
> +					size_t size)
> +{
> +	if (*ptr >= end)
> +		*ptr = (int16_t *) ((size_t)*ptr - size);
> +}
> +
> +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, n_min, ret;
> +	int nch = dev->params.channels;
> +	int nread = 0;
> +
> +	n = frames * nch;
> +	while (n > 0) {
> +		n_wrap_dest = (int32_t *) sink->end_addr - dest;
> +		n_min = (n < n_wrap_dest) ? n : n_wrap_dest;
> +		while (n_min > 0) {
> +			n -= nch;
> +			n_min -= nch;
> +			for (i = 0; i < nch; i++) {
> +				ret = fscanf(cd->frs.fh, "%d", dest);
> +				nread++;
> +				dest++;
> +				if (ret == EOF)
> +					goto read_eof;
> +			}
> +		}
> +		circular_inc_wrap(&dest, sink->end_addr, sink->size);
> +	}
> +
> +	cd->frs.n += nread;
> +	return nread;
> +
> +read_eof:
> +	cd->frs.n += nread;
> +	cd->frs.reached_eof = 1;
> +	return nread;
> +}

The text format for file data is nice as human readable format and 
possibility to manually create test vectors with a text editor but could 
there be in addition similar functions to read/write raw binary files 
with fread()/fwrite() and invoke such file mode via command line if 
desired? Then it would be possible to convert wav or mp3 etc. to 
compatible raw binary format easily with sox and back.

Binary format would be also faster and more compact for CI tests.

> +
> +static int fileread_s16(struct comp_dev *dev, struct comp_buffer *sink,
> +	struct comp_buffer *source, uint32_t frames)
> +{
> +	struct fileread_comp_data *cd = comp_get_drvdata(dev);
> +	int16_t *dest = (int16_t *) sink->w_ptr;
> +	int i, n, n_wrap_dest, n_min, ret;
> +	int nch = dev->params.channels;
> +	int nread = 0;
> +
> +	n = frames * nch;
> +	while (n > 0) {
> +		n_wrap_dest = (int16_t *) sink->end_addr - dest;
> +		n_min = (n < n_wrap_dest) ? n : n_wrap_dest;
> +		while (n_min > 0) {
> +			n -= nch;
> +			n_min -= nch;
> +			for (i = 0; i < nch; i++) {
> +				ret = fscanf(cd->frs.fh, "%hd", dest);
> +				nread++;
> +				dest++;
> +				if (ret == EOF)
> +					goto read_eof;
> +			}
> +		}
> +		circular_inc_wrap_16(&dest, sink->end_addr, sink->size);
> +	}
> +
> +	cd->frs.n += nread;
> +	return nread;
> +
> +read_eof:
> +	cd->frs.n += nread;
> +	cd->frs.reached_eof = 1;
> +	return nread;
> +}
> +
> +static int fileread_s24(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;
> +	int32_t sample;
> +	int i, n, n_wrap_dest, n_min, ret;
> +	int nch = dev->params.channels;
> +	int nread = 0;
> +
> +	n = frames * nch;
> +	while (n > 0) {
> +		n_wrap_dest = (int32_t *) sink->end_addr - dest;
> +		n_min = (n < n_wrap_dest) ? n : n_wrap_dest;
> +		while (n_min > 0) {
> +			n -= nch;
> +			n_min -= nch;
> +			for (i = 0; i < nch; i++) {
> +				ret = fscanf(cd->frs.fh, "%d", &sample);
> +				*dest = sample & 0x00ffffff;  /* Mask bits */
> +				nread++;
> +				dest++;
> +				if (ret == EOF)
> +					goto read_eof;
> +			}
> +		}
> +		circular_inc_wrap(&dest, sink->end_addr, sink->size);
> +	}
> +
> +	cd->frs.n += nread;
> +	return nread;
> +
> +read_eof:
> +	cd->frs.n += nread;
> +	cd->frs.reached_eof = 1;
> +	return nread;
> +}
> +
> +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 */
> +	strcpy(cd->frs.fn, ipc_fileread->fn);
> +	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/S16_LE/S24_4LE PCM formats */
> +	if ((config->frame_fmt != SOF_IPC_FRAME_S32_LE)
> +		&& (config->frame_fmt != SOF_IPC_FRAME_S24_4LE)
> +		&& (config->frame_fmt != SOF_IPC_FRAME_S16_LE))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int fr_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata)
> +{
> +	return -EINVAL;
> +}
> +
> +static int fileread_trigger(struct comp_dev *dev, int cmd)
> +{
> +	return comp_set_state(dev, cmd);
> +}
> +
> +/* used to pass standard and bespoke commands (with data) to component */
> +static int fileread_cmd(struct comp_dev *dev, int cmd, void *data)
> +{
> +	struct sof_ipc_ctrl_data *cdata = data;
> +	int ret = 0;
> +
> +	switch (cmd) {
> +	case COMP_CMD_SET_DATA:
> +		ret = fr_cmd(dev, cdata);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +/* 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)
> +{
> +	struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
> +	struct comp_buffer *sink_buffer;
> +	struct fileread_comp_data *cd = comp_get_drvdata(dev);
> +	int ret = 0;
> +
> +	/* fileread component sink buffer */
> +	sink_buffer = list_first_item(&dev->bsink_list, struct comp_buffer,
> +		source_list);
> +
> +	switch (config->frame_fmt) {
> +	case(SOF_IPC_FRAME_S16_LE):
> +#if SHRINK_SINK == 1
> +		/* set downstream buffer size */
> +		ret = buffer_set_size(sink_buffer, dev->frames * 2 *
> +			config->periods_sink * dev->params.channels);
> +		if (ret < 0) {
> +			printf("error: fileread buffer size set\n");
> +			return ret;
> +		}
> +#endif
> +		buffer_reset_pos(sink_buffer);
> +
> +		/* set fileread function */
> +		cd->fileread_func = fileread_s16;
> +		break;
> +	case(SOF_IPC_FRAME_S24_4LE):
> +#if SHRINK_SINK == 1
> +		/* set downstream buffer size */
> +		ret = buffer_set_size(sink_buffer, dev->frames * 4 *
> +			config->periods_sink * dev->params.channels);
> +		if (ret < 0) {
> +			printf("error: fileread buffer size set\n");
> +			return ret;
> +		}
> +#endif
> +		buffer_reset_pos(sink_buffer);
> +		/* set fileread function */
> +		cd->fileread_func = fileread_s24;
> +		break;
> +	case(SOF_IPC_FRAME_S32_LE):
> +#if SHRINK_SINK == 1
> +		/* set downstream buffer size */
> +		ret = buffer_set_size(sink_buffer, dev->frames * 4 *
> +			config->periods_sink * dev->params.channels);
> +		if (ret < 0) {
> +			printf("error: fileread buffer size set\n");
> +			return ret;
> +		}
> +#endif
> +		buffer_reset_pos(sink_buffer);
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	dev->state = COMP_STATE_PREPARE;
> +
> +	return ret;
> +}
> +
> +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,
> +		.trigger = fileread_trigger,
> +		.copy = fileread_copy,
> +		.prepare = fileread_prepare,
> +		.reset = fileread_reset,
> +	},
> +};
> +
> +void sys_comp_fileread_init(void)
> +{
> +	comp_register(&comp_fileread);
> +}
> diff --git a/tune/common/filewrite.c b/tune/common/filewrite.c
> new file mode 100644
> index 0000000..fc8d76e
> --- /dev/null
> +++ b/tune/common/filewrite.c
> @@ -0,0 +1,395 @@
> +/*
> + * 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>
> + *	   Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> + */
> +
> +#include <stdio.h>
> +#include <stdint.h>
> +#include <stddef.h>
> +#include <errno.h>
> +#include <sof/sof.h>
> +#include <sof/lock.h>
> +#include <sof/list.h>
> +#include <sof/stream.h>
> +#include <sof/work.h>
> +#include <sof/clock.h>
> +#include <sof/audio/component.h>
> +#include <sof/audio/format.h>
> +#include <sof/audio/pipeline.h>
> +#include "common_test.h"
> +
> +static inline void circular_inc_wrap(int32_t **ptr, int32_t *end,
> +				     size_t size)
> +{
> +	if (*ptr >= end)
> +		*ptr = (int32_t *) ((size_t)*ptr - size);
> +}
> +
> +static inline void circular_inc_wrap_16(int16_t **ptr, int16_t *end,
> +					size_t size)
> +{
> +	if (*ptr >= end)
> +		*ptr = (int16_t *) ((size_t)*ptr - size);
> +}
> +
> +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, n_min, ret;
> +	int nch = dev->params.channels;
> +	int nwrite = 0;
> +
> +	if (cd->fws.write_fail)
> +		return -EINVAL;
> +
> +	n = frames * nch;
> +
> +	while (n > 0) {
> +		n_wrap_src = (int32_t *) source->end_addr - src;
> +		n_min = (n < n_wrap_src) ? n : n_wrap_src;
> +		while (n_min > 0) {
> +			n -= nch;
> +			n_min -= 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;
> +				}
> +			}
> +		}
> +		circular_inc_wrap(&src, source->end_addr, source->size);
> +	}
> +
> +quit:
> +	cd->fws.n += nwrite;
> +	return nwrite;
> +}
> +
> +static int filewrite_s16(struct comp_dev *dev, struct comp_buffer *sink,
> +			 struct comp_buffer *source, uint32_t frames)
> +{
> +	struct filewrite_comp_data *cd = comp_get_drvdata(dev);
> +	int16_t *src = (int16_t *) source->r_ptr;
> +	int i, n, n_wrap_src, n_min, ret;
> +	int nch = dev->params.channels;
> +	int nwrite = 0;
> +
> +	if (cd->fws.write_fail)
> +		return -EINVAL;
> +
> +	n = frames * nch;
> +
> +	while (n > 0) {
> +		n_wrap_src = (int16_t *) source->end_addr - src;
> +		n_min = (n < n_wrap_src) ? n : n_wrap_src;
> +		while (n_min > 0) {
> +			n -= nch;
> +			n_min -= 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;
> +				}
> +			}
> +		}
> +		circular_inc_wrap_16(&src, source->end_addr, source->size);
> +	}
> +
> +
> +quit:
> +	cd->fws.n += nwrite;
> +	return nwrite;
> +}
> +
> +static int filewrite_s24(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;
> +	int32_t se;
> +	int i, n, n_wrap_src, n_min, ret;
> +	int nch = dev->params.channels;
> +	int nwrite = 0;
> +
> +	if (cd->fws.write_fail)
> +		return -EINVAL;
> +
> +	n = frames * nch;
> +
> +	while (n > 0) {
> +		n_wrap_src = (int32_t *) source->end_addr - src;
> +		n_min = (n < n_wrap_src) ? n : n_wrap_src;
> +		while (n_min > 0) {
> +			n -= nch;
> +			n_min -= nch;
> +			for (i = 0; i < nch; i++) {
> +				se = *src << 8;
> +				ret = fprintf(cd->fws.fh, "%d\n", se >> 8);
> +				nwrite++;
> +				src++;
> +				if (ret < 0) {
> +					cd->fws.write_fail = 1;
> +					goto quit;
> +				}
> +			}
> +		}
> +		circular_inc_wrap(&src, source->end_addr, source->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/S16_LE/S24_4LE PCM formats */
> +	if ((config->frame_fmt != SOF_IPC_FRAME_S32_LE)
> +		&& (config->frame_fmt != SOF_IPC_FRAME_S24_4LE)
> +		&& (config->frame_fmt != SOF_IPC_FRAME_S16_LE))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int fw_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata)
> +{
> +	return -EINVAL;
> +}
> +
> +static int filewrite_trigger(struct comp_dev *dev, int cmd)
> +{
> +	return comp_set_state(dev, cmd);
> +}
> +
> +/* used to pass standard and bespoke commands (with data) to component */
> +static int filewrite_cmd(struct comp_dev *dev, int cmd, void *data)
> +{
> +	struct sof_ipc_ctrl_data *cdata = data;
> +	int ret = 0;
> +
> +	switch (cmd) {
> +	case COMP_CMD_SET_DATA:
> +		ret = fw_cmd(dev, cdata);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +/* 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);
> +		if (ret < 0) {
> +			printf("error: filewrite fail\n");
> +			return ret;
> +		}
> +		comp_update_buffer_consume(source, ret *
> +					   dev->params.sample_container_bytes);
> +	}
> +
> +	return ret;
> +}
> +
> +static int filewrite_prepare(struct comp_dev *dev)
> +{
> +	struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
> +	struct comp_buffer *source_buffer;
> +	struct filewrite_comp_data *cd = comp_get_drvdata(dev);
> +	int ret = 0;
> +
> +	/* fileread component sink buffer */
> +	source_buffer = list_first_item(&dev->bsource_list, struct comp_buffer,
> +					sink_list);
> +
> +	switch (config->frame_fmt) {
> +	case(SOF_IPC_FRAME_S16_LE):
> +		/* set downstream buffer size */
> +		ret = buffer_set_size(source_buffer, dev->frames * 2 *
> +			config->periods_source * dev->params.channels);
> +		if (ret < 0) {
> +			printf("error: fileread buffer size set\n");
> +			return ret;
> +		}
> +
> +		buffer_reset_pos(source_buffer);
> +
> +		/* set fileread function */
> +		cd->filewrite_func = filewrite_s16;
> +		break;
> +	case(SOF_IPC_FRAME_S24_4LE):
> +		/* set downstream buffer size */
> +		ret = buffer_set_size(source_buffer, dev->frames * 4 *
> +				      config->periods_source *
> +				      dev->params.channels);
> +		if (ret < 0) {
> +			printf("error: fileread buffer size set\n");
> +			return ret;
> +		}
> +
> +		buffer_reset_pos(source_buffer);
> +
> +		/* set fileread function */
> +		cd->filewrite_func = filewrite_s24;
> +		break;
> +	case(SOF_IPC_FRAME_S32_LE):
> +		/* set downstream buffer size */
> +		ret = buffer_set_size(source_buffer, dev->frames * 4 *
> +				      config->periods_source *
> +					dev->params.channels);
> +		if (ret < 0) {
> +			printf("error: fileread buffer size set\n");
> +			return ret;
> +		}
> +
> +		buffer_reset_pos(source_buffer);
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	dev->state = COMP_STATE_PREPARE;
> +
> +	return 0;
> +}
> +
> +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,
> +		.trigger = filewrite_trigger,
> +		.copy = filewrite_copy,
> +		.prepare = filewrite_prepare,
> +		.reset = filewrite_reset,
> +	},
> +};
> +
> +void sys_comp_filewrite_init(void)
> +{
> +	comp_register(&comp_filewrite);
> +}



More information about the Sound-open-firmware mailing list