[Sound-open-firmware] [RFC PATCH 2/6] host: add new component for file IO

Liam Girdwood liam.r.girdwood at linux.intel.com
Fri Jun 1 18:37:59 CEST 2018


On Thu, 2018-05-31 at 19:29 -0700, Ranjani Sridharan wrote:
> This patch adds a new file component that testbench
> can use to read in samples and write out processed samples. Both
> text and raw pcm input formats are supported.
> 
> Signed-off-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> ---
>  src/host/file.c         | 720 ++++++++++++++++++++++++++++++++++++++++
>  src/include/host/file.h |  77 +++++
>  2 files changed, 797 insertions(+)
>  create mode 100644 src/host/file.c
>  create mode 100644 src/include/host/file.h
> 
> diff --git a/src/host/file.c b/src/host/file.c
> new file mode 100644
> index 0000000..f0d420f
> --- /dev/null
> +++ b/src/host/file.c
> @@ -0,0 +1,720 @@
> +/*
> + * Copyright (c) 2018, 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(s): Seppo Ingalsuo <seppo.ingalsuo at linux.intel.com>
> + *	   Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> + */
> +
> +/* file component for reading/writing pcm samples to/from a file */
> +
> +#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 "host/common_test.h"
> +#include "host/file.h"
> +
> +static inline void buffer_check_wrap_32(int32_t **ptr, int32_t *end,
> +					size_t size)
> +{
> +	if (*ptr >= end)
> +		*ptr = (int32_t *)((size_t)*ptr - size);
> +}
> +
> +static inline void buffer_check_wrap_16(int16_t **ptr, int16_t *end,
> +					size_t size)
> +{
> +	if (*ptr >= end)
> +		*ptr = (int16_t *)((size_t)*ptr - size);
> +}
> +
> +/*
> + * Read 32-bit samples from file
> + * currently only supports txt files
> + */
> +static int read_samples_32(struct comp_dev *dev, struct comp_buffer *sink,
> +			   int n, int fmt, int nch)
> +{
> +	struct file_comp_data *cd = comp_get_drvdata(dev);
> +	int32_t *dest = (int32_t *)sink->w_ptr;
> +	int32_t sample;
> +	int n_samples = 0;
> +	int i, n_wrap, n_min, ret;
> +
> +	while (n > 0) {
> +		n_wrap = (int32_t *)sink->end_addr - dest;
> +
> +		/* check for buffer wrap and copy to the end of the buffer */
> +		n_min = (n < n_wrap) ? n : n_wrap;
> +		while (n_min > 0) {
> +			n -= nch;
> +			n_min -= nch;
> +
> +			/* copy sample per channel */
> +			for (i = 0; i < nch; i++) {
> +				/* read sample from file */
> +				switch (cd->fs.f_format) {

We should really have a reader/write for each type to be optimal.

> +				/* text input file */
> +				case FILE_TEXT:
> +					if (fmt == SOF_IPC_FRAME_S32_LE)
> +						ret = fscanf(cd->fs.rfh,
> "%d",
> +							     dest);
> +
> +					/* mask bits if 24-bit samples */
> +					if (fmt == SOF_IPC_FRAME_S24_4LE) {
> +						ret = fscanf(cd->fs.rfh,
> "%d",
> +							     &sample);
> +						*dest = sample & 0x00ffffff;
> +					}
> +					/* quit if eof is reached */
> +					if (ret == EOF) {
> +						cd->fs.reached_eof = 1;
> +						goto quit;
> +					}
> +					break;
> +
> +				/* raw input file */
> +				default:
> +					if (fmt == SOF_IPC_FRAME_S32_LE)
> +						ret = fread(dest,
> +							    sizeof(int32_t),
> +							    1, cd->fs.rfh);

and freading period at a time is optimal rather than sample by sample.

> +
> +					/* mask bits if 24-bit samples */
> +					if (fmt == SOF_IPC_FRAME_S24_4LE) {
> +						ret = fread(&sample,
> +							    sizeof(int32_t),
> +							    1, cd->fs.rfh);
> +						*dest = sample & 0x00ffffff;
> +					}
> +					/* quit if eof is reached */
> +					if (ret != 1) {
> +						cd->fs.reached_eof = 1;
> +						goto quit;
> +					}
> +					break;
> +				}
> +				dest++;
> +				n_samples++;
> +			}
> +		}
> +		/* check for buffer wrap and update pointer */
> +		buffer_check_wrap_32(&dest, sink->end_addr,
> +				     sink->size);
> +	}
> +quit:
> +	return n_samples;
> +}
> +
> +/*
> + * Read 16-bit samples from file
> + * currently only supports txt files
> + */
> +static int read_samples_16(struct comp_dev *dev, struct comp_buffer *sink,
> +			   int n, int nch)
> +{
> +	struct file_comp_data *cd = comp_get_drvdata(dev);
> +	int16_t *dest = (int16_t *)sink->w_ptr;
> +	int i, n_wrap, n_min, ret;
> +	int n_samples = 0;
> +
> +	/* copy samples */
> +	while (n > 0) {
> +		n_wrap = (int16_t *)sink->end_addr - dest;
> +
> +		/* check for buffer wrap and copy to the end of the buffer */
> +		n_min = (n < n_wrap) ? n : n_wrap;
> +		while (n_min > 0) {
> +			n -= nch;
> +			n_min -= nch;
> +
> +			/* copy sample per channel */
> +			for (i = 0; i < nch; i++) {
> +				/* read sample from file */
> +				ret = fscanf(cd->fs.rfh, "%hd", dest);
> +				switch (cd->fs.f_format) {
> +				/* text input file */
> +				case FILE_TEXT:
> +					ret = fscanf(cd->fs.rfh, "%hd",
> dest);
> +					if (ret == EOF) {
> +						cd->fs.reached_eof = 1;
> +						goto quit;
> +					}
> +					break;
> +
> +				/* rw pcm input file */
> +				default:
> +					ret = fread(dest, sizeof(int16_t), 1,
> +						    cd->fs.rfh);
> +					if (ret != 1) {
> +						cd->fs.reached_eof = 1;
> +						goto quit;
> +					}
> +					break;
> +				}
> +
> +				dest++;
> +				n_samples++;
> +			}
> +		}
> +		/* check for buffer wrap and update pointer */
> +		buffer_check_wrap_16(&dest, sink->end_addr,
> +				     sink->size);
> +	}
> +
> +quit:
> +	return n_samples;
> +}
> +
> +/*
> + * Write 16-bit samples from file
> + * currently only supports txt files
> + */
> +static int write_samples_16(struct comp_dev *dev, struct comp_buffer *source,
> +			    int n, int nch)
> +{
> +	struct file_comp_data *cd = comp_get_drvdata(dev);
> +	int16_t *src = (int16_t *)source->r_ptr;
> +	int i, n_wrap, n_min, ret;
> +	int n_samples = 0;
> +
> +	/* copy samples */
> +	while (n > 0) {
> +		n_wrap = (int16_t *)source->end_addr - src;
> +
> +		/* check for buffer wrap and copy to the end of the buffer */
> +		n_min = (n < n_wrap) ? n : n_wrap;
> +		while (n_min > 0) {
> +			n -= nch;
> +			n_min -= nch;
> +
> +			/* copy sample per channel */
> +			for (i = 0; i < nch; i++) {
> +				switch (cd->fs.f_format) {
> +				/* text output file */
> +				case FILE_TEXT:
> +					ret = fprintf(cd->fs.wfh,
> +						      "%d\n", *src);
> +					if (ret < 0)
> +						goto quit;
> +					break;
> +
> +				/* raw pcm output file */
> +				default:
> +					ret = fwrite(src,
> +						     sizeof(int16_t),
> +						     1, cd->fs.wfh);
> +					if (ret != 1)
> +						goto quit;
> +					break;
> +				}
> +
> +				src++;
> +				n_samples++;
> +			}
> +		}
> +		/* check for buffer wrap and update pointer */
> +		buffer_check_wrap_16(&src, source->end_addr,
> +				     source->size);
> +	}
> +quit:
> +	return n_samples;
> +}
> +
> +/*
> + * Write 32-bit samples from file
> + * currently only supports txt files
> + */
> +static int write_samples_32(struct comp_dev *dev, struct comp_buffer *source,
> +			    int n, int fmt, int nch)
> +{
> +	struct file_comp_data *cd = comp_get_drvdata(dev);
> +	int32_t *src = (int32_t *)source->r_ptr;
> +	int i, n_wrap, n_min, ret;
> +	int n_samples = 0;
> +	int32_t sample;
> +
> +	/* copy samples */
> +	while (n > 0) {
> +		n_wrap = (int32_t *)source->end_addr - src;
> +
> +		/* check for buffer wrap and copy to the end of the buffer */
> +		n_min = (n < n_wrap) ? n : n_wrap;
> +		while (n_min > 0) {
> +			n -= nch;
> +			n_min -= nch;
> +
> +			/* copy sample per channel */
> +			for (i = 0; i < nch; i++) {
> +				switch (cd->fs.f_format) {
> +				/* text output file */
> +				case FILE_TEXT:
> +					if (fmt == SOF_IPC_FRAME_S32_LE)
> +						ret = fprintf(cd->fs.wfh,
> +							      "%d\n", *src);
> +					if (fmt == SOF_IPC_FRAME_S24_4LE) {
> +						sample = *src << 8;
> +						ret = fprintf(cd->fs.wfh,
> +							      "%d\n",
> +							      sample >> 8);
> +					}
> +					if (ret < 0)
> +						goto quit;
> +					break;
> +
> +				/* raw pcm output file */
> +				default:
> +					if (fmt == SOF_IPC_FRAME_S32_LE)
> +						ret = fwrite(src,
> +							     sizeof(int32_t),
> +							     1, cd->fs.wfh);
> +					if (fmt == SOF_IPC_FRAME_S24_4LE) {
> +						sample = *src << 8;
> +						sample >>= 8;
> +						ret = fwrite(&sample,
> +							     sizeof(int32_t),
> +							     1, cd->fs.wfh);
> +					}
> +					if (ret != 1)
> +						goto quit;
> +					break;
> +				}
> +
> +				/* increment read pointer */
> +				src++;
> +
> +				/* increment number of samples written */
> +				n_samples++;
> +			}
> +		}
> +		/* check for buffer wrap and update pointer */
> +		buffer_check_wrap_32(&src, source->end_addr,
> +				     source->size);
> +	}
> +quit:
> +	return n_samples;
> +}
> +
> +/* function for processing 32-bit samples */
> +static int file_s32_default(struct comp_dev *dev, struct comp_buffer *sink,
> +			    struct comp_buffer *source, uint32_t frames)
> +{
> +	struct file_comp_data *cd = comp_get_drvdata(dev);
> +	int nch = dev->params.channels;
> +	int n_samples = 0;
> +
> +	switch (cd->fs.mode) {
> +	case FILE_READ:
> +		/* read samples */
> +		n_samples = read_samples_32(dev, sink, frames * nch,
> +					    SOF_IPC_FRAME_S32_LE, nch);
> +		break;
> +	case FILE_WRITE:
> +		/* write samples */
> +		n_samples = write_samples_32(dev, source, frames * nch,
> +					     SOF_IPC_FRAME_S32_LE, nch);
> +		break;
> +	default:
> +		/* TODO: duplex mode */
> +		break;
> +	}
> +
> +	cd->fs.n += n_samples;
> +	return n_samples;
> +}
> +
> +/* function for processing 16-bit samples */
> +static int file_s16(struct comp_dev *dev, struct comp_buffer *sink,
> +		    struct comp_buffer *source, uint32_t frames)
> +{
> +	struct file_comp_data *cd = comp_get_drvdata(dev);
> +	int nch = dev->params.channels;
> +	int n_samples = 0;
> +
> +	switch (cd->fs.mode) {
> +	case FILE_READ:
> +		/* read samples */
> +		n_samples = read_samples_16(dev, sink, frames * nch, nch);
> +		break;
> +	case FILE_WRITE:
> +		/* write samples */
> +		n_samples = write_samples_16(dev, source, frames * nch, nch);
> +		break;
> +	default:
> +		/* TODO: duplex mode */
> +		break;
> +	}
> +
> +	cd->fs.n += n_samples;
> +	return n_samples;
> +}
> +
> +/* function for processing 24-bit samples */
> +static int file_s24(struct comp_dev *dev, struct comp_buffer *sink,
> +		    struct comp_buffer *source, uint32_t frames)
> +{
> +	struct file_comp_data *cd = comp_get_drvdata(dev);
> +	int nch = dev->params.channels;
> +	int n_samples = 0;
> +
> +	switch (cd->fs.mode) {
> +	case FILE_READ:
> +		/* read samples */
> +		n_samples = read_samples_32(dev, sink, frames * nch,
> +					    SOF_IPC_FRAME_S24_4LE, nch);
> +		break;
> +	case FILE_WRITE:
> +		/* write samples */
> +		n_samples = write_samples_32(dev, source, frames * nch,
> +					     SOF_IPC_FRAME_S24_4LE, nch);
> +		break;
> +	default:
> +		/* TODO: duplex mode */
> +		break;
> +	}
> +
> +	cd->fs.n += n_samples;
> +	return n_samples;
> +}
> +
> +static enum file_format get_file_format(char *filename)
> +{
> +	char *ext = strrchr(filename, '.');
> +
> +	if (!strcmp(ext, ".txt"))
> +		return FILE_TEXT;
> +
> +	return FILE_RAW;
> +}
> +
> +static struct comp_dev *file_new(struct sof_ipc_comp *comp)
> +{
> +	struct comp_dev *dev;
> +	struct sof_ipc_comp_file *file;
> +	struct sof_ipc_comp_file *ipc_file =
> +		(struct sof_ipc_comp_file *)comp;
> +	struct file_comp_data *cd;
> +
> +	/* allocate memory for file comp */
> +	dev = malloc(COMP_SIZE(struct sof_ipc_comp_file));
> +	if (!dev)
> +		return NULL;
> +
> +	/* copy file comp config */
> +	file = (struct sof_ipc_comp_file *)&dev->comp;
> +	memcpy(file, ipc_file, sizeof(struct sof_ipc_comp_file));
> +
> +	/* allocate  memory for file comp data */
> +	cd = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, sizeof(*cd));
> +	if (!cd) {
> +		free(dev);
> +		return NULL;
> +	}
> +
> +	comp_set_drvdata(dev, cd);
> +
> +	/* default function for processing samples */
> +	cd->file_func = file_s32_default;
> +
> +	/* get filename from IPC and open file */
> +	cd->fs.fn = strdup(ipc_file->fn);
> +
> +	/* set file format */
> +	cd->fs.f_format = get_file_format(cd->fs.fn);
> +
> +	/* set file comp mode */
> +	cd->fs.mode = ipc_file->mode;
> +
> +	/* open file handle(s) depending on mode */
> +	switch (cd->fs.mode) {
> +	case FILE_READ:
> +		cd->fs.rfh = fopen(cd->fs.fn, "r");
> +		if (!cd->fs.rfh) {
> +			fprintf(stderr, "error: opening file %s\n", cd-
> >fs.fn);
> +			free(cd);
> +			free(dev);
> +			return NULL;
> +		}
> +		break;
> +	case FILE_WRITE:
> +		cd->fs.wfh = fopen(cd->fs.fn, "w");
> +		if (!cd->fs.wfh) {
> +			fprintf(stderr, "error: opening file %s\n", cd-
> >fs.fn);
> +			free(cd);
> +			free(dev);
> +			return NULL;
> +		}
> +		break;
> +	default:
> +		/* TODO: duplex mode */
> +		break;
> +	}
> +
> +	cd->fs.reached_eof = 0;
> +	cd->fs.n = 0;
> +
> +	dev->state = COMP_STATE_READY;
> +
> +	return dev;
> +}
> +
> +static void file_free(struct comp_dev *dev)
> +{
> +	struct file_comp_data *cd = comp_get_drvdata(dev);
> +
> +	if (cd->fs.mode == FILE_READ)
> +		fclose(cd->fs.rfh);
> +	else
> +		fclose(cd->fs.wfh);
> +
> +	free(cd->fs.fn);
> +	free(cd);
> +	free(dev);
> +
> +	debug_print("free file component\n");
> +}
> +
> +/* set component audio stream parameters */
> +static int file_params(struct comp_dev *dev)
> +{
> +	struct file_comp_data *cd = comp_get_drvdata(dev);
> +	struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
> +
> +	/* for file endpoint set the following from topology config */
> +	if (cd->fs.mode == FILE_WRITE) {
> +		dev->params.frame_fmt = config->frame_fmt;
> +		if (dev->params.frame_fmt == SOF_IPC_FRAME_S16_LE)
> +			dev->params.sample_container_bytes = 2;
> +		else
> +			dev->params.sample_container_bytes = 4;
> +	}
> +
> +	/* 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 file_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 file_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 samples
> + * returns the number of bytes copied
> + */
> +static int file_copy(struct comp_dev *dev)
> +{
> +	struct comp_buffer *buffer;
> +	struct file_comp_data *cd = comp_get_drvdata(dev);
> +	int ret = 0, bytes;
> +
> +	switch (cd->fs.mode) {
> +	case FILE_READ:
> +		/* file component sink buffer */
> +		buffer = list_first_item(&dev->bsink_list, struct
> comp_buffer,
> +					 source_list);
> +
> +		/* test sink has enough free frames */
> +		if (buffer->free >= cd->period_bytes && !cd->fs.reached_eof)
> {
> +			/* read PCM samples from file */
> +			ret = cd->file_func(dev, buffer, NULL, dev->frames);
> +
> +			/* update sink buffer pointers */
> +			bytes = dev->params.sample_container_bytes;
> +			if (ret > 0)
> +				comp_update_buffer_produce(buffer,
> +							   ret * bytes);
> +		}
> +		break;
> +	case FILE_WRITE:
> +		/* file component source buffer */
> +		buffer = list_first_item(&dev->bsource_list,
> +					 struct comp_buffer, sink_list);
> +
> +		/* test source has enough free frames */
> +		if (buffer->avail >= cd->period_bytes) {
> +			/* write PCM samples into file */
> +			ret = cd->file_func(dev, NULL, buffer, dev->frames);
> +
> +			/* update source buffer pointers */
> +			bytes = dev->params.sample_container_bytes;
> +			if (ret > 0)
> +				comp_update_buffer_consume(buffer,
> +							   ret * bytes);
> +		}
> +		break;
> +	default:
> +		/* TODO: duplex mode */
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static int file_prepare(struct comp_dev *dev)
> +{
> +	struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
> +	struct comp_buffer *buffer = NULL;
> +	struct file_comp_data *cd = comp_get_drvdata(dev);
> +	int ret = 0, periods;
> +
> +	/* file component sink/source buffer period count */
> +	switch (cd->fs.mode) {
> +	case FILE_READ:
> +		buffer = list_first_item(&dev->bsink_list, struct
> comp_buffer,
> +					 source_list);
> +		periods = config->periods_sink;
> +		break;
> +	case FILE_WRITE:
> +		buffer = list_first_item(&dev->bsource_list,
> +					 struct comp_buffer, sink_list);
> +		periods = config->periods_source;
> +		break;
> +	default:
> +		/* TODO: duplex mode */
> +		break;
> +	}
> +
> +	if (!buffer) {
> +		printf("error: no sink/source buffer\n");
> +		return -EINVAL;
> +	}
> +
> +	/* set downstream buffer size */
> +	switch (config->frame_fmt) {
> +	case(SOF_IPC_FRAME_S16_LE):
> +		ret = buffer_set_size(buffer, dev->frames * 2 *
> +			periods * dev->params.channels);
> +		if (ret < 0) {
> +			printf("error: file buffer size set\n");
> +			return ret;
> +		}
> +		buffer_reset_pos(buffer);
> +
> +		/* set file function */
> +		cd->file_func = file_s16;
> +		break;
> +	case(SOF_IPC_FRAME_S24_4LE):
> +		ret = buffer_set_size(buffer, dev->frames * 4 *
> +			periods * dev->params.channels);
> +		if (ret < 0) {
> +			fprintf(stderr, "error: file buffer size set\n");
> +			return ret;
> +		}
> +		buffer_reset_pos(buffer);
> +
> +		/* set file function */
> +		cd->file_func = file_s24;
> +		break;
> +	case(SOF_IPC_FRAME_S32_LE):
> +		ret = buffer_set_size(buffer, dev->frames * 4 *
> +			periods * dev->params.channels);
> +		if (ret < 0) {
> +			fprintf(stderr, "error: file buffer size set\n");
> +			return ret;
> +		}
> +		buffer_reset_pos(buffer);
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	dev->state = COMP_STATE_PREPARE;
> +
> +	return ret;
> +}
> +
> +static int file_reset(struct comp_dev *dev)
> +{
> +	dev->state = COMP_STATE_INIT;
> +
> +	return 0;
> +}
> +
> +struct comp_driver comp_file = {
> +	.type = SOF_COMP_FILEREAD,
> +	.ops = {
> +		.new = file_new,
> +		.free = file_free,
> +		.params = file_params,
> +		.cmd = file_cmd,
> +		.trigger = file_trigger,
> +		.copy = file_copy,
> +		.prepare = file_prepare,
> +		.reset = file_reset,
> +	},
> +};
> +
> +void sys_comp_file_init(void)
> +{
> +	comp_register(&comp_file);
> +}
> diff --git a/src/include/host/file.h b/src/include/host/file.h
> new file mode 100644
> index 0000000..777b26d
> --- /dev/null
> +++ b/src/include/host/file.h
> @@ -0,0 +1,77 @@
> +/*
> + * Copyright (c) 2018, 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>
> + *	   Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> + */
> +#ifndef _FILE_H
> +#define _FILE_H
> +
> +/* file component modes */
> +enum file_mode {
> +	FILE_READ = 0,
> +	FILE_WRITE,
> +	FILE_DUPLEX,
> +};
> +
> +enum file_format {
> +	FILE_TEXT = 0,
> +	FILE_RAW,
> +};
> +
> +/* file component state */
> +struct file_state {
> +	char *fn;
> +	FILE *rfh, *wfh; /* read/write file handle */
> +	int reached_eof;
> +	int n;
> +	enum file_mode mode;
> +	enum file_format f_format;
> +};
> +
> +/* file comp data */
> +struct file_comp_data {
> +	uint32_t period_bytes;
> +	uint32_t channels;
> +	uint32_t frame_bytes;
> +	uint32_t rate;
> +	struct file_state fs;
> +	int (*file_func)(struct comp_dev *dev, struct comp_buffer *sink,
> +			 struct comp_buffer *source, uint32_t frames);
> +
> +};
> +
> +/* file IO ipc comp */
> +struct sof_ipc_comp_file {
> +	struct sof_ipc_comp comp;
> +	struct sof_ipc_comp_config config;
> +	char *fn;
> +	enum file_mode mode;
> +};
> +#endif


More information about the Sound-open-firmware mailing list