blob: 993c76b215f719515ad6fa012b57e4fe0f6b47bd [file] [log] [blame]
Seppo Ingalsuo6a274832017-06-07 14:17:55 +03001/*
2 * Copyright (c) 2017, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the Intel Corporation nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
29 * Liam Girdwood <liam.r.girdwood@linux.intel.com>
30 * Keyon Jie <yang.jie@linux.intel.com>
31 */
32
33#include <stdint.h>
34#include <stddef.h>
35#include <errno.h>
36#include <reef/reef.h>
37#include <reef/lock.h>
38#include <reef/list.h>
39#include <reef/stream.h>
40#include <reef/alloc.h>
41#include <reef/work.h>
42#include <reef/clock.h>
43#include <reef/audio/component.h>
44#include <reef/audio/pipeline.h>
Liam Girdwood17641522017-06-09 17:27:02 +010045#include <uapi/ipc.h>
Seppo Ingalsuo6a274832017-06-07 14:17:55 +030046#include "src_core.h"
47
48#ifdef MODULE_TEST
49#include <stdio.h>
50#endif
51
52#define trace_src(__e) trace_event(TRACE_CLASS_SRC, __e)
53#define tracev_src(__e) tracev_event(TRACE_CLASS_SRC, __e)
54#define trace_src_error(__e) trace_error(TRACE_CLASS_SRC, __e)
55
56/* src component private data */
57struct comp_data {
58 struct polyphase_src src[PLATFORM_MAX_CHANNELS];
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +030059 struct src_param param;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +030060 int32_t *delay_lines;
Liam Girdwood3488cce2017-08-10 11:59:08 +010061 uint32_t sink_rate;
62 uint32_t source_rate;
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +030063 int32_t *sbuf_w_ptr;
64 int32_t *sbuf_r_ptr;
65 int sbuf_avail;
Seppo Ingalsuo887628a2017-09-14 16:00:05 +030066 int sign_extend_s24; /* Set if need to copy sign bit to b24..b31 */
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +030067 void (* src_func)(struct comp_dev *dev,
Seppo Ingalsuo6a274832017-06-07 14:17:55 +030068 struct comp_buffer *source,
69 struct comp_buffer *sink,
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +030070 size_t *consumed,
71 size_t *produced);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +030072};
73
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +030074/* Fallback function */
75static void fallback_s32(struct comp_dev *dev, struct comp_buffer *source,
76 struct comp_buffer *sink, size_t *bytes_read, size_t *bytes_written)
Seppo Ingalsuo6a274832017-06-07 14:17:55 +030077{
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +030078 *bytes_read = 0;
79 *bytes_written = 0;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +030080}
81
82/* Normal 2 stage SRC */
83static void src_2s_s32_default(struct comp_dev *dev,
84 struct comp_buffer *source, struct comp_buffer *sink,
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +030085 size_t *bytes_read, size_t *bytes_written)
Seppo Ingalsuo6a274832017-06-07 14:17:55 +030086{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +030087 struct polyphase_src *s;
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -050088 struct src_stage_prm s1;
89 struct src_stage_prm s2;
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +030090 int j;
91 struct comp_data *cd = comp_get_drvdata(dev);
92 int32_t *dest = (int32_t *) sink->w_ptr;
93 int32_t *src = (int32_t *) source->r_ptr;
94 int32_t *sbuf_addr = cd->delay_lines;
95 int32_t *sbuf_end_addr = &cd->delay_lines[cd->param.sbuf_length];
96 int32_t sbuf_size = cd->param.sbuf_length * sizeof(int32_t);
97 const int nch = dev->params.channels;
98 const int s1_blk_in = cd->src[0].stage1->blk_in * nch;
99 const int s1_blk_out = cd->src[0].stage1->blk_out * nch;
100 const int s2_blk_in = cd->src[0].stage2->blk_in * nch;
101 const int s2_blk_out = cd->src[0].stage2->blk_out * nch;
102 int sbuf_free = cd->param.sbuf_length - cd->sbuf_avail;
103 int source_check = (source->avail >> 2) - s1_blk_in; /* for int32_t */
104 int sink_check = (sink->free >> 2) - s2_blk_out; /* For int32_t */
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300105 int n_read = 0;
106 int n_written = 0;
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300107 int n1 = 0;
108 int n2 = 0;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300109
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300110 s1.times = 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300111 s1.x_end_addr = source->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100112 s1.x_size = source->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300113 s1.x_inc = nch;
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300114 s1.y_end_addr = sbuf_end_addr;
115 s1.y_size = sbuf_size;
116 s1.y_inc = nch;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300117
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300118 s2.times = 1;
119 s2.x_end_addr = sbuf_end_addr;
120 s2.x_size = sbuf_size;
121 s2.x_inc = nch;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300122 s2.y_end_addr = sink->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100123 s2.y_size = sink->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300124 s2.y_inc = nch;
125
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300126 /* 1st stage runs once a long multiplied length block.
127 * The stage buffer much be large enough to fit one s1 output block
128 * plus one s2 input block plus jitter in s2 consumption.
129 */
130 while ((n1 < cd->param.stage1_times_max)
131 && (n_read <= source_check)
132 && (sbuf_free >= s1_blk_out)) {
133 for (j = 0; j < nch; j++) {
134 s = &cd->src[j]; /* Point to src[] for this channel */
135 s1.x_rptr = src++;
136 s1.y_wptr = cd->sbuf_w_ptr++;
137 src_circ_inc_wrap(&src, source->end_addr, source->size);
138 src_circ_inc_wrap(&cd->sbuf_w_ptr, sbuf_end_addr, sbuf_size);
139 s1.state = &s->state1;
140 s1.stage = s->stage1;
141 if (cd->sign_extend_s24)
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300142 src_polyphase_stage_cir_s24(&s1);
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300143 else
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300144 src_polyphase_stage_cir(&s1);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300145
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300146 }
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300147 n_read += s1_blk_in;
148 cd->sbuf_avail += s1_blk_out;
149 sbuf_free -= s1_blk_out;
150 src = s1.x_rptr - nch + 1;
151 cd->sbuf_w_ptr = s1.y_wptr - nch + 1;
152 src_circ_dec_wrap(&src, source->addr, source->size);
153 src_circ_dec_wrap(&cd->sbuf_w_ptr, sbuf_addr, sbuf_size);
154 n1++;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300155 }
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300156
157 /* 2nd stage runs as many min size blocks as buffers allow */
158 while ((n2 < cd->param.stage2_times_max)
159 && (cd->sbuf_avail >= s2_blk_in)
160 && (n_written <= sink_check)) {
161 for (j = 0; j < nch; j++) {
162 s2.x_rptr = cd->sbuf_r_ptr++;
163 s2.y_wptr = dest++;
164 src_circ_inc_wrap(&cd->sbuf_r_ptr, sbuf_end_addr, sbuf_size);
165 src_circ_inc_wrap(&dest, sink->end_addr, sink->size);
166 s = &cd->src[j]; /* Point to src[] for this channel */
167 s2.state = &s->state2;
168 s2.stage = s->stage2;
169 if (cd->sign_extend_s24)
170 src_polyphase_stage_cir_s24(&s2);
171 else
172 src_polyphase_stage_cir(&s2);
173
174 }
175 cd->sbuf_r_ptr = s2.x_rptr - nch + 1;
176 dest = s2.y_wptr - nch + 1;
177 src_circ_dec_wrap(&cd->sbuf_r_ptr, sbuf_addr, sbuf_size);
178 src_circ_dec_wrap(&dest, sink->addr, sink->size);
179 n_written += s2_blk_out;
180 cd->sbuf_avail -= s2_blk_in;
181 n2++;
182 }
183 *bytes_read = sizeof(int32_t) * n_read;
184 *bytes_written = sizeof(int32_t) * n_written;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300185}
186
187/* 1 stage SRC for simple conversions */
188static void src_1s_s32_default(struct comp_dev *dev,
189 struct comp_buffer *source, struct comp_buffer *sink,
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300190 size_t *bytes_read, size_t *bytes_written)
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300191{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300192 struct polyphase_src *s;
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300193 struct src_stage_prm s1;
194 int j;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300195 struct comp_data *cd = comp_get_drvdata(dev);
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300196 int32_t *dest = (int32_t *) sink->w_ptr;
197 int32_t *src = (int32_t *) source->r_ptr;
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300198 int nch = dev->params.channels;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300199 int n_read = 0;
200 int n_written = 0;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300201
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300202 s1.times = cd->param.stage1_times;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300203 s1.x_end_addr = source->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100204 s1.x_size = source->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300205 s1.x_inc = nch;
206 s1.y_end_addr = sink->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100207 s1.y_size = sink->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300208 s1.y_inc = nch;
Seppo Ingalsuo6f27ab62017-06-12 11:31:15 +0300209 s1.x_rptr = src + nch - 1;
210 s1.y_wptr = dest + nch - 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300211
212 for (j = 0; j < nch; j++) {
213 s = &cd->src[j]; /* Point to src for this channel */
214 s1.x_rptr = src++;
215 s1.y_wptr = dest++;
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300216 src_circ_inc_wrap(&src, source->end_addr, source->size);
217 src_circ_inc_wrap(&dest, sink->end_addr, sink->size);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300218 s1.state = &s->state1;
219 s1.stage = s->stage1;
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300220 if (cd->sign_extend_s24)
221 src_polyphase_stage_cir_s24(&s1);
222 else
223 src_polyphase_stage_cir(&s1);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300224
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300225 n_read += cd->param.blk_in;
226 n_written += cd->param.blk_out;
227 }
228 *bytes_read = n_read * sizeof(int32_t);
229 *bytes_written = n_written * sizeof(int32_t);
230}
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300231
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300232/* A fast copy function for same in and out rate */
233static void src_copy_s32_default(struct comp_dev *dev,
234 struct comp_buffer *source, struct comp_buffer *sink,
235 size_t *bytes_read, size_t *bytes_written)
236{
237 struct comp_data *cd = comp_get_drvdata(dev);
238 int32_t *src = (int32_t *) source->r_ptr;
239 int32_t *snk = (int32_t *) sink->w_ptr;
240 int nch = dev->params.channels;
241 int frames = cd->param.blk_in;
242 int n;
243 int n_wrap_src;
244 int n_wrap_snk;
245 int n_wrap_min;
246 int n_copy;
247
248 n = frames * nch;
249 while (n > 0) {
250 n_wrap_src = (int32_t *) source->end_addr - src;
251 n_wrap_snk = (int32_t *) sink->end_addr - snk;
252 n_wrap_min = (n_wrap_src < n_wrap_snk) ? n_wrap_src : n_wrap_snk;
253 n_copy = (n < n_wrap_min) ? n : n_wrap_min;
254 memcpy(snk, src, n_copy * sizeof(int32_t));
255
256 /* Update and check both source and destination for wrap */
257 n -= n_copy;
258 src += n_copy;
259 snk += n_copy;
260 src_circ_inc_wrap(&src, source->end_addr, source->size);
261 src_circ_inc_wrap(&snk, sink->end_addr, sink->size);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300262
263 }
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300264 *bytes_read = frames * nch * sizeof(int32_t);
265 *bytes_written = frames * nch * sizeof(int32_t);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300266}
267
268static struct comp_dev *src_new(struct sof_ipc_comp *comp)
269{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300270 struct comp_dev *dev;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100271 struct sof_ipc_comp_src *src;
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300272 struct sof_ipc_comp_src *ipc_src = (struct sof_ipc_comp_src *) comp;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300273 struct comp_data *cd;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100274 int i;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300275
Liam Girdwood3488cce2017-08-10 11:59:08 +0100276 trace_src("new");
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100277
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100278 /* validate init data - either SRC sink or source rate must be set */
279 if (ipc_src->source_rate == 0 && ipc_src->sink_rate == 0) {
280 trace_src_error("sn1");
281 return NULL;
282 }
283
Liam Girdwood3488cce2017-08-10 11:59:08 +0100284 dev = rzalloc(RZONE_RUNTIME, RFLAGS_NONE,
Liam Girdwood17641522017-06-09 17:27:02 +0100285 COMP_SIZE(struct sof_ipc_comp_src));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300286 if (dev == NULL)
287 return NULL;
288
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300289 src = (struct sof_ipc_comp_src *) &dev->comp;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100290 memcpy(src, ipc_src, sizeof(struct sof_ipc_comp_src));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300291
Liam Girdwood3488cce2017-08-10 11:59:08 +0100292 cd = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300293 if (cd == NULL) {
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300294 rfree(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300295 return NULL;
296 }
297
298 comp_set_drvdata(dev, cd);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300299
300 cd->delay_lines = NULL;
301 cd->src_func = src_2s_s32_default;
302 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
303 src_polyphase_reset(&cd->src[i]);
304
Liam Girdwoodbe41b682017-09-21 16:48:18 +0100305 dev->state = COMP_STATE_READY;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300306 return dev;
307}
308
309static void src_free(struct comp_dev *dev)
310{
311 struct comp_data *cd = comp_get_drvdata(dev);
312
Liam Girdwood3488cce2017-08-10 11:59:08 +0100313 trace_src("fre");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300314
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300315 /* Free dynamically reserved buffers for SRC algorithm */
316 if (cd->delay_lines != NULL)
317 rfree(cd->delay_lines);
318
319 rfree(cd);
320 rfree(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300321}
322
323/* set component audio stream parameters */
Liam Girdwood2cfaebe2017-08-21 17:13:52 +0100324static int src_params(struct comp_dev *dev)
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300325{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100326 struct sof_ipc_stream_params *params = &dev->params;
327 struct sof_ipc_comp_src *src = COMP_GET_IPC(dev, sof_ipc_comp_src);
328 struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
329 struct comp_data *cd = comp_get_drvdata(dev);
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500330 struct comp_buffer *sink;
331 struct comp_buffer *source;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300332 size_t delay_lines_size;
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500333 uint32_t source_rate;
334 uint32_t sink_rate;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300335 int32_t *buffer_start;
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500336 int n = 0;
337 int i;
338 int err;
339 int frames_is_for_source;
340 int nch;
341 int q;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300342
Liam Girdwood3488cce2017-08-10 11:59:08 +0100343 trace_src("par");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300344
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300345 /* SRC supports S24_4LE and S32_LE formats */
346 switch (config->frame_fmt) {
347 case SOF_IPC_FRAME_S24_4LE:
348 cd->sign_extend_s24 = 1;
349 break;
350 case SOF_IPC_FRAME_S32_LE:
351 cd->sign_extend_s24 = 0;
352 break;
353 default:
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100354 trace_src_error("sr0");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300355 return -EINVAL;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100356 }
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300357
Liam Girdwood3488cce2017-08-10 11:59:08 +0100358 /* Calculate source and sink rates, one rate will come from IPC new
359 * and the other from params. */
360 if (src->source_rate == 0) {
361 /* params rate is source rate */
362 source_rate = params->rate;
363 sink_rate = src->sink_rate;
364 /* re-write our params with output rate for next component */
365 params->rate = sink_rate;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300366 frames_is_for_source = 0;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100367 } else {
368 /* params rate is sink rate */
369 source_rate = src->source_rate;
370 sink_rate = params->rate;
371 /* re-write our params with output rate for next component */
372 params->rate = source_rate;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300373 frames_is_for_source = 1;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100374 }
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300375
376 /* Allocate needed memory for delay lines */
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300377 err = src_buffer_lengths(&cd->param, source_rate, sink_rate,
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300378 params->channels, dev->frames, frames_is_for_source);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100379 if (err < 0) {
380 trace_src_error("sr1");
381 trace_value(source_rate);
382 trace_value(sink_rate);
383 trace_value(params->channels);
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300384 trace_value(dev->frames);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100385 return err;
386 }
387
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300388 delay_lines_size = sizeof(int32_t) * cd->param.total;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100389 if (delay_lines_size == 0) {
390 trace_src_error("sr2");
391 return -EINVAL;
392 }
393
394 /* free any existing dalay lines. TODO reuse if same size */
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300395 if (cd->delay_lines != NULL)
396 rfree(cd->delay_lines);
397
Liam Girdwood22ce8062017-09-03 22:04:26 +0100398 cd->delay_lines = rballoc(RZONE_RUNTIME, RFLAGS_NONE, delay_lines_size);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100399 if (cd->delay_lines == NULL) {
400 trace_src_error("sr3");
401 trace_value(delay_lines_size);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100402 return -EINVAL;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100403 }
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300404
405 /* Clear all delay lines here */
406 memset(cd->delay_lines, 0, delay_lines_size);
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300407 buffer_start = cd->delay_lines + cd->param.sbuf_length;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300408
409 /* Initize SRC for actual sample rate */
Seppo Ingalsuo849a5282017-09-22 16:08:44 +0300410 nch = MIN(params->channels, PLATFORM_MAX_CHANNELS);
411 for (i = 0; i < nch; i++) {
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300412 n = src_polyphase_init(&cd->src[i], &cd->param, buffer_start);
413 buffer_start += cd->param.single_src;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300414 }
415
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300416 /* Reset stage buffer */
417 cd->sbuf_r_ptr = cd->delay_lines;
418 cd->sbuf_w_ptr = cd->delay_lines;
419 cd->sbuf_avail = 0;
420
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300421 switch (n) {
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300422 case 0:
423 cd->src_func = src_copy_s32_default; /* 1:1 fast copy */
424 break;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300425 case 1:
426 cd->src_func = src_1s_s32_default; /* Simpler 1 stage SRC */
427 break;
428 case 2:
429 cd->src_func = src_2s_s32_default; /* Default 2 stage SRC */
430 break;
431 default:
432 /* This is possibly due to missing coefficients for
433 * requested rates combination. Sink audio will be
434 * muted if copy() is run.
435 */
436 trace_src("SFa");
437 cd->src_func = fallback_s32;
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300438 return -EINVAL;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100439 break;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300440 }
441
Seppo Ingalsuo14d10a82017-09-22 16:08:47 +0300442 /* Calculate period size based on config. First make sure that
443 * frame_bytes is set.
444 */
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300445 dev->frame_bytes =
446 dev->params.sample_container_bytes * dev->params.channels;
Liam Girdwood44509242017-09-07 15:34:42 +0100447
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300448 /* The downstream buffer must be at least length of blk_out plus
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300449 * a dev->frames and an integer multiple of dev->frames. The
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300450 * buffer_set_size will return an error if the required length would
451 * be too long.
452 */
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300453 q = src_ceil_divide(cd->param.blk_out, (int) dev->frames) + 1;
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300454
455 /* Configure downstream buffer */
456 sink = list_first_item(&dev->bsink_list, struct comp_buffer,
457 source_list);
458 err = buffer_set_size(sink, q * dev->frames * dev->frame_bytes);
Liam Girdwood44509242017-09-07 15:34:42 +0100459 if (err < 0) {
460 trace_src_error("eSz");
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300461 trace_value(sink->alloc_size);
462 trace_value(q * dev->frames * dev->frame_bytes);
Liam Girdwood44509242017-09-07 15:34:42 +0100463 return err;
464 }
465
466 buffer_reset_pos(sink);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300467
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300468 /* Check that source buffer has sufficient size */
469 source = list_first_item(&dev->bsource_list, struct comp_buffer,
470 sink_list);
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300471 if (source->size < cd->param.blk_in * dev->frame_bytes) {
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300472 trace_src_error("eSy");
473 return -EINVAL;
474 }
475
476
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300477 return 0;
478}
479
Liam Girdwood854b2e52017-09-02 23:14:02 +0100480static int src_ctrl_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata)
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300481{
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300482 trace_src_error("ec1");
483 return -EINVAL;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100484}
485
486/* used to pass standard and bespoke commands (with data) to component */
487static int src_cmd(struct comp_dev *dev, int cmd, void *data)
488{
489 struct sof_ipc_ctrl_data *cdata = data;
Ranjani Sridharan62004082017-09-06 22:01:40 +0100490 int ret = 0;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100491
Liam Girdwoodbe41b682017-09-21 16:48:18 +0100492 trace_src("cmd");
493
494 ret = comp_set_state(dev, cmd);
495 if (ret < 0)
496 return ret;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100497
Pierre-Louis Bossartb513a452017-09-25 14:52:12 -0500498 if (cmd == COMP_CMD_SET_VALUE)
499 ret = src_ctrl_cmd(dev, cdata);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300500
Ranjani Sridharan62004082017-09-06 22:01:40 +0100501 return ret;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300502}
503
504/* copy and process stream data from source to sink buffers */
505static int src_copy(struct comp_dev *dev)
506{
507 struct comp_data *cd = comp_get_drvdata(dev);
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500508 struct comp_buffer *source;
509 struct comp_buffer *sink;
510 int need_source;
511 int need_sink;
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300512 size_t consumed = 0;
513 size_t produced = 0;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300514
515 trace_comp("SRC");
516
517 /* src component needs 1 source and 1 sink buffer */
518 source = list_first_item(&dev->bsource_list, struct comp_buffer,
519 sink_list);
520 sink = list_first_item(&dev->bsink_list, struct comp_buffer,
521 source_list);
522
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300523 /* Calculate needed amount of source buffer and sink buffer
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300524 * for one SRC run. The blk_in and blk are minimum condition to
525 * call copy. Copy can consume or produce a slightly larger block
526 * with the rates where block sizes are not constant. E.g. for
527 * 1 ms schduling the blocks can be under or above 1 ms when the
528 * SRC interal block size constraint prevents exact 1 ms blocks.
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300529 */
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300530 need_source = cd->param.blk_in * dev->frame_bytes;
531 need_sink = cd->param.blk_out * dev->frame_bytes;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300532
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300533 /* Run SRC function if buffers avail and free allow */
534 if (((int) source->avail >= need_source) && ((int) sink->free >= need_sink)) {
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300535 /* Run src */
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300536 cd->src_func(dev, source, sink, &consumed, &produced);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300537
Seppo Ingalsuo28fafc12017-10-05 18:57:37 +0300538 /* Calc new free and available if data was processed. These
539 * functions must not be called with 0 consumed/produced.
540 */
541 if (consumed > 0)
542 comp_update_buffer_consume(source, consumed);
543
544 if (produced > 0)
545 comp_update_buffer_produce(sink, produced);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300546 }
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300547 return 0;
548}
549
550static int src_prepare(struct comp_dev *dev)
551{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300552 dev->state = COMP_STATE_PREPARE;
553 return 0;
554}
555
556static int src_preload(struct comp_dev *dev)
557{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100558 return src_copy(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300559}
560
561static int src_reset(struct comp_dev *dev)
562{
563 int i;
564 struct comp_data *cd = comp_get_drvdata(dev);
565
566 trace_src("SRe");
567
568 cd->src_func = src_2s_s32_default;
569 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
570 src_polyphase_reset(&cd->src[i]);
571
Liam Girdwoodbe41b682017-09-21 16:48:18 +0100572 dev->state = COMP_STATE_READY;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300573 return 0;
574}
575
576struct comp_driver comp_src = {
577 .type = SOF_COMP_SRC,
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300578 .ops = {
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300579 .new = src_new,
580 .free = src_free,
581 .params = src_params,
582 .cmd = src_cmd,
583 .copy = src_copy,
584 .prepare = src_prepare,
585 .reset = src_reset,
586 .preload = src_preload,
587 },
588};
589
590void sys_comp_src_init(void)
591{
592 comp_register(&comp_src);
593}