blob: 2ecf0252df08bfd5ff92b84e8e6100fd075d43df [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 Ingalsuo54162292017-09-12 13:45:50 +030063 uint32_t period_bytes; /* sink period */
Seppo Ingalsuo6a274832017-06-07 14:17:55 +030064 void (*src_func)(struct comp_dev *dev,
65 struct comp_buffer *source,
66 struct comp_buffer *sink,
67 uint32_t source_frames,
68 uint32_t sink_frames);
69};
70
71/* Common mute function for 2s and 1s SRC. This preserves the same
72 * buffer consume and produce pattern as normal operation.
73 */
74static void src_muted_s32(struct comp_buffer *source, struct comp_buffer *sink,
75 int blk_in, int blk_out, int nch, int source_frames)
76{
77
78 int i;
79 int32_t *src = (int32_t *) source->r_ptr;
80 int32_t *dest = (int32_t *) sink->w_ptr;
81 int32_t *end = (int32_t *) sink->end_addr;
82 int n_read = 0;
83 int n_max;
84 int n;
85 int n_written = 0;
86
87 for (i = 0; i < source_frames - blk_in + 1; i += blk_in) {
88 n_max = end - dest;
89 n = nch*blk_out;
90 if (n < n_max) {
91 bzero(dest, n * sizeof(int32_t));
92 dest += n;
93 } else {
94 /* Also case n_max == n is done here */
95 bzero(dest, n_max * sizeof(int32_t));
96 dest = (int32_t *) sink->addr;
97 bzero(dest, (n - n_max) * sizeof(int32_t));
98 dest += n - n_max;
99 }
100 n_read += nch*blk_in;
101 n_written += nch*blk_out;
102 }
103 source->r_ptr = src + n_read;
104 sink->w_ptr = dest;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300105}
106
107/* Fallback function to just output muted samples and advance
108 * pointers. Note that a buffer that is not having integer number of
109 * frames in a period will drift since there is no similar blk in/out
110 * check as for SRC.
111 */
112static void fallback_s32(struct comp_dev *dev,
113 struct comp_buffer *source,
114 struct comp_buffer *sink,
115 uint32_t source_frames,
116 uint32_t sink_frames)
117{
118
119 struct comp_data *cd = comp_get_drvdata(dev);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100120 int nch = dev->params.channels;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300121 int blk_in = cd->src[0].blk_in;
122 int blk_out = cd->src[0].blk_out;
123
124 src_muted_s32(source, sink, blk_in, blk_out, nch, source_frames);
125
126}
127
128/* Normal 2 stage SRC */
129static void src_2s_s32_default(struct comp_dev *dev,
130 struct comp_buffer *source, struct comp_buffer *sink,
131 uint32_t source_frames, uint32_t sink_frames)
132{
133 int i, j;
134 struct polyphase_src *s;
135 struct comp_data *cd = comp_get_drvdata(dev);
136 int blk_in = cd->src[0].blk_in;
137 int blk_out = cd->src[0].blk_out;
138 int n_times1 = cd->src[0].stage1_times;
139 int n_times2 = cd->src[0].stage2_times;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100140 int nch = dev->params.channels;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300141 int32_t *dest = (int32_t *) sink->w_ptr;
142 int32_t *src = (int32_t *) source->r_ptr;
143 struct src_stage_prm s1, s2;
144 int n_read = 0;
145 int n_written = 0;
146
147 if (cd->src[0].mute) {
Liam Girdwood3488cce2017-08-10 11:59:08 +0100148 src_muted_s32(source, sink, blk_in, blk_out, nch, source_frames);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300149 return;
150 }
151
152 s1.times = n_times1;
153 s1.x_end_addr = source->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100154 s1.x_size = source->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300155 s1.x_inc = nch;
156 s1.y_end_addr = &cd->delay_lines[cd->scratch_length];
157 s1.y_size = STAGE_BUF_SIZE * sizeof(int32_t);
158 s1.y_inc = 1;
159
160 s2.times = n_times2;
161 s2.x_end_addr = &cd->delay_lines[cd->scratch_length];
162 s2.x_size = STAGE_BUF_SIZE * sizeof(int32_t);
163 s2.x_inc = 1;
164 s2.y_end_addr = sink->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100165 s2.y_size = sink->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300166 s2.y_inc = nch;
167
Seppo Ingalsuo6f27ab62017-06-12 11:31:15 +0300168 s1.x_rptr = src + nch - 1;
169 s2.y_wptr = dest + nch - 1;
170
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300171 for (j = 0; j < nch; j++) {
172 s = &cd->src[j]; /* Point to src[] for this channel */
173 s1.x_rptr = src++;
174 s2.y_wptr = dest++;
175 s1.state = &s->state1;
176 s1.stage = s->stage1;
177 s2.state = &s->state2;
178 s2.stage = s->stage2;
179
180 for (i = 0; i < source_frames - blk_in + 1; i += blk_in) {
181 /* Reset output to buffer start, read interleaved */
182 s1.y_wptr = cd->delay_lines;
183 src_polyphase_stage_cir(&s1);
184 s2.x_rptr = cd->delay_lines;
185 src_polyphase_stage_cir(&s2);
186
187 n_read += blk_in;
188 n_written += blk_out;
189 }
190 }
191 source->r_ptr = s1.x_rptr - nch + 1;
192 sink->w_ptr = s2.y_wptr - nch + 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300193}
194
195/* 1 stage SRC for simple conversions */
196static void src_1s_s32_default(struct comp_dev *dev,
197 struct comp_buffer *source, struct comp_buffer *sink,
198 uint32_t source_frames, uint32_t sink_frames)
199{
200 int i, j;
201 //int32_t *xp, *yp;
202 struct polyphase_src *s;
203
204 struct comp_data *cd = comp_get_drvdata(dev);
205 int blk_in = cd->src[0].blk_in;
206 int blk_out = cd->src[0].blk_out;
207 int n_times = cd->src[0].stage1_times;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100208 int nch = dev->params.channels;
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300209 int32_t *dest = (int32_t *) sink->w_ptr;
210 int32_t *src = (int32_t *) source->r_ptr;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300211 int n_read = 0;
212 int n_written = 0;
213 struct src_stage_prm s1;
214
215 if (cd->src[0].mute) {
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300216 src_muted_s32(source, sink, blk_in, blk_out, nch,
217 source_frames);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300218 return;
219 }
220
221 s1.times = n_times;
222 s1.x_end_addr = source->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100223 s1.x_size = source->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300224 s1.x_inc = nch;
225 s1.y_end_addr = sink->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100226 s1.y_size = sink->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300227 s1.y_inc = nch;
Seppo Ingalsuo6f27ab62017-06-12 11:31:15 +0300228 s1.x_rptr = src + nch - 1;
229 s1.y_wptr = dest + nch - 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300230
231 for (j = 0; j < nch; j++) {
232 s = &cd->src[j]; /* Point to src for this channel */
233 s1.x_rptr = src++;
234 s1.y_wptr = dest++;
235 s1.state = &s->state1;
236 s1.stage = s->stage1;
237
238 for (i = 0; i + blk_in - 1 < source_frames; i += blk_in) {
239 src_polyphase_stage_cir(&s1);
240
241 n_read += blk_in;
242 n_written += blk_out;
243 }
244
245 }
246 source->r_ptr = s1.x_rptr - nch + 1;
247 sink->w_ptr = s1.y_wptr - nch + 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300248}
249
250static struct comp_dev *src_new(struct sof_ipc_comp *comp)
251{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300252 struct comp_dev *dev;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100253 struct sof_ipc_comp_src *src;
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300254 struct sof_ipc_comp_src *ipc_src = (struct sof_ipc_comp_src *) comp;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300255 struct comp_data *cd;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100256 int i;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300257
Liam Girdwood3488cce2017-08-10 11:59:08 +0100258 trace_src("new");
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100259
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100260 /* validate init data - either SRC sink or source rate must be set */
261 if (ipc_src->source_rate == 0 && ipc_src->sink_rate == 0) {
262 trace_src_error("sn1");
263 return NULL;
264 }
265
Liam Girdwood3488cce2017-08-10 11:59:08 +0100266 dev = rzalloc(RZONE_RUNTIME, RFLAGS_NONE,
Liam Girdwood17641522017-06-09 17:27:02 +0100267 COMP_SIZE(struct sof_ipc_comp_src));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300268 if (dev == NULL)
269 return NULL;
270
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300271 src = (struct sof_ipc_comp_src *) &dev->comp;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100272 memcpy(src, ipc_src, sizeof(struct sof_ipc_comp_src));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300273
Liam Girdwood3488cce2017-08-10 11:59:08 +0100274 cd = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300275 if (cd == NULL) {
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300276 rfree(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300277 return NULL;
278 }
279
280 comp_set_drvdata(dev, cd);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300281
282 cd->delay_lines = NULL;
283 cd->src_func = src_2s_s32_default;
284 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
285 src_polyphase_reset(&cd->src[i]);
286
287 return dev;
288}
289
290static void src_free(struct comp_dev *dev)
291{
292 struct comp_data *cd = comp_get_drvdata(dev);
293
Liam Girdwood3488cce2017-08-10 11:59:08 +0100294 trace_src("fre");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300295
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300296 /* Free dynamically reserved buffers for SRC algorithm */
297 if (cd->delay_lines != NULL)
298 rfree(cd->delay_lines);
299
300 rfree(cd);
301 rfree(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300302}
303
304/* set component audio stream parameters */
Liam Girdwood2cfaebe2017-08-21 17:13:52 +0100305static int src_params(struct comp_dev *dev)
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300306{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100307 struct sof_ipc_stream_params *params = &dev->params;
308 struct sof_ipc_comp_src *src = COMP_GET_IPC(dev, sof_ipc_comp_src);
309 struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
310 struct comp_data *cd = comp_get_drvdata(dev);
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300311 struct comp_buffer *sink, *source;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300312 struct src_alloc need;
313 size_t delay_lines_size;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100314 uint32_t source_rate, sink_rate;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300315 int32_t *buffer_start;
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300316 int n = 0, i, err, frames_is_for_source, q;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300317
Liam Girdwood3488cce2017-08-10 11:59:08 +0100318 trace_src("par");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300319
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300320 /* SRC supports only S32_LE PCM format */
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100321 if (config->frame_fmt != SOF_IPC_FRAME_S32_LE) {
322 trace_src_error("sr0");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300323 return -EINVAL;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100324 }
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300325
Liam Girdwood3488cce2017-08-10 11:59:08 +0100326 /* Calculate source and sink rates, one rate will come from IPC new
327 * and the other from params. */
328 if (src->source_rate == 0) {
329 /* params rate is source rate */
330 source_rate = params->rate;
331 sink_rate = src->sink_rate;
332 /* re-write our params with output rate for next component */
333 params->rate = sink_rate;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300334 frames_is_for_source = 0;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100335 } else {
336 /* params rate is sink rate */
337 source_rate = src->source_rate;
338 sink_rate = params->rate;
339 /* re-write our params with output rate for next component */
340 params->rate = source_rate;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300341 frames_is_for_source = 1;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100342 }
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300343
344 /* Allocate needed memory for delay lines */
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300345 err = src_buffer_lengths(&need, source_rate, sink_rate,
346 params->channels, dev->frames, frames_is_for_source);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100347 if (err < 0) {
348 trace_src_error("sr1");
349 trace_value(source_rate);
350 trace_value(sink_rate);
351 trace_value(params->channels);
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300352 trace_value(dev->frames);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100353 return err;
354 }
355
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300356 delay_lines_size = sizeof(int32_t) * need.total;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100357 if (delay_lines_size == 0) {
358 trace_src_error("sr2");
359 return -EINVAL;
360 }
361
362 /* free any existing dalay lines. TODO reuse if same size */
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300363 if (cd->delay_lines != NULL)
364 rfree(cd->delay_lines);
365
Liam Girdwood22ce8062017-09-03 22:04:26 +0100366 cd->delay_lines = rballoc(RZONE_RUNTIME, RFLAGS_NONE, delay_lines_size);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100367 if (cd->delay_lines == NULL) {
368 trace_src_error("sr3");
369 trace_value(delay_lines_size);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100370 return -EINVAL;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100371 }
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300372
373 /* Clear all delay lines here */
374 memset(cd->delay_lines, 0, delay_lines_size);
375 cd->scratch_length = need.scratch;
376 buffer_start = cd->delay_lines + need.scratch;
377
378 /* Initize SRC for actual sample rate */
Liam Girdwood3488cce2017-08-10 11:59:08 +0100379 for (i = 0; i < params->channels; i++) {
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300380 n = src_polyphase_init(&cd->src[i], source_rate, sink_rate,
381 &need, buffer_start);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300382 buffer_start += need.single_src;
383 }
384
385 switch (n) {
386 case 1:
387 cd->src_func = src_1s_s32_default; /* Simpler 1 stage SRC */
388 break;
389 case 2:
390 cd->src_func = src_2s_s32_default; /* Default 2 stage SRC */
391 break;
392 default:
393 /* This is possibly due to missing coefficients for
394 * requested rates combination. Sink audio will be
395 * muted if copy() is run.
396 */
397 trace_src("SFa");
398 cd->src_func = fallback_s32;
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300399 return -EINVAL;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100400 break;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300401 }
402
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300403 /* Need to compute this */
404 dev->frame_bytes =
405 dev->params.sample_container_bytes * dev->params.channels;
Liam Girdwood44509242017-09-07 15:34:42 +0100406 cd->period_bytes = dev->frames * dev->frame_bytes;
407
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300408 /* The downstream buffer must be at least length of blk_out plus
409 * dev->frames and an integer multiple of dev->frames. The
410 * buffer_set_size will return an error if the required length would
411 * be too long.
412 */
413 q = need.blk_out / dev->frames;
414 if (q * dev->frames < need.blk_out)
415 ++q;
416
417 if (q * dev->frames < need.blk_out + dev->frames)
418 ++q;
419
420 /* Configure downstream buffer */
421 sink = list_first_item(&dev->bsink_list, struct comp_buffer,
422 source_list);
423 err = buffer_set_size(sink, q * dev->frames * dev->frame_bytes);
Liam Girdwood44509242017-09-07 15:34:42 +0100424 if (err < 0) {
425 trace_src_error("eSz");
426 return err;
427 }
428
429 buffer_reset_pos(sink);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300430
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300431 /* Check that source buffer has sufficient size */
432 source = list_first_item(&dev->bsource_list, struct comp_buffer,
433 sink_list);
434 if (source->size < need.blk_in * dev->frame_bytes) {
435 trace_src_error("eSy");
436 return -EINVAL;
437 }
438
439
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300440 return 0;
441}
442
Liam Girdwood854b2e52017-09-02 23:14:02 +0100443static int src_ctrl_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata)
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300444{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300445 struct comp_data *cd = comp_get_drvdata(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300446 int i;
447
Liam Girdwood854b2e52017-09-02 23:14:02 +0100448 switch (cdata->cmd) {
449 case SOF_CTRL_CMD_MUTE:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300450 trace_src("SMu");
451 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
452 src_polyphase_mute(&cd->src[i]);
453
454 break;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100455 case SOF_CTRL_CMD_UNMUTE:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300456 trace_src("SUm");
457 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
458 src_polyphase_unmute(&cd->src[i]);
459
460 break;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100461 default:
462 trace_src_error("ec1");
463 return -EINVAL;
464 }
465
466 return 0;
467}
468
469/* used to pass standard and bespoke commands (with data) to component */
470static int src_cmd(struct comp_dev *dev, int cmd, void *data)
471{
472 struct sof_ipc_ctrl_data *cdata = data;
Ranjani Sridharan62004082017-09-06 22:01:40 +0100473 int ret = 0;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100474
475 trace_src("SCm");
476
477 switch (cmd) {
478 case COMP_CMD_SET_VALUE:
479 return src_ctrl_cmd(dev, cdata);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300480 case COMP_CMD_START:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300481 case COMP_CMD_STOP:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300482 case COMP_CMD_PAUSE:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300483 case COMP_CMD_RELEASE:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300484 default:
Ranjani Sridharan62004082017-09-06 22:01:40 +0100485 ret = comp_set_state(dev, cmd);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300486 break;
487 }
488
Ranjani Sridharan62004082017-09-06 22:01:40 +0100489 return ret;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300490}
491
492/* copy and process stream data from source to sink buffers */
493static int src_copy(struct comp_dev *dev)
494{
495 struct comp_data *cd = comp_get_drvdata(dev);
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300496 struct comp_buffer *source, *sink;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300497 int need_source, need_sink, blk_in, blk_out;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300498
499 trace_comp("SRC");
500
501 /* src component needs 1 source and 1 sink buffer */
502 source = list_first_item(&dev->bsource_list, struct comp_buffer,
503 sink_list);
504 sink = list_first_item(&dev->bsink_list, struct comp_buffer,
505 source_list);
506
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300507 /* Calculate needed amount of source buffer and sink buffer
508 * for one SRC run.
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300509 */
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300510 blk_in = src_polyphase_get_blk_in(&cd->src[0]);
511 blk_out = src_polyphase_get_blk_out(&cd->src[0]);
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300512 need_source = blk_in * dev->frame_bytes;
513 need_sink = blk_out * dev->frame_bytes;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300514
515 /* Run as many times as buffers allow */
516 while ((source->avail >= need_source) && (sink->free >= need_sink)) {
517 /* Run src */
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300518 cd->src_func(dev, source, sink, blk_in, blk_out);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300519
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300520 /* calc new free and available */
521 comp_update_buffer_consume(source, 0);
522 comp_update_buffer_produce(sink, 0);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300523 }
524
525 return 0;
526}
527
528static int src_prepare(struct comp_dev *dev)
529{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300530 dev->state = COMP_STATE_PREPARE;
531 return 0;
532}
533
534static int src_preload(struct comp_dev *dev)
535{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100536 return src_copy(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300537}
538
539static int src_reset(struct comp_dev *dev)
540{
541 int i;
542 struct comp_data *cd = comp_get_drvdata(dev);
543
544 trace_src("SRe");
545
546 cd->src_func = src_2s_s32_default;
547 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
548 src_polyphase_reset(&cd->src[i]);
549
550 dev->state = COMP_STATE_INIT;
551 return 0;
552}
553
554struct comp_driver comp_src = {
555 .type = SOF_COMP_SRC,
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300556 .ops = {
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300557 .new = src_new,
558 .free = src_free,
559 .params = src_params,
560 .cmd = src_cmd,
561 .copy = src_copy,
562 .prepare = src_prepare,
563 .reset = src_reset,
564 .preload = src_preload,
565 },
566};
567
568void sys_comp_src_init(void)
569{
570 comp_register(&comp_src);
571}