[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