blob: 2b94854f8ea588d6edbb12f471892ca113d71ec5 [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;
Liam Girdwood3488cce2017-08-10 11:59:08 +010060 uint32_t sink_rate;
61 uint32_t source_rate;
Seppo Ingalsuo54162292017-09-12 13:45:50 +030062 uint32_t period_bytes; /* sink period */
Seppo Ingalsuo887628a2017-09-14 16:00:05 +030063 int scratch_length; /* Buffer for stage1-stage2 */
64 int sign_extend_s24; /* Set if need to copy sign bit to b24..b31 */
Seppo Ingalsuo6a274832017-06-07 14:17:55 +030065 void (*src_func)(struct comp_dev *dev,
66 struct comp_buffer *source,
67 struct comp_buffer *sink,
68 uint32_t source_frames,
69 uint32_t sink_frames);
70};
71
72/* Common mute function for 2s and 1s SRC. This preserves the same
73 * buffer consume and produce pattern as normal operation.
74 */
75static void src_muted_s32(struct comp_buffer *source, struct comp_buffer *sink,
76 int blk_in, int blk_out, int nch, int source_frames)
77{
78
79 int i;
80 int32_t *src = (int32_t *) source->r_ptr;
81 int32_t *dest = (int32_t *) sink->w_ptr;
82 int32_t *end = (int32_t *) sink->end_addr;
83 int n_read = 0;
84 int n_max;
85 int n;
86 int n_written = 0;
87
88 for (i = 0; i < source_frames - blk_in + 1; i += blk_in) {
89 n_max = end - dest;
90 n = nch*blk_out;
91 if (n < n_max) {
92 bzero(dest, n * sizeof(int32_t));
93 dest += n;
94 } else {
95 /* Also case n_max == n is done here */
96 bzero(dest, n_max * sizeof(int32_t));
97 dest = (int32_t *) sink->addr;
98 bzero(dest, (n - n_max) * sizeof(int32_t));
99 dest += n - n_max;
100 }
101 n_read += nch*blk_in;
102 n_written += nch*blk_out;
103 }
104 source->r_ptr = src + n_read;
105 sink->w_ptr = dest;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300106}
107
108/* Fallback function to just output muted samples and advance
109 * pointers. Note that a buffer that is not having integer number of
110 * frames in a period will drift since there is no similar blk in/out
111 * check as for SRC.
112 */
113static void fallback_s32(struct comp_dev *dev,
114 struct comp_buffer *source,
115 struct comp_buffer *sink,
116 uint32_t source_frames,
117 uint32_t sink_frames)
118{
119
120 struct comp_data *cd = comp_get_drvdata(dev);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100121 int nch = dev->params.channels;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300122 int blk_in = cd->src[0].blk_in;
123 int blk_out = cd->src[0].blk_out;
124
125 src_muted_s32(source, sink, blk_in, blk_out, nch, source_frames);
126
127}
128
129/* Normal 2 stage SRC */
130static void src_2s_s32_default(struct comp_dev *dev,
131 struct comp_buffer *source, struct comp_buffer *sink,
132 uint32_t source_frames, uint32_t sink_frames)
133{
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500134 int i;
135 int j;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300136 struct polyphase_src *s;
137 struct comp_data *cd = comp_get_drvdata(dev);
138 int blk_in = cd->src[0].blk_in;
139 int blk_out = cd->src[0].blk_out;
140 int n_times1 = cd->src[0].stage1_times;
141 int n_times2 = cd->src[0].stage2_times;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100142 int nch = dev->params.channels;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300143 int32_t *dest = (int32_t *) sink->w_ptr;
144 int32_t *src = (int32_t *) source->r_ptr;
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500145 struct src_stage_prm s1;
146 struct src_stage_prm s2;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300147 int n_read = 0;
148 int n_written = 0;
149
150 if (cd->src[0].mute) {
Liam Girdwood3488cce2017-08-10 11:59:08 +0100151 src_muted_s32(source, sink, blk_in, blk_out, nch, source_frames);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300152 return;
153 }
154
155 s1.times = n_times1;
156 s1.x_end_addr = source->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100157 s1.x_size = source->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300158 s1.x_inc = nch;
159 s1.y_end_addr = &cd->delay_lines[cd->scratch_length];
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300160 s1.y_size = cd->scratch_length * sizeof(int32_t);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300161 s1.y_inc = 1;
162
163 s2.times = n_times2;
164 s2.x_end_addr = &cd->delay_lines[cd->scratch_length];
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300165 s2.x_size = cd->scratch_length * sizeof(int32_t);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300166 s2.x_inc = 1;
167 s2.y_end_addr = sink->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100168 s2.y_size = sink->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300169 s2.y_inc = nch;
170
Seppo Ingalsuo6f27ab62017-06-12 11:31:15 +0300171 s1.x_rptr = src + nch - 1;
172 s2.y_wptr = dest + nch - 1;
173
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300174 for (j = 0; j < nch; j++) {
175 s = &cd->src[j]; /* Point to src[] for this channel */
176 s1.x_rptr = src++;
177 s2.y_wptr = dest++;
178 s1.state = &s->state1;
179 s1.stage = s->stage1;
180 s2.state = &s->state2;
181 s2.stage = s->stage2;
182
183 for (i = 0; i < source_frames - blk_in + 1; i += blk_in) {
184 /* Reset output to buffer start, read interleaved */
185 s1.y_wptr = cd->delay_lines;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300186 s2.x_rptr = cd->delay_lines;
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300187 if (cd->sign_extend_s24) {
188 src_polyphase_stage_cir_s24(&s1);
189 src_polyphase_stage_cir_s24(&s2);
190 } else {
191 src_polyphase_stage_cir(&s1);
192 src_polyphase_stage_cir(&s2);
193 }
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300194
195 n_read += blk_in;
196 n_written += blk_out;
197 }
198 }
199 source->r_ptr = s1.x_rptr - nch + 1;
200 sink->w_ptr = s2.y_wptr - nch + 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300201}
202
203/* 1 stage SRC for simple conversions */
204static void src_1s_s32_default(struct comp_dev *dev,
205 struct comp_buffer *source, struct comp_buffer *sink,
206 uint32_t source_frames, uint32_t sink_frames)
207{
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500208 int i;
209 int j;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300210 struct polyphase_src *s;
211
212 struct comp_data *cd = comp_get_drvdata(dev);
213 int blk_in = cd->src[0].blk_in;
214 int blk_out = cd->src[0].blk_out;
215 int n_times = cd->src[0].stage1_times;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100216 int nch = dev->params.channels;
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300217 int32_t *dest = (int32_t *) sink->w_ptr;
218 int32_t *src = (int32_t *) source->r_ptr;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300219 int n_read = 0;
220 int n_written = 0;
221 struct src_stage_prm s1;
222
223 if (cd->src[0].mute) {
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300224 src_muted_s32(source, sink, blk_in, blk_out, nch,
225 source_frames);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300226 return;
227 }
228
229 s1.times = n_times;
230 s1.x_end_addr = source->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100231 s1.x_size = source->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300232 s1.x_inc = nch;
233 s1.y_end_addr = sink->end_addr;
Liam Girdwood44509242017-09-07 15:34:42 +0100234 s1.y_size = sink->size;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300235 s1.y_inc = nch;
Seppo Ingalsuo6f27ab62017-06-12 11:31:15 +0300236 s1.x_rptr = src + nch - 1;
237 s1.y_wptr = dest + nch - 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300238
239 for (j = 0; j < nch; j++) {
240 s = &cd->src[j]; /* Point to src for this channel */
241 s1.x_rptr = src++;
242 s1.y_wptr = dest++;
243 s1.state = &s->state1;
244 s1.stage = s->stage1;
245
246 for (i = 0; i + blk_in - 1 < source_frames; i += blk_in) {
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300247 if (cd->sign_extend_s24)
248 src_polyphase_stage_cir_s24(&s1);
249 else
250 src_polyphase_stage_cir(&s1);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300251
252 n_read += blk_in;
253 n_written += blk_out;
254 }
255
256 }
257 source->r_ptr = s1.x_rptr - nch + 1;
258 sink->w_ptr = s1.y_wptr - nch + 1;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300259}
260
261static struct comp_dev *src_new(struct sof_ipc_comp *comp)
262{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300263 struct comp_dev *dev;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100264 struct sof_ipc_comp_src *src;
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300265 struct sof_ipc_comp_src *ipc_src = (struct sof_ipc_comp_src *) comp;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300266 struct comp_data *cd;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100267 int i;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300268
Liam Girdwood3488cce2017-08-10 11:59:08 +0100269 trace_src("new");
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100270
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100271 /* validate init data - either SRC sink or source rate must be set */
272 if (ipc_src->source_rate == 0 && ipc_src->sink_rate == 0) {
273 trace_src_error("sn1");
274 return NULL;
275 }
276
Liam Girdwood3488cce2017-08-10 11:59:08 +0100277 dev = rzalloc(RZONE_RUNTIME, RFLAGS_NONE,
Liam Girdwood17641522017-06-09 17:27:02 +0100278 COMP_SIZE(struct sof_ipc_comp_src));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300279 if (dev == NULL)
280 return NULL;
281
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300282 src = (struct sof_ipc_comp_src *) &dev->comp;
Liam Girdwood960cf8e2017-06-12 11:38:07 +0100283 memcpy(src, ipc_src, sizeof(struct sof_ipc_comp_src));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300284
Liam Girdwood3488cce2017-08-10 11:59:08 +0100285 cd = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd));
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300286 if (cd == NULL) {
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300287 rfree(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300288 return NULL;
289 }
290
291 comp_set_drvdata(dev, cd);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300292
293 cd->delay_lines = NULL;
294 cd->src_func = src_2s_s32_default;
295 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
296 src_polyphase_reset(&cd->src[i]);
297
Liam Girdwoodbe41b682017-09-21 16:48:18 +0100298 dev->state = COMP_STATE_READY;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300299 return dev;
300}
301
302static void src_free(struct comp_dev *dev)
303{
304 struct comp_data *cd = comp_get_drvdata(dev);
305
Liam Girdwood3488cce2017-08-10 11:59:08 +0100306 trace_src("fre");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300307
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300308 /* Free dynamically reserved buffers for SRC algorithm */
309 if (cd->delay_lines != NULL)
310 rfree(cd->delay_lines);
311
312 rfree(cd);
313 rfree(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300314}
315
316/* set component audio stream parameters */
Liam Girdwood2cfaebe2017-08-21 17:13:52 +0100317static int src_params(struct comp_dev *dev)
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300318{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100319 struct sof_ipc_stream_params *params = &dev->params;
320 struct sof_ipc_comp_src *src = COMP_GET_IPC(dev, sof_ipc_comp_src);
321 struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
322 struct comp_data *cd = comp_get_drvdata(dev);
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500323 struct comp_buffer *sink;
324 struct comp_buffer *source;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300325 struct src_alloc need;
326 size_t delay_lines_size;
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500327 uint32_t source_rate;
328 uint32_t sink_rate;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300329 int32_t *buffer_start;
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500330 int n = 0;
331 int i;
332 int err;
333 int frames_is_for_source;
334 int nch;
335 int q;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300336
Liam Girdwood3488cce2017-08-10 11:59:08 +0100337 trace_src("par");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300338
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300339 /* SRC supports S24_4LE and S32_LE formats */
340 switch (config->frame_fmt) {
341 case SOF_IPC_FRAME_S24_4LE:
342 cd->sign_extend_s24 = 1;
343 break;
344 case SOF_IPC_FRAME_S32_LE:
345 cd->sign_extend_s24 = 0;
346 break;
347 default:
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100348 trace_src_error("sr0");
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300349 return -EINVAL;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100350 }
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300351
Liam Girdwood3488cce2017-08-10 11:59:08 +0100352 /* Calculate source and sink rates, one rate will come from IPC new
353 * and the other from params. */
354 if (src->source_rate == 0) {
355 /* params rate is source rate */
356 source_rate = params->rate;
357 sink_rate = src->sink_rate;
358 /* re-write our params with output rate for next component */
359 params->rate = sink_rate;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300360 frames_is_for_source = 0;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100361 } else {
362 /* params rate is sink rate */
363 source_rate = src->source_rate;
364 sink_rate = params->rate;
365 /* re-write our params with output rate for next component */
366 params->rate = source_rate;
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300367 frames_is_for_source = 1;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100368 }
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300369
370 /* Allocate needed memory for delay lines */
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300371 err = src_buffer_lengths(&need, source_rate, sink_rate,
372 params->channels, dev->frames, frames_is_for_source);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100373 if (err < 0) {
374 trace_src_error("sr1");
375 trace_value(source_rate);
376 trace_value(sink_rate);
377 trace_value(params->channels);
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300378 trace_value(dev->frames);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100379 return err;
380 }
381
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300382 delay_lines_size = sizeof(int32_t) * need.total;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100383 if (delay_lines_size == 0) {
384 trace_src_error("sr2");
385 return -EINVAL;
386 }
387
388 /* free any existing dalay lines. TODO reuse if same size */
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300389 if (cd->delay_lines != NULL)
390 rfree(cd->delay_lines);
391
Liam Girdwood22ce8062017-09-03 22:04:26 +0100392 cd->delay_lines = rballoc(RZONE_RUNTIME, RFLAGS_NONE, delay_lines_size);
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100393 if (cd->delay_lines == NULL) {
394 trace_src_error("sr3");
395 trace_value(delay_lines_size);
Liam Girdwood3488cce2017-08-10 11:59:08 +0100396 return -EINVAL;
Liam Girdwoodb12aa0d2017-09-03 22:00:58 +0100397 }
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300398
399 /* Clear all delay lines here */
400 memset(cd->delay_lines, 0, delay_lines_size);
401 cd->scratch_length = need.scratch;
402 buffer_start = cd->delay_lines + need.scratch;
403
404 /* Initize SRC for actual sample rate */
Seppo Ingalsuo849a5282017-09-22 16:08:44 +0300405 nch = MIN(params->channels, PLATFORM_MAX_CHANNELS);
406 for (i = 0; i < nch; i++) {
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300407 n = src_polyphase_init(&cd->src[i], source_rate, sink_rate,
408 &need, buffer_start);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300409 buffer_start += need.single_src;
410 }
411
412 switch (n) {
413 case 1:
414 cd->src_func = src_1s_s32_default; /* Simpler 1 stage SRC */
415 break;
416 case 2:
417 cd->src_func = src_2s_s32_default; /* Default 2 stage SRC */
418 break;
419 default:
420 /* This is possibly due to missing coefficients for
421 * requested rates combination. Sink audio will be
422 * muted if copy() is run.
423 */
424 trace_src("SFa");
425 cd->src_func = fallback_s32;
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300426 return -EINVAL;
Liam Girdwood3488cce2017-08-10 11:59:08 +0100427 break;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300428 }
429
Seppo Ingalsuo14d10a82017-09-22 16:08:47 +0300430 /* Calculate period size based on config. First make sure that
431 * frame_bytes is set.
432 */
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300433 dev->frame_bytes =
434 dev->params.sample_container_bytes * dev->params.channels;
Liam Girdwood44509242017-09-07 15:34:42 +0100435 cd->period_bytes = dev->frames * dev->frame_bytes;
436
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300437 /* The downstream buffer must be at least length of blk_out plus
438 * dev->frames and an integer multiple of dev->frames. The
439 * buffer_set_size will return an error if the required length would
440 * be too long.
441 */
442 q = need.blk_out / dev->frames;
443 if (q * dev->frames < need.blk_out)
444 ++q;
445
446 if (q * dev->frames < need.blk_out + dev->frames)
447 ++q;
448
449 /* Configure downstream buffer */
450 sink = list_first_item(&dev->bsink_list, struct comp_buffer,
451 source_list);
452 err = buffer_set_size(sink, q * dev->frames * dev->frame_bytes);
Liam Girdwood44509242017-09-07 15:34:42 +0100453 if (err < 0) {
454 trace_src_error("eSz");
Seppo Ingalsuo887628a2017-09-14 16:00:05 +0300455 trace_value(sink->alloc_size);
456 trace_value(q * dev->frames * dev->frame_bytes);
Liam Girdwood44509242017-09-07 15:34:42 +0100457 return err;
458 }
459
460 buffer_reset_pos(sink);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300461
Seppo Ingalsuo54162292017-09-12 13:45:50 +0300462 /* Check that source buffer has sufficient size */
463 source = list_first_item(&dev->bsource_list, struct comp_buffer,
464 sink_list);
465 if (source->size < need.blk_in * dev->frame_bytes) {
466 trace_src_error("eSy");
467 return -EINVAL;
468 }
469
470
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300471 return 0;
472}
473
Liam Girdwood854b2e52017-09-02 23:14:02 +0100474static int src_ctrl_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata)
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300475{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300476 struct comp_data *cd = comp_get_drvdata(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300477 int i;
478
Liam Girdwood854b2e52017-09-02 23:14:02 +0100479 switch (cdata->cmd) {
480 case SOF_CTRL_CMD_MUTE:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300481 trace_src("SMu");
482 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
483 src_polyphase_mute(&cd->src[i]);
484
485 break;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100486 case SOF_CTRL_CMD_UNMUTE:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300487 trace_src("SUm");
488 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
489 src_polyphase_unmute(&cd->src[i]);
490
491 break;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100492 default:
493 trace_src_error("ec1");
494 return -EINVAL;
495 }
496
497 return 0;
498}
499
500/* used to pass standard and bespoke commands (with data) to component */
501static int src_cmd(struct comp_dev *dev, int cmd, void *data)
502{
503 struct sof_ipc_ctrl_data *cdata = data;
Ranjani Sridharan62004082017-09-06 22:01:40 +0100504 int ret = 0;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100505
Liam Girdwoodbe41b682017-09-21 16:48:18 +0100506 trace_src("cmd");
507
508 ret = comp_set_state(dev, cmd);
509 if (ret < 0)
510 return ret;
Liam Girdwood854b2e52017-09-02 23:14:02 +0100511
512 switch (cmd) {
513 case COMP_CMD_SET_VALUE:
514 return src_ctrl_cmd(dev, cdata);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300515 default:
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300516 break;
517 }
518
Ranjani Sridharan62004082017-09-06 22:01:40 +0100519 return ret;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300520}
521
522/* copy and process stream data from source to sink buffers */
523static int src_copy(struct comp_dev *dev)
524{
525 struct comp_data *cd = comp_get_drvdata(dev);
Pierre-Louis Bossart4ccf81d2017-09-25 14:52:09 -0500526 struct comp_buffer *source;
527 struct comp_buffer *sink;
528 int need_source;
529 int need_sink;
530 int blk_in;
531 int blk_out;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300532
533 trace_comp("SRC");
534
535 /* src component needs 1 source and 1 sink buffer */
536 source = list_first_item(&dev->bsource_list, struct comp_buffer,
537 sink_list);
538 sink = list_first_item(&dev->bsink_list, struct comp_buffer,
539 source_list);
540
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300541 /* Calculate needed amount of source buffer and sink buffer
542 * for one SRC run.
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300543 */
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300544 blk_in = src_polyphase_get_blk_in(&cd->src[0]);
545 blk_out = src_polyphase_get_blk_out(&cd->src[0]);
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300546 need_source = blk_in * dev->frame_bytes;
547 need_sink = blk_out * dev->frame_bytes;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300548
549 /* Run as many times as buffers allow */
550 while ((source->avail >= need_source) && (sink->free >= need_sink)) {
551 /* Run src */
Seppo Ingalsuocb3a64d2017-09-06 15:16:12 +0300552 cd->src_func(dev, source, sink, blk_in, blk_out);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300553
Seppo Ingalsuo28ef8542017-08-25 18:29:04 +0300554 /* calc new free and available */
555 comp_update_buffer_consume(source, 0);
556 comp_update_buffer_produce(sink, 0);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300557 }
558
559 return 0;
560}
561
562static int src_prepare(struct comp_dev *dev)
563{
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300564 dev->state = COMP_STATE_PREPARE;
565 return 0;
566}
567
568static int src_preload(struct comp_dev *dev)
569{
Liam Girdwood3488cce2017-08-10 11:59:08 +0100570 return src_copy(dev);
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300571}
572
573static int src_reset(struct comp_dev *dev)
574{
575 int i;
576 struct comp_data *cd = comp_get_drvdata(dev);
577
578 trace_src("SRe");
579
580 cd->src_func = src_2s_s32_default;
581 for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
582 src_polyphase_reset(&cd->src[i]);
583
Liam Girdwoodbe41b682017-09-21 16:48:18 +0100584 dev->state = COMP_STATE_READY;
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300585 return 0;
586}
587
588struct comp_driver comp_src = {
589 .type = SOF_COMP_SRC,
Seppo Ingalsuo4a006912017-06-28 19:25:51 +0300590 .ops = {
Seppo Ingalsuo6a274832017-06-07 14:17:55 +0300591 .new = src_new,
592 .free = src_free,
593 .params = src_params,
594 .cmd = src_cmd,
595 .copy = src_copy,
596 .prepare = src_prepare,
597 .reset = src_reset,
598 .preload = src_preload,
599 },
600};
601
602void sys_comp_src_init(void)
603{
604 comp_register(&comp_src);
605}