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@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 */