SRC updates sink and downstream pipeline PCM rate, period_count and
period_bytes in src_params() according to received out_rate via IPC.
Also the use of incorrect alloc_size is replaced by ipc_buffer.size.
Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo(a)linux.intel.com>
---
src/audio/src.c | 90 ++++++++++++++++++++++++-----------------
src/include/reef/audio/buffer.h | 8 ++--
src/include/uapi/ipc.h | 1 +
3 files changed, 57 insertions(+), 42 deletions(-)
diff --git a/src/audio/src.c b/src/audio/src.c
index c338220..f1f4b86 100644
--- a/src/audio/src.c
+++ b/src/audio/src.c
@@ -56,9 +56,13 @@
/* src component private data */
struct comp_data {
struct polyphase_src src[PLATFORM_MAX_CHANNELS];
+ /* Next two elements must be kept in this order since
+ * the end of pcm_params is a flexible array.
+ */
+ struct sof_ipc_pcm_params pcm_params;
+ enum sof_ipc_chmap channel_map[PLATFORM_MAX_CHANNELS];
int32_t *delay_lines;
int scratch_length;
- //int32_t z[STAGE_BUF_SIZE];
void (*src_func)(struct comp_dev *dev,
struct comp_buffer *source,
struct comp_buffer *sink,
@@ -155,7 +159,7 @@ static void src_2s_s32_default(struct comp_dev *dev,
s1.times = n_times1;
s1.x_end_addr = source->end_addr;
- s1.x_size = source->alloc_size;
+ s1.x_size = source->ipc_buffer.size;
s1.x_inc = nch;
s1.y_end_addr = &cd->delay_lines[cd->scratch_length];
s1.y_size = STAGE_BUF_SIZE * sizeof(int32_t);
@@ -166,7 +170,7 @@ static void src_2s_s32_default(struct comp_dev *dev,
s2.x_size = STAGE_BUF_SIZE * sizeof(int32_t);
s2.x_inc = 1;
s2.y_end_addr = sink->end_addr;
- s2.y_size = sink->alloc_size;
+ s2.y_size = sink->ipc_buffer.size;
s2.y_inc = nch;
s1.x_rptr = src + nch - 1;
@@ -227,10 +231,10 @@ static void src_1s_s32_default(struct comp_dev *dev,
s1.times = n_times;
s1.x_end_addr = source->end_addr;
- s1.x_size = source->alloc_size;
+ s1.x_size = source->ipc_buffer.size;
s1.x_inc = nch;
s1.y_end_addr = sink->end_addr;
- s1.y_size = sink->alloc_size;
+ s1.y_size = sink->ipc_buffer.size;
s1.y_inc = nch;
s1.x_rptr = src + nch - 1;
s1.y_wptr = dest + nch - 1;
@@ -263,7 +267,7 @@ static struct comp_dev *src_new(struct sof_ipc_comp *comp)
{
struct comp_dev *dev;
struct sof_ipc_comp_src *src;
- struct sof_ipc_comp_src *ipc_src = (struct sof_ipc_comp_src *)comp;
+ struct sof_ipc_comp_src *ipc_src = (struct sof_ipc_comp_src *) comp;
struct comp_data *cd;
int i;
@@ -274,7 +278,7 @@ static struct comp_dev *src_new(struct sof_ipc_comp *comp)
if (dev == NULL)
return NULL;
- src = (struct sof_ipc_comp_src *)&dev->comp;
+ src = (struct sof_ipc_comp_src *) &dev->comp;
memcpy(src, ipc_src, sizeof(struct sof_ipc_comp_src));
cd = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd));
@@ -317,6 +321,7 @@ static int src_params(struct comp_dev *dev, struct stream_params *params)
int32_t *buffer_start;
int n = 0;
struct comp_data *cd = comp_get_drvdata(dev);
+ struct sof_ipc_comp_src *src = (struct sof_ipc_comp_src *) &dev->comp;
trace_src("SPa");
@@ -325,23 +330,43 @@ static int src_params(struct comp_dev *dev, struct stream_params *params)
|| (params->pcm->frame_fmt != SOF_IPC_FRAME_S32_LE))
return -EINVAL;
- /* No data transformation */
- comp_set_sink_params(dev, params);
-
- /* Allocate needed memory for delay lines */
source = list_first_item(&dev->bsource_list, struct comp_buffer,
sink_list);
sink = list_first_item(&dev->bsink_list, struct comp_buffer,
source_list);
- src_buffer_lengths(&need, source->params.pcm->rate,
- sink->params.pcm->rate, source->params.pcm->channels);
+
+ /* Copy PCM stream parameters and the channel map array */
+ memcpy(&cd->pcm_params, &(*params->pcm),
+ sizeof(struct sof_ipc_pcm_params));
+ for (i = 0; i < params->pcm->channels; i++)
+ cd->pcm_params.channel_map[i] = params->pcm->channel_map[i];
+
+ /* Point sink stream parameters to copy */
+ sink->params.pcm = &cd->pcm_params;
+
+ /* Stored IPC from src_new() contains the output rate for sink,
+ * set the new rate for sink.
+ */
+ sink->params.pcm->rate = src->out_rate;
+
+ /* Adjust sink buffer parameters to match fs_out/fs_in */
+ sink->params.pcm->period_count = sink->params.pcm->period_count
+ * sink->params.pcm->rate / source->params.pcm->rate;
+ sink->params.pcm->period_bytes = sink->params.pcm->period_bytes
+ * sink->params.pcm->rate / source->params.pcm->rate;
+
+ /* Allocate needed memory for delay lines */
+ if (src_buffer_lengths(&need, source->params.pcm->rate,
+ sink->params.pcm->rate, source->params.pcm->channels) < 0)
+ return -EINVAL;
+
delay_lines_size = sizeof(int32_t) * need.total;
if (cd->delay_lines != NULL)
rfree(cd->delay_lines);
cd->delay_lines = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, delay_lines_size);
if (cd->delay_lines == NULL)
- return -EINVAL;
+ return -ENOMEM;
/* Clear all delay lines here */
memset(cd->delay_lines, 0, delay_lines_size);
@@ -369,19 +394,20 @@ static int src_params(struct comp_dev *dev, struct stream_params *params)
*/
trace_src("SFa");
cd->src_func = fallback_s32;
- return(-EINVAL);
- break;
+ rfree(cd->delay_lines);
+ return -EINVAL;
}
/* Check that src blk_in and blk_out are less than params.period_frames.
* Return an error if the period is too short.
*/
- if (src_polyphase_get_blk_in(&cd->src[0]) > source->params.pcm->period_count)
- return(-EINVAL);
-
- if (src_polyphase_get_blk_out(&cd->src[0]) > sink->params.pcm->period_count)
- return(-EINVAL);
+ if (src_polyphase_get_blk_in(&cd->src[0])
+ > source->params.pcm->period_count)
+ return -EINVAL;
+ if (src_polyphase_get_blk_out(&cd->src[0])
+ > sink->params.pcm->period_count)
+ return -EINVAL;
return 0;
}
@@ -453,7 +479,8 @@ static int src_copy(struct comp_dev *dev)
struct comp_buffer *sink;
uint32_t frames_source;
uint32_t frames_sink;
- int need_source, need_sink, min_frames;
+ int need_source, need_sink;
+ // int min_frames;
trace_comp("SRC");
@@ -464,25 +491,12 @@ static int src_copy(struct comp_dev *dev)
source_list);
/* Check that source has enough frames available and sink enough
- * frames free.
+ * frames free. Increase tried period_count if not sufficient to run.
*/
frames_source = source->params.pcm->period_count;
frames_sink = sink->params.pcm->period_count;
- min_frames = src_polyphase_get_blk_in(&cd->src[0]);
- if (frames_source > min_frames)
- need_source = frames_source * source->params.pcm->frame_size;
- else {
- frames_source = min_frames;
- need_source = min_frames * source->params.pcm->frame_size;
- }
-
- min_frames = src_polyphase_get_blk_out(&cd->src[0]);
- if (frames_sink > min_frames)
- need_sink = frames_sink * sink->params.pcm->frame_size;
- else {
- frames_sink = min_frames;
- need_sink = min_frames * sink->params.pcm->frame_size;
- }
+ need_source = source->params.pcm->period_bytes;
+ need_sink = sink->params.pcm->period_bytes;
/* Run as many times as buffers allow */
while ((source->avail >= need_source) && (sink->free >= need_sink)) {
diff --git a/src/include/reef/audio/buffer.h b/src/include/reef/audio/buffer.h
index 5f2dbb7..0817a40 100644
--- a/src/include/reef/audio/buffer.h
+++ b/src/include/reef/audio/buffer.h
@@ -119,20 +119,20 @@ static inline void comp_update_sink_free_avail(struct comp_buffer *snk, int n)
static inline void comp_wrap_source_r_ptr_circular(struct comp_buffer *src)
{
if (src->r_ptr >= src->end_addr)
- src->r_ptr -= src->alloc_size;
+ src->r_ptr -= src->ipc_buffer.size;
if (src->r_ptr < src->addr)
- src->r_ptr += src->alloc_size;
+ src->r_ptr += src->ipc_buffer.size;
}
static inline void comp_wrap_sink_w_ptr_circular(struct comp_buffer *snk)
{
if (snk->w_ptr >= snk->end_addr)
- snk->w_ptr -= snk->alloc_size;
+ snk->w_ptr -= snk->ipc_buffer.size;
if (snk->w_ptr < snk->addr)
- snk->w_ptr += snk->alloc_size;
+ snk->w_ptr += snk->ipc_buffer.size;
}
#endif
diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h
index 3d78db3..d89039e 100644
--- a/src/include/uapi/ipc.h
+++ b/src/include/uapi/ipc.h
@@ -488,6 +488,7 @@ struct sof_ipc_comp_src {
struct sof_ipc_pcm_comp pcm;
uint32_t in_mask; /* SOF_RATE_ supported input rates */
uint32_t out_mask; /* SOF_RATE_ supported output rates */
+ int32_t out_rate;
} __attribute__((packed));
/* generic MUX component */
--
2.11.0