blob: ac2fbb5e07eac46fa14f01eab0ffb786fba16fd7 [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];
59 int32_t *delay_lines;
60 int scratch_length;
Liam Girdwood3488cce2017-08-10 11:59:08 +010061 uint32_t sink_rate;
62 uint32_t source_rate;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +030063 void (*src_func)(struct comp_dev *dev,
64 struct comp_buffer *source,
65 struct comp_buffer *sink,
66 uint32_t source_frames,
67 uint32_t sink_frames);
68};
69
70/* Common mute function for 2s and 1s SRC. This preserves the same
71 * buffer consume and produce pattern as normal operation.
72 */
73static void src_muted_s32(struct comp_buffer *source, struct comp_buffer *sink,
74 int blk_in, int blk_out, int nch, int source_frames)
75{
76
77 int i;
78 int32_t *src = (int32_t *) source->r_ptr;
79 int32_t *dest = (int32_t *) sink->w_ptr;
80 int32_t *end = (int32_t *) sink->end_addr;
81 int n_read = 0;
82 int n_max;
83 int n;
84 int n_written = 0;
85
86 for (i = 0; i < source_frames - blk_in + 1; i += blk_in) {
87 n_max = end - dest;
88 n = nch*blk_out;
89 if (n < n_max) {
90 bzero(dest, n * sizeof(int32_t));
91 dest += n;
92 } else {
93 /* Also case n_max == n is done here */
94 bzero(dest, n_max * sizeof(int32_t));
95 dest = (int32_t *) sink->addr;
96 bzero(dest, (n - n_max) * sizeof(int32_t));
97 dest += n - n_max;
98 }
99 n_read += nch*blk_in;
100 n_written += nch*blk_out;
101 }
102 source->r_ptr = src + n_read;
103 sink->w_ptr = dest;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300104}
105
106/* Fallback function to just output muted samples and advance
107 * pointers. Note that a buffer that is not having integer number of
108 * frames in a period will drift since there is no similar blk in/out
109 * check as for SRC.
110 */
111static void fallback_s32(struct comp_dev *dev,
112 struct comp_buffer *source,
113 struct comp_buffer *sink,
114 uint32_t source_frames,
115 uint32_t sink_frames)
116{
117
118 struct comp_data *cd = comp_get_drvdata(dev);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100119 int nch = dev->params.channels;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300120 int blk_in = cd->src[0].blk_in;
121 int blk_out = cd->src[0].blk_out;
122
123 src_muted_s32(source, sink, blk_in, blk_out, nch, source_frames);
124
125}
126
127/* Normal 2 stage SRC */
128static void src_2s_s32_default(struct comp_dev *dev,
129 struct comp_buffer *source, struct comp_buffer *sink,
130 uint32_t source_frames, uint32_t sink_frames)
131{
132 int i, j;
133 struct polyphase_src *s;
134 struct comp_data *cd = comp_get_drvdata(dev);
135 int blk_in = cd->src[0].blk_in;
136 int blk_out = cd->src[0].blk_out;
137 int n_times1 = cd->src[0].stage1_times;
138 int n_times2 = cd->src[0].stage2_times;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100139 int nch = dev->params.channels;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300140 int32_t *dest = (int32_t *) sink->w_ptr;
141 int32_t *src = (int32_t *) source->r_ptr;
142 struct src_stage_prm s1, s2;
143 int n_read = 0;
144 int n_written = 0;
145
146 if (cd->src[0].mute) {
Liam Girdwood3488cce2017-08-10 11:59:08 +0100147 src_muted_s32(source, sink, blk_in, blk_out, nch, source_frames);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300148 return;
149 }
150
151 s1.times = n_times1;
152 s1.x_end_addr = source->end_addr;
153 s1.x_size = source->alloc_size;
154 s1.x_inc = nch;
155 s1.y_end_addr = &cd->delay_lines[cd->scratch_length];
156 s1.y_size = STAGE_BUF_SIZE * sizeof(int32_t);
157 s1.y_inc = 1;
158
159 s2.times = n_times2;
160 s2.x_end_addr = &cd->delay_lines[cd->scratch_length];
161 s2.x_size = STAGE_BUF_SIZE * sizeof(int32_t);
162 s2.x_inc = 1;
163 s2.y_end_addr = sink->end_addr;
164 s2.y_size = sink->alloc_size;
165 s2.y_inc = nch;
166
Seppo Ingalsuo6f27ab62017-06-12 11:31:15 +0300167 s1.x_rptr = src + nch - 1;
168 s2.y_wptr = dest + nch - 1;
169
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300170 for (j = 0; j < nch; j++) {
171 s = &cd->src[j]; /* Point to src[] for this channel */
172 s1.x_rptr = src++;
173 s2.y_wptr = dest++;
174 s1.state = &s->state1;
175 s1.stage = s->stage1;
176 s2.state = &s->state2;
177 s2.stage = s->stage2;
178
179 for (i = 0; i < source_frames - blk_in + 1; i += blk_in) {
180 /* Reset output to buffer start, read interleaved */
181 s1.y_wptr = cd->delay_lines;
182 src_polyphase_stage_cir(&s1);
183 s2.x_rptr = cd->delay_lines;
184 src_polyphase_stage_cir(&s2);
185
186 n_read += blk_in;
187 n_written += blk_out;
188 }
189 }
190 source->r_ptr = s1.x_rptr - nch + 1;
191 sink->w_ptr = s2.y_wptr - nch + 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300192}
193
194/* 1 stage SRC for simple conversions */
195static void src_1s_s32_default(struct comp_dev *dev,
196 struct comp_buffer *source, struct comp_buffer *sink,
197 uint32_t source_frames, uint32_t sink_frames)
198{
199 int i, j;
200 //int32_t *xp, *yp;
201 struct polyphase_src *s;
202
203 struct comp_data *cd = comp_get_drvdata(dev);
204 int blk_in = cd->src[0].blk_in;
205 int blk_out = cd->src[0].blk_out;
206 int n_times = cd->src[0].stage1_times;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100207 int nch = dev->params.channels;
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300208 int32_t *dest = (int32_t *) sink->w_ptr;
209 int32_t *src = (int32_t *) source->r_ptr;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300210 int n_read = 0;
211 int n_written = 0;
212 struct src_stage_prm s1;
213
214 if (cd->src[0].mute) {
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300215 src_muted_s32(source, sink, blk_in, blk_out, nch,
216 source_frames);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300217 return;
218 }
219
220 s1.times = n_times;
221 s1.x_end_addr = source->end_addr;
222 s1.x_size = source->alloc_size;
223 s1.x_inc = nch;
224 s1.y_end_addr = sink->end_addr;
225 s1.y_size = sink->alloc_size;
226 s1.y_inc = nch;
Seppo Ingalsuo6f27ab62017-06-12 11:31:15 +0300227 s1.x_rptr = src + nch - 1;
228 s1.y_wptr = dest + nch - 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300229
230 for (j = 0; j < nch; j++) {
231 s = &cd->src[j]; /* Point to src for this channel */
232 s1.x_rptr = src++;
233 s1.y_wptr = dest++;
234 s1.state = &s->state1;
235 s1.stage = s->stage1;
236
237 for (i = 0; i + blk_in - 1 < source_frames; i += blk_in) {
238 src_polyphase_stage_cir(&s1);
239
240 n_read += blk_in;
241 n_written += blk_out;
242 }
243
244 }
245 source->r_ptr = s1.x_rptr - nch + 1;
246 sink->w_ptr = s1.y_wptr - nch + 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300247}
248
249static struct comp_dev *src_new(struct sof_ipc_comp *comp)
250{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300251 struct comp_dev *dev;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100252 struct sof_ipc_comp_src *src;
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300253 struct sof_ipc_comp_src *ipc_src = (struct sof_ipc_comp_src *) comp;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300254 struct comp_data *cd;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100255 int i;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300256
Liam Girdwood3488cce2017-08-10 11:59:08 +0100257 trace_src("new");
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100258
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100259 /* validate init data - either SRC sink or source rate must be set */
260 if (ipc_src->source_rate == 0 && ipc_src->sink_rate == 0) {
261 trace_src_error("sn1");
262 return NULL;
263 }
264
Liam Girdwood3488cce2017-08-10 11:59:08 +0100265 dev = rzalloc(RZONE_RUNTIME, RFLAGS_NONE,
Liam Girdwood17641522017-06-09 17:27:02 +0100266 COMP_SIZE(struct sof_ipc_comp_src));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300267 if (dev == NULL)
268 return NULL;
269
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300270 src = (struct sof_ipc_comp_src *) &dev->comp;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100271 memcpy(src, ipc_src, sizeof(struct sof_ipc_comp_src));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300272
Liam Girdwood3488cce2017-08-10 11:59:08 +0100273 cd = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300274 if (cd == NULL) {
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300275 rfree(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300276 return NULL;
277 }
278
279 comp_set_drvdata(dev, cd);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300280
281 cd->delay_lines = NULL;
282 cd->src_func = src_2s_s32_default;
283 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
284 src_polyphase_reset(&cd->src[i]);
285
286 return dev;
287}
288
289static void src_free(struct comp_dev *dev)
290{
291 struct comp_data *cd = comp_get_drvdata(dev);
292
Liam Girdwood3488cce2017-08-10 11:59:08 +0100293 trace_src("fre");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300294
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300295 /* Free dynamically reserved buffers for SRC algorithm */
296 if (cd->delay_lines != NULL)
297 rfree(cd->delay_lines);
298
299 rfree(cd);
300 rfree(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300301}
302
303/* set component audio stream parameters */
Liam Girdwood2cfaebe2017-08-21 17:13:52 +0100304static int src_params(struct comp_dev *dev)
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300305{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100306 struct sof_ipc_stream_params *params = &dev->params;
307 struct sof_ipc_comp_src *src = COMP_GET_IPC(dev, sof_ipc_comp_src);
308 struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
309 struct comp_data *cd = comp_get_drvdata(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300310 struct src_alloc need;
311 size_t delay_lines_size;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100312 uint32_t source_rate, sink_rate;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300313 int32_t *buffer_start;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300314 int n = 0, i, err, frames_is_for_source;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300315
Liam Girdwood3488cce2017-08-10 11:59:08 +0100316 trace_src("par");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300317
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300318 /* SRC supports only S32_LE PCM format */
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100319 if (config->frame_fmt != SOF_IPC_FRAME_S32_LE) {
320 trace_src_error("sr0");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300321 return -EINVAL;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100322 }
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300323
Liam Girdwood3488cce2017-08-10 11:59:08 +0100324 /* Calculate source and sink rates, one rate will come from IPC new
325 * and the other from params. */
326 if (src->source_rate == 0) {
327 /* params rate is source rate */
328 source_rate = params->rate;
329 sink_rate = src->sink_rate;
330 /* re-write our params with output rate for next component */
331 params->rate = sink_rate;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300332 frames_is_for_source = 0;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100333 } else {
334 /* params rate is sink rate */
335 source_rate = src->source_rate;
336 sink_rate = params->rate;
337 /* re-write our params with output rate for next component */
338 params->rate = source_rate;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300339 frames_is_for_source = 1;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100340 }
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300341
342 /* Allocate needed memory for delay lines */
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300343 err = src_buffer_lengths(&need, source_rate, sink_rate,
344 params->channels, dev->frames, frames_is_for_source);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100345 if (err < 0) {
346 trace_src_error("sr1");
347 trace_value(source_rate);
348 trace_value(sink_rate);
349 trace_value(params->channels);
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300350 trace_value(dev->frames);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100351 return err;
352 }
353
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300354 delay_lines_size = sizeof(int32_t) * need.total;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100355 if (delay_lines_size == 0) {
356 trace_src_error("sr2");
357 return -EINVAL;
358 }
359
360 /* free any existing dalay lines. TODO reuse if same size */
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300361 if (cd->delay_lines != NULL)
362 rfree(cd->delay_lines);
363
Liam Girdwood22ce8062017-09-03 22:04:26 +0100364 cd->delay_lines = rballoc(RZONE_RUNTIME, RFLAGS_NONE, delay_lines_size);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100365 if (cd->delay_lines == NULL) {
366 trace_src_error("sr3");
367 trace_value(delay_lines_size);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100368 return -EINVAL;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100369 }
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300370
371 /* Clear all delay lines here */
372 memset(cd->delay_lines, 0, delay_lines_size);
373 cd->scratch_length = need.scratch;
374 buffer_start = cd->delay_lines + need.scratch;
375
376 /* Initize SRC for actual sample rate */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100377 for (i = 0; i < params->channels; i++) {
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300378 n = src_polyphase_init(&cd->src[i], source_rate, sink_rate,
379 &need, buffer_start);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300380 buffer_start += need.single_src;
381 }
382
383 switch (n) {
384 case 1:
385 cd->src_func = src_1s_s32_default; /* Simpler 1 stage SRC */
386 break;
387 case 2:
388 cd->src_func = src_2s_s32_default; /* Default 2 stage SRC */
389 break;
390 default:
391 /* This is possibly due to missing coefficients for
392 * requested rates combination. Sink audio will be
393 * muted if copy() is run.
394 */
395 trace_src("SFa");
396 cd->src_func = fallback_s32;
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300397 return -EINVAL;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100398 break;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300399 }
400
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300401 /* Need to compute this */
402 dev->frame_bytes =
403 dev->params.sample_container_bytes * dev->params.channels;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300404
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300405 return 0;
406}
407
Liam Girdwood854b2e52017-09-02 23:14:02 +0100408static int src_ctrl_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata)
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300409{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300410 struct comp_data *cd = comp_get_drvdata(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300411 int i;
412
Liam Girdwood854b2e52017-09-02 23:14:02 +0100413 switch (cdata->cmd) {
414 case SOF_CTRL_CMD_MUTE:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300415 trace_src("SMu");
416 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
417 src_polyphase_mute(&cd->src[i]);
418
419 break;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100420 case SOF_CTRL_CMD_UNMUTE:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300421 trace_src("SUm");
422 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
423 src_polyphase_unmute(&cd->src[i]);
424
425 break;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100426 default:
427 trace_src_error("ec1");
428 return -EINVAL;
429 }
430
431 return 0;
432}
433
434/* used to pass standard and bespoke commands (with data) to component */
435static int src_cmd(struct comp_dev *dev, int cmd, void *data)
436{
437 struct sof_ipc_ctrl_data *cdata = data;
Ranjani Sridharan62004082017-09-06 22:01:40 +0100438 int ret = 0;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100439
440 trace_src("SCm");
441
442 switch (cmd) {
443 case COMP_CMD_SET_VALUE:
444 return src_ctrl_cmd(dev, cdata);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300445 case COMP_CMD_START:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300446 case COMP_CMD_STOP:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300447 case COMP_CMD_PAUSE:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300448 case COMP_CMD_RELEASE:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300449 default:
Ranjani Sridharan62004082017-09-06 22:01:40 +0100450 ret = comp_set_state(dev, cmd);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300451 break;
452 }
453
Ranjani Sridharan62004082017-09-06 22:01:40 +0100454 return ret;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300455}
456
457/* copy and process stream data from source to sink buffers */
458static int src_copy(struct comp_dev *dev)
459{
460 struct comp_data *cd = comp_get_drvdata(dev);
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300461 struct comp_buffer *source, *sink;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300462 int need_source, need_sink, blk_in, blk_out;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300463
464 trace_comp("SRC");
465
466 /* src component needs 1 source and 1 sink buffer */
467 source = list_first_item(&dev->bsource_list, struct comp_buffer,
468 sink_list);
469 sink = list_first_item(&dev->bsink_list, struct comp_buffer,
470 source_list);
471
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300472 /* Calculate needed amount of source buffer and sink buffer
473 * for one SRC run.
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300474 */
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300475 blk_in = src_polyphase_get_blk_in(&cd->src[0]);
476 blk_out = src_polyphase_get_blk_out(&cd->src[0]);
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300477 need_source = blk_in * dev->frame_bytes;
478 need_sink = blk_out * dev->frame_bytes;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300479
480 /* Run as many times as buffers allow */
481 while ((source->avail >= need_source) && (sink->free >= need_sink)) {
482 /* Run src */
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300483 cd->src_func(dev, source, sink, blk_in, blk_out);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300484
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300485 /* calc new free and available */
486 comp_update_buffer_consume(source, 0);
487 comp_update_buffer_produce(sink, 0);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300488 }
489
490 return 0;
491}
492
493static int src_prepare(struct comp_dev *dev)
494{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300495 dev->state = COMP_STATE_PREPARE;
496 return 0;
497}
498
499static int src_preload(struct comp_dev *dev)
500{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100501 return src_copy(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300502}
503
504static int src_reset(struct comp_dev *dev)
505{
506 int i;
507 struct comp_data *cd = comp_get_drvdata(dev);
508
509 trace_src("SRe");
510
511 cd->src_func = src_2s_s32_default;
512 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
513 src_polyphase_reset(&cd->src[i]);
514
515 dev->state = COMP_STATE_INIT;
516 return 0;
517}
518
519struct comp_driver comp_src = {
520 .type = SOF_COMP_SRC,
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300521 .ops = {
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300522 .new = src_new,
523 .free = src_free,
524 .params = src_params,
525 .cmd = src_cmd,
526 .copy = src_copy,
527 .prepare = src_prepare,
528 .reset = src_reset,
529 .preload = src_preload,
530 },
531};
532
533void sys_comp_src_init(void)
534{
535 comp_register(&comp_src);
536}