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

Liam Girdwood liam.r.girdwood at linux.intel.com
Mon May 7 16:07:40 CEST 2018


On Wed, 2018-05-02 at 21:31 -0700, 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


This should do bit R & W. i.e. we have file.c that can do duplex operations as
this means we can reuse existing SSP based pipelines for test without
modification.

> 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)

buffer_check_wrap_s32() ?

> +{
> +	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;
> +

can you add some comments below on the stages of this loop (and others).

> +	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;
> +}
> +
> +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