1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2019 Intel Corporation. All rights reserved.
4 //
5 // Author: Slawomir Blauciak <slawomir.blauciak@linux.intel.com>
6
7 #include <sof/audio/buffer.h>
8 #include <sof/audio/component.h>
9 #include <sof/audio/data_blob.h>
10 #include <sof/audio/format.h>
11 #include <sof/audio/ipc-config.h>
12 #include <sof/audio/kpb.h>
13 #include <sof/common.h>
14 #include <sof/compiler_attributes.h>
15 #include <rtos/panic.h>
16 #include <sof/ipc/msg.h>
17 #include <rtos/alloc.h>
18 #include <rtos/init.h>
19 #include <sof/lib/memory.h>
20 #include <sof/lib/notifier.h>
21 #include <rtos/wait.h>
22 #include <sof/lib/uuid.h>
23 #include <sof/list.h>
24 #include <sof/math/numbers.h>
25 #include <rtos/string.h>
26 #include <sof/ut.h>
27 #include <sof/trace/trace.h>
28 #include <ipc/control.h>
29 #include <ipc/stream.h>
30 #include <ipc/topology.h>
31 #if CONFIG_IPC_MAJOR_4
32 #include <ipc4/detect_test.h>
33 #include <ipc4/notification.h>
34 #endif
35 #include <kernel/abi.h>
36 #include <sof/samples/audio/detect_test.h>
37 #include <user/trace.h>
38 #include <errno.h>
39 #include <stdbool.h>
40 #include <stddef.h>
41 #include <stdint.h>
42 #include <stdlib.h>
43 #include <sof/samples/audio/kwd_nn_detect_test.h>
44
45 #define ACTIVATION_DEFAULT_SHIFT 3
46 #define ACTIVATION_DEFAULT_COEF 0.05
47
48 #define ACTIVATION_DEFAULT_THRESHOLD_S16 \
49 Q_CONVERT_FLOAT(ACTIVATION_DEFAULT_COEF, 15) /* Q1.15 */
50 #define ACTIVATION_DEFAULT_THRESHOLD_S24 \
51 Q_CONVERT_FLOAT(ACTIVATION_DEFAULT_COEF, 23) /* Q1.23 */
52 #define ACTIVATION_DEFAULT_THRESHOLD_S32 \
53 Q_CONVERT_FLOAT(ACTIVATION_DEFAULT_COEF, 31) /* Q1.31 */
54
55 #define INITIAL_MODEL_DATA_SIZE 64
56
57 /* default number of samples before detection is activated */
58 #define KEYPHRASE_DEFAULT_PREAMBLE_LENGTH 0
59
60 #define KWD_NN_BUFF_ALIGN 64
61
62 static const struct comp_driver comp_keyword;
63
64 LOG_MODULE_REGISTER(kd_test, CONFIG_SOF_LOG_LEVEL);
65
66 /* eba8d51f-7827-47b5-82ee-de6e7743af67 */
67 DECLARE_SOF_RT_UUID("kd-test", keyword_uuid, 0xeba8d51f, 0x7827, 0x47b5,
68 0x82, 0xee, 0xde, 0x6e, 0x77, 0x43, 0xaf, 0x67);
69
70 DECLARE_TR_CTX(keyword_tr, SOF_UUID(keyword_uuid), LOG_LEVEL_INFO);
71
72 struct comp_data {
73 #ifdef CONFIG_IPC_MAJOR_4
74 struct ipc4_base_module_cfg base_cfg;
75 #endif
76 struct sof_detect_test_config config;
77 struct comp_data_blob_handler *model_handler;
78 void *data_blob;
79 size_t data_blob_size;
80 uint32_t data_blob_crc;
81
82 int32_t activation;
83 uint32_t detected;
84 uint32_t detect_preamble; /**< current keyphrase preamble length */
85 uint32_t keyphrase_samples; /**< keyphrase length in samples */
86 uint32_t drain_req; /** defines draining size in bytes. */
87 uint16_t sample_valid_bytes;
88 struct kpb_event_data event_data;
89 struct kpb_client client_data;
90
91 #if CONFIG_KWD_NN_SAMPLE_KEYPHRASE
92 int16_t *input;
93 size_t input_size;
94 #endif
95
96 struct ipc_msg *msg; /**< host notification */
97
98 void (*detect_func)(struct comp_dev *dev,
99 const struct audio_stream __sparse_cache *source, uint32_t frames);
100 struct sof_ipc_comp_event event;
101 };
102
detector_is_sample_width_supported(enum sof_ipc_frame sf)103 static inline bool detector_is_sample_width_supported(enum sof_ipc_frame sf)
104 {
105 bool ret;
106
107 switch (sf) {
108 #if CONFIG_FORMAT_S16LE
109 case SOF_IPC_FRAME_S16_LE:
110 /* FALLTHRU */
111 #endif /* CONFIG_FORMAT_S16LE */
112 #if CONFIG_FORMAT_S24LE
113 case SOF_IPC_FRAME_S24_4LE:
114 /* FALLTHRU */
115 #endif /* CONFIG_FORMAT_S24LE */
116 #if CONFIG_FORMAT_S32LE
117 case SOF_IPC_FRAME_S32_LE:
118 /* FALLTHRU */
119 #endif /* CONFIG_FORMAT_S32LE */
120 ret = true;
121 break;
122 default:
123 ret = false;
124 break;
125 }
126
127 return ret;
128 }
129
notify_host(const struct comp_dev * dev)130 static void notify_host(const struct comp_dev *dev)
131 {
132 struct comp_data *cd = comp_get_drvdata(dev);
133
134 comp_info(dev, "notify_host()");
135
136 #if CONFIG_IPC_MAJOR_4
137 ipc_msg_send(cd->msg, NULL, true);
138 #else
139 ipc_msg_send(cd->msg, &cd->event, true);
140 #endif /* CONFIG_IPC_MAJOR_4 */
141 }
142
notify_kpb(const struct comp_dev * dev)143 static void notify_kpb(const struct comp_dev *dev)
144 {
145 struct comp_data *cd = comp_get_drvdata(dev);
146
147 comp_info(dev, "notify_kpb(), preamble: %u", cd->detect_preamble);
148
149 cd->client_data.r_ptr = NULL;
150 cd->client_data.sink = NULL;
151 cd->client_data.id = 0; /**< TODO: acquire proper id from kpb */
152 /* time in milliseconds */
153 cd->client_data.drain_req = (cd->drain_req != 0) ?
154 cd->drain_req :
155 cd->config.drain_req;
156 cd->event_data.event_id = KPB_EVENT_BEGIN_DRAINING;
157 cd->event_data.client_data = &cd->client_data;
158
159 notifier_event(dev, NOTIFIER_ID_KPB_CLIENT_EVT,
160 NOTIFIER_TARGET_CORE_ALL_MASK, &cd->event_data,
161 sizeof(cd->event_data));
162 }
163
detect_test_notify(const struct comp_dev * dev)164 void detect_test_notify(const struct comp_dev *dev)
165 {
166 notify_host(dev);
167 notify_kpb(dev);
168 }
169
default_detect_test(struct comp_dev * dev,const struct audio_stream __sparse_cache * source,uint32_t frames)170 static void default_detect_test(struct comp_dev *dev,
171 const struct audio_stream __sparse_cache *source,
172 uint32_t frames)
173 {
174 struct comp_data *cd = comp_get_drvdata(dev);
175 void *src;
176 int32_t diff;
177 uint32_t count = frames; /**< Assuming single channel */
178 uint32_t sample;
179 uint16_t valid_bits = cd->sample_valid_bytes * 8;
180 const int32_t activation_threshold = cd->config.activation_threshold;
181 uint32_t cycles_per_frame; /**< Clock cycles required per frame */
182
183 /* synthetic load */
184 if (cd->config.load_mips) {
185 /* assuming count is a processing frame size in samples */
186 cycles_per_frame = (cd->config.load_mips * 1000000 * count)
187 / source->rate;
188 idelay(cycles_per_frame);
189 }
190
191 /* perform detection within current period */
192 for (sample = 0; sample < count && !cd->detected; ++sample) {
193 src = (valid_bits == 16U) ?
194 audio_stream_read_frag_s16(source, sample) :
195 audio_stream_read_frag_s32(source, sample);
196 if (valid_bits > 16U) {
197 diff = abs(*(int32_t *)src) - abs(cd->activation);
198 } else {
199 diff = abs(*(int16_t *)src) -
200 abs((int16_t)cd->activation);
201 }
202
203 diff >>= cd->config.activation_shift;
204 cd->activation += diff;
205
206 if (cd->detect_preamble >= cd->keyphrase_samples) {
207 if (cd->activation >= activation_threshold) {
208 /* The algorithm shall use cd->drain_req
209 * to specify its draining size request.
210 * Zero value means default config value
211 * will be used.
212 */
213 cd->drain_req = 0;
214 detect_test_notify(dev);
215 cd->detected = 1;
216 }
217 } else {
218 ++cd->detect_preamble;
219 }
220 }
221 }
222
test_keyword_get_threshold(struct comp_dev * dev,int sample_width)223 static int test_keyword_get_threshold(struct comp_dev *dev, int sample_width)
224 {
225 switch (sample_width) {
226 #if CONFIG_FORMAT_S16LE
227 case 16:
228 return ACTIVATION_DEFAULT_THRESHOLD_S16;
229 #endif /* CONFIG_FORMAT_S16LE */
230 #if CONFIG_FORMAT_S24LE
231 case 24:
232 return ACTIVATION_DEFAULT_THRESHOLD_S24;
233 #endif /* CONFIG_FORMAT_S24LE */
234 #if CONFIG_FORMAT_S32LE
235 case 32:
236 return ACTIVATION_DEFAULT_THRESHOLD_S32;
237 #endif /* CONFIG_FORMAT_S32LE */
238 default:
239 comp_err(dev, "test_keyword_get_threshold(), unsupported sample width: %d",
240 sample_width);
241 return -EINVAL;
242 }
243 }
244
test_keyword_apply_config(struct comp_dev * dev,const struct sof_detect_test_config * cfg)245 static int test_keyword_apply_config(struct comp_dev *dev,
246 const struct sof_detect_test_config *cfg)
247 {
248 struct comp_data *cd = comp_get_drvdata(dev);
249 uint16_t sample_width;
250 int ret;
251
252 ret = memcpy_s(&cd->config, sizeof(cd->config), cfg,
253 sizeof(struct sof_detect_test_config));
254 assert(!ret);
255
256 #if CONFIG_IPC_MAJOR_4
257 sample_width = cd->base_cfg.audio_fmt.depth;
258 #else
259 sample_width = cd->config.sample_width;
260 #endif /* CONFIG_IPC_MAJOR_4 */
261
262 if (!cd->config.activation_shift)
263 cd->config.activation_shift = ACTIVATION_DEFAULT_SHIFT;
264
265 if (!cd->config.activation_threshold) {
266 ret = test_keyword_get_threshold(dev, sample_width);
267 if (ret < 0) {
268 comp_err(dev, "test_keyword_apply_config(): unsupported sample width %u",
269 sample_width);
270 return ret;
271 }
272
273 cd->config.activation_threshold = ret;
274 }
275
276 return 0;
277 }
278
279 #if CONFIG_IPC_MAJOR_4
280 #define NOTIFICATION_DEFAULT_WORD_ID 1
281 #define NOTIFICATION_DEFAULT_SCORE 100
282
test_keyword_set_params(struct comp_dev * dev,struct sof_ipc_stream_params * params)283 static void test_keyword_set_params(struct comp_dev *dev,
284 struct sof_ipc_stream_params *params)
285 {
286 struct comp_data *cd = comp_get_drvdata(dev);
287 uint32_t __sparse_cache valid_fmt, frame_fmt;
288
289 comp_info(dev, "test_keyword_set_params()");
290
291 memset(params, 0, sizeof(*params));
292 params->channels = cd->base_cfg.audio_fmt.channels_count;
293 params->rate = cd->base_cfg.audio_fmt.sampling_frequency;
294 params->sample_container_bytes = cd->base_cfg.audio_fmt.depth / 8;
295 params->sample_valid_bytes =
296 cd->base_cfg.audio_fmt.valid_bit_depth / 8;
297 params->buffer_fmt = cd->base_cfg.audio_fmt.interleaving_style;
298 params->buffer.size = cd->base_cfg.ibs;
299
300 audio_stream_fmt_conversion(cd->base_cfg.audio_fmt.depth,
301 cd->base_cfg.audio_fmt.valid_bit_depth,
302 &frame_fmt, &valid_fmt,
303 cd->base_cfg.audio_fmt.s_type);
304
305 params->frame_fmt = frame_fmt;
306 }
307
test_keyword_set_config(struct comp_dev * dev,const char * data,uint32_t data_size)308 static int test_keyword_set_config(struct comp_dev *dev, const char *data,
309 uint32_t data_size)
310 {
311 const struct sof_detect_test_config *cfg;
312 size_t cfg_size;
313
314 /* Copy new config */
315 cfg = (const struct sof_detect_test_config *)data;
316 cfg_size = data_size;
317
318 comp_info(dev, "test_keyword_set_config(): config size = %u",
319 cfg_size);
320
321 if (cfg_size != sizeof(struct sof_detect_test_config)) {
322 comp_err(dev, "test_keyword_set_config(): invalid config size");
323 return -EINVAL;
324 }
325
326 return test_keyword_apply_config(dev, cfg);
327 }
328
test_keyword_get_config(struct comp_dev * dev,char * data,uint32_t * data_size)329 static int test_keyword_get_config(struct comp_dev *dev, char *data,
330 uint32_t *data_size)
331 {
332 struct comp_data *cd = comp_get_drvdata(dev);
333 size_t cfg_size;
334 int ret;
335
336 comp_info(dev, "test_keyword_get_config()");
337
338 cfg_size = sizeof(struct sof_detect_test_config);
339
340 if (cfg_size > *data_size) {
341 comp_err(dev, "test_keyword_get_config(): wrong config size: %d",
342 *data_size);
343 return -EINVAL;
344 }
345
346 *data_size = cfg_size;
347
348 /* Copy back to user space */
349 ret = memcpy_s(data, cfg_size, &cd->config, cfg_size);
350 assert(!ret);
351
352 return 0;
353 }
354
test_keyword_set_large_config(struct comp_dev * dev,uint32_t param_id,bool first_block,bool last_block,uint32_t data_offset,const char * data)355 static int test_keyword_set_large_config(struct comp_dev *dev,
356 uint32_t param_id,
357 bool first_block,
358 bool last_block,
359 uint32_t data_offset,
360 const char *data)
361 {
362 comp_dbg(dev, "test_keyword_set_large_config()");
363 struct comp_data *cd = comp_get_drvdata(dev);
364
365 switch (param_id) {
366 case IPC4_DETECT_TEST_SET_MODEL_BLOB:
367 return ipc4_comp_data_blob_set(cd->model_handler,
368 first_block,
369 last_block,
370 data_offset,
371 data);
372 case IPC4_DETECT_TEST_SET_CONFIG:
373 return test_keyword_set_config(dev, data, data_offset);
374 default:
375 return -EINVAL;
376 }
377 }
378
test_keyword_get_large_config(struct comp_dev * dev,uint32_t param_id,bool first_block,bool last_block,uint32_t * data_offset,char * data)379 static int test_keyword_get_large_config(struct comp_dev *dev,
380 uint32_t param_id,
381 bool first_block,
382 bool last_block,
383 uint32_t *data_offset,
384 char *data)
385 {
386 comp_dbg(dev, "test_keyword_get_large_config()");
387
388 switch (param_id) {
389 case IPC4_DETECT_TEST_GET_CONFIG:
390 return test_keyword_get_config(dev, data, data_offset);
391 default:
392 return -EINVAL;
393 }
394 }
395
test_keyword_get_attribute(struct comp_dev * dev,uint32_t type,void * value)396 static int test_keyword_get_attribute(struct comp_dev *dev,
397 uint32_t type,
398 void *value)
399 {
400 struct comp_data *cd = comp_get_drvdata(dev);
401
402 switch (type) {
403 case COMP_ATTR_BASE_CONFIG:
404 *(struct ipc4_base_module_cfg *)value = cd->base_cfg;
405 break;
406 default:
407 return -EINVAL;
408 }
409
410 return 0;
411 }
412
ipc4_kd_notification_init(uint32_t word_id,uint32_t score)413 static struct ipc_msg *ipc4_kd_notification_init(uint32_t word_id,
414 uint32_t score)
415 {
416 struct ipc4_voice_cmd_notification notif;
417 struct ipc_msg *msg;
418
419 memset_s(¬if, sizeof(notif), 0, sizeof(notif));
420
421 notif.primary.r.word_id = word_id;
422 notif.primary.r.notif_type = SOF_IPC4_NOTIFY_PHRASE_DETECTED;
423 notif.primary.r.type = SOF_IPC4_GLB_NOTIFICATION;
424 notif.primary.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST;
425 notif.primary.r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG;
426
427 notif.extension.r.sv_score = score;
428
429 msg = ipc_msg_w_ext_init(notif.primary.dat,
430 notif.extension.dat,
431 0);
432 if (!msg)
433 return NULL;
434
435 return msg;
436 }
437
438 #else /* CONFIG_IPC_MAJOR_4 */
test_keyword_set_config(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata)439 static int test_keyword_set_config(struct comp_dev *dev,
440 struct sof_ipc_ctrl_data *cdata)
441 {
442 struct sof_detect_test_config *cfg;
443 size_t bs;
444
445 /* Copy new config, find size from header */
446 cfg = (struct sof_detect_test_config *)cdata->data->data;
447 bs = cfg->size;
448
449 comp_info(dev, "test_keyword_set_config(), blob size = %u", bs);
450
451 if (bs != sizeof(struct sof_detect_test_config)) {
452 comp_err(dev, "test_keyword_set_config(): invalid blob size");
453 return -EINVAL;
454 }
455
456 return test_keyword_apply_config(dev, cfg);
457 }
458
test_keyword_set_params(struct comp_dev * dev,struct sof_ipc_stream_params * params)459 static void test_keyword_set_params(struct comp_dev *dev,
460 struct sof_ipc_stream_params *params)
461 {}
462
test_keyword_ctrl_set_bin_data(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata)463 static int test_keyword_ctrl_set_bin_data(struct comp_dev *dev,
464 struct sof_ipc_ctrl_data *cdata)
465 {
466 struct comp_data *cd = comp_get_drvdata(dev);
467 int ret = 0;
468
469 if (dev->state != COMP_STATE_READY) {
470 /* It is a valid request but currently this is not
471 * supported during playback/capture. The driver will
472 * re-send data in next resume when idle and the new
473 * configuration will be used when playback/capture
474 * starts.
475 */
476 comp_err(dev, "keyword_ctrl_set_bin_data(): driver is busy");
477 return -EBUSY;
478 }
479
480 switch (cdata->data->type) {
481 case SOF_DETECT_TEST_CONFIG:
482 ret = test_keyword_set_config(dev, cdata);
483 break;
484 case SOF_DETECT_TEST_MODEL:
485 ret = comp_data_blob_set_cmd(cd->model_handler, cdata);
486 break;
487 default:
488 comp_err(dev, "keyword_ctrl_set_bin_data(): unknown binary data type");
489 break;
490 }
491
492 return ret;
493 }
494
test_keyword_ctrl_set_data(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata)495 static int test_keyword_ctrl_set_data(struct comp_dev *dev,
496 struct sof_ipc_ctrl_data *cdata)
497 {
498 int ret = 0;
499
500 /* Check version from ABI header */
501 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
502 comp_err(dev, "test_keyword_cmd_set_data(): invalid version");
503 return -EINVAL;
504 }
505
506 switch (cdata->cmd) {
507 case SOF_CTRL_CMD_ENUM:
508 comp_info(dev, "test_keyword_cmd_set_data(), SOF_CTRL_CMD_ENUM");
509 break;
510 case SOF_CTRL_CMD_BINARY:
511 comp_info(dev, "test_keyword_cmd_set_data(), SOF_CTRL_CMD_BINARY");
512 ret = test_keyword_ctrl_set_bin_data(dev, cdata);
513 break;
514 default:
515 comp_err(dev, "test_keyword_cmd_set_data(): invalid cdata->cmd");
516 ret = -EINVAL;
517 break;
518 }
519
520 return ret;
521 }
522
test_keyword_get_config(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata,int size)523 static int test_keyword_get_config(struct comp_dev *dev,
524 struct sof_ipc_ctrl_data *cdata, int size)
525 {
526 struct comp_data *cd = comp_get_drvdata(dev);
527 size_t bs;
528 int ret = 0;
529
530 comp_info(dev, "test_keyword_get_config()");
531
532 /* Copy back to user space */
533 bs = cd->config.size;
534 comp_info(dev, "value of block size: %u", bs);
535
536 if (bs == 0 || bs > size)
537 return -EINVAL;
538
539 ret = memcpy_s(cdata->data->data, size, &cd->config, bs);
540 assert(!ret);
541
542 cdata->data->abi = SOF_ABI_VERSION;
543 cdata->data->size = bs;
544
545 return ret;
546 }
547
test_keyword_ctrl_get_bin_data(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata,int size)548 static int test_keyword_ctrl_get_bin_data(struct comp_dev *dev,
549 struct sof_ipc_ctrl_data *cdata,
550 int size)
551 {
552 struct comp_data *cd = comp_get_drvdata(dev);
553 int ret = 0;
554
555 switch (cdata->data->type) {
556 case SOF_DETECT_TEST_CONFIG:
557 ret = test_keyword_get_config(dev, cdata, size);
558 break;
559 case SOF_DETECT_TEST_MODEL:
560 ret = comp_data_blob_get_cmd(cd->model_handler, cdata, size);
561 break;
562 default:
563 comp_err(dev, "test_keyword_ctrl_get_bin_data(): unknown binary data type");
564 break;
565 }
566
567 return ret;
568 }
569
test_keyword_ctrl_get_data(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata,int size)570 static int test_keyword_ctrl_get_data(struct comp_dev *dev,
571 struct sof_ipc_ctrl_data *cdata, int size)
572 {
573 int ret = 0;
574
575 comp_info(dev, "test_keyword_ctrl_get_data() size: %d", size);
576
577 switch (cdata->cmd) {
578 case SOF_CTRL_CMD_BINARY:
579 ret = test_keyword_ctrl_get_bin_data(dev, cdata, size);
580 break;
581 default:
582 comp_err(dev, "test_keyword_ctrl_get_data(): invalid cdata->cmd");
583 return -EINVAL;
584 }
585
586 return ret;
587 }
588
589 /* used to pass standard and bespoke commands (with data) to component */
test_keyword_cmd(struct comp_dev * dev,int cmd,void * data,int max_data_size)590 static int test_keyword_cmd(struct comp_dev *dev, int cmd, void *data,
591 int max_data_size)
592 {
593 struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4);
594
595 comp_info(dev, "test_keyword_cmd()");
596
597 switch (cmd) {
598 case COMP_CMD_SET_DATA:
599 return test_keyword_ctrl_set_data(dev, cdata);
600 case COMP_CMD_GET_DATA:
601 return test_keyword_ctrl_get_data(dev, cdata, max_data_size);
602 default:
603 return -EINVAL;
604 }
605 }
606 #endif /* CONFIG_IPC_MAJOR_4 */
607
test_keyword_new(const struct comp_driver * drv,const struct comp_ipc_config * config,const void * spec)608 static struct comp_dev *test_keyword_new(const struct comp_driver *drv,
609 const struct comp_ipc_config *config,
610 const void *spec)
611 {
612 struct comp_dev *dev = NULL;
613 #if CONFIG_IPC_MAJOR_4
614 const struct ipc4_base_module_cfg *base_cfg = spec;
615 #else
616 const struct ipc_config_process *ipc_keyword = spec;
617 const struct sof_detect_test_config *cfg;
618 size_t bs;
619 #endif /* CONFIG_IPC_MAJOR_4 */
620 struct comp_data *cd = NULL;
621 int ret = 0;
622
623 comp_cl_info(&comp_keyword, "test_keyword_new()");
624
625 dev = comp_alloc(drv, sizeof(*dev));
626 if (!dev)
627 return NULL;
628 dev->ipc_config = *config;
629
630 cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd));
631
632 if (!cd)
633 goto fail;
634
635 #if CONFIG_KWD_NN_SAMPLE_KEYPHRASE
636 cd->detect_func = kwd_nn_detect_test;
637 #else
638 /* using default processing function */
639 cd->detect_func = default_detect_test;
640 #endif
641
642 comp_set_drvdata(dev, cd);
643
644 /* component model data handler */
645 cd->model_handler = comp_data_blob_handler_new(dev);
646
647 #if CONFIG_IPC_MAJOR_4
648 /* For IPC4 we only receive the base_cfg, make a copy of it */
649 memcpy_s(&cd->base_cfg, sizeof(cd->base_cfg), base_cfg, sizeof(*base_cfg));
650 #else
651 cfg = (const struct sof_detect_test_config *)ipc_keyword->data;
652 bs = ipc_keyword->size;
653
654 if (bs > 0) {
655 if (bs < sizeof(struct sof_detect_test_config)) {
656 comp_err(dev, "test_keyword_new(): invalid data size");
657 goto cd_fail;
658 }
659
660 if (test_keyword_apply_config(dev, cfg)) {
661 comp_err(dev, "test_keyword_new(): failed to apply config");
662 goto cd_fail;
663 }
664 }
665 #endif /* CONFIG_IPC_MAJOR_4 */
666
667 ret = comp_init_data_blob(cd->model_handler, INITIAL_MODEL_DATA_SIZE,
668 NULL);
669 if (ret < 0) {
670 comp_err(dev, "test_keyword_new(): model data initial failed");
671 goto cd_fail;
672 }
673
674 /* build component event */
675 ipc_build_comp_event(&cd->event, dev->ipc_config.type, dev->ipc_config.id);
676 cd->event.event_type = SOF_CTRL_EVENT_KD;
677 cd->event.num_elems = 0;
678
679 #if CONFIG_IPC_MAJOR_4
680 cd->msg = ipc4_kd_notification_init(NOTIFICATION_DEFAULT_WORD_ID,
681 NOTIFICATION_DEFAULT_SCORE);
682 #else
683 cd->msg = ipc_msg_init(cd->event.rhdr.hdr.cmd, sizeof(cd->event));
684 #endif /* CONFIG_IPC_MAJOR_4 */
685
686 if (!cd->msg) {
687 comp_err(dev, "test_keyword_new(): ipc notification init failed");
688 goto cd_fail;
689 }
690
691 #if CONFIG_KWD_NN_SAMPLE_KEYPHRASE
692 /* global buffer to accumulate data for processing */
693 cd->input = rballoc_align(0, SOF_MEM_CAPS_RAM,
694 sizeof(int16_t) * KWD_NN_IN_BUFF_SIZE, 64);
695 if (!cd->input) {
696 comp_err(dev, "test_keyword_new(): input alloc failed");
697 goto cd_fail;
698 }
699 bzero(cd->input, sizeof(int16_t) * KWD_NN_IN_BUFF_SIZE);
700 cd->input_size = 0;
701 #endif
702
703 dev->direction = SOF_IPC_STREAM_CAPTURE;
704 dev->direction_set = true;
705 dev->state = COMP_STATE_READY;
706 return dev;
707
708 cd_fail:
709 comp_data_blob_handler_free(cd->model_handler);
710 rfree(cd);
711 fail:
712 rfree(dev);
713 return NULL;
714 }
715
test_keyword_free(struct comp_dev * dev)716 static void test_keyword_free(struct comp_dev *dev)
717 {
718 struct comp_data *cd = comp_get_drvdata(dev);
719
720 comp_info(dev, "test_keyword_free()");
721
722 ipc_msg_free(cd->msg);
723 comp_data_blob_handler_free(cd->model_handler);
724 rfree(cd);
725 rfree(dev);
726 }
727
test_keyword_verify_params(struct comp_dev * dev,struct sof_ipc_stream_params * params)728 static int test_keyword_verify_params(struct comp_dev *dev,
729 struct sof_ipc_stream_params *params)
730 {
731 int ret;
732
733 comp_dbg(dev, "test_keyword_verify_params()");
734
735 ret = comp_verify_params(dev, 0, params);
736 if (ret < 0) {
737 comp_err(dev, "test_keyword_verify_params(): verification failed!");
738 return ret;
739 }
740
741 return 0;
742 }
743
744 /* set component audio stream parameters */
test_keyword_params(struct comp_dev * dev,struct sof_ipc_stream_params * params)745 static int test_keyword_params(struct comp_dev *dev,
746 struct sof_ipc_stream_params *params)
747 {
748 struct comp_data *cd = comp_get_drvdata(dev);
749 struct comp_buffer *sourceb;
750 struct comp_buffer __sparse_cache *source_c;
751 unsigned int channels, rate;
752 enum sof_ipc_frame frame_fmt;
753 int err;
754
755 test_keyword_set_params(dev, params);
756
757 err = test_keyword_verify_params(dev, params);
758 if (err < 0) {
759 comp_err(dev, "test_keyword_params(): pcm params verification failed.");
760 return err;
761 }
762
763 cd->sample_valid_bytes = params->sample_valid_bytes;
764
765 /* keyword components will only ever have 1 source */
766 sourceb = list_first_item(&dev->bsource_list, struct comp_buffer,
767 sink_list);
768 source_c = buffer_acquire(sourceb);
769 channels = source_c->stream.channels;
770 frame_fmt = source_c->stream.frame_fmt;
771 rate = source_c->stream.rate;
772 buffer_release(source_c);
773
774 if (channels != 1) {
775 comp_err(dev, "test_keyword_params(): only single-channel supported");
776 return -EINVAL;
777 }
778
779 if (!detector_is_sample_width_supported(frame_fmt)) {
780 comp_err(dev, "test_keyword_params(): only 16-bit format supported");
781 return -EINVAL;
782 }
783
784 /* calculate the length of the preamble */
785 if (cd->config.preamble_time) {
786 cd->keyphrase_samples = cd->config.preamble_time *
787 (rate / 1000);
788 } else {
789 cd->keyphrase_samples = KEYPHRASE_DEFAULT_PREAMBLE_LENGTH;
790 }
791
792 err = test_keyword_get_threshold(dev, params->sample_valid_bytes * 8);
793 if (err < 0) {
794 comp_err(dev, "test_keyword_params(): unsupported sample width %u",
795 params->sample_valid_bytes * 8);
796 return err;
797 }
798
799 cd->config.activation_threshold = err;
800
801 return 0;
802 }
803
test_keyword_trigger(struct comp_dev * dev,int cmd)804 static int test_keyword_trigger(struct comp_dev *dev, int cmd)
805 {
806 int ret;
807 struct comp_data *cd = comp_get_drvdata(dev);
808
809 comp_info(dev, "test_keyword_trigger()");
810
811 ret = comp_set_state(dev, cmd);
812 if (ret)
813 return ret;
814
815 if (cmd == COMP_TRIGGER_START ||
816 cmd == COMP_TRIGGER_RELEASE) {
817 cd->detect_preamble = 0;
818 cd->detected = 0;
819 cd->activation = 0;
820 }
821
822 return 0;
823 }
824
825 /* process stream data from source buffer */
test_keyword_copy(struct comp_dev * dev)826 static int test_keyword_copy(struct comp_dev *dev)
827 {
828 struct comp_data *cd = comp_get_drvdata(dev);
829 struct comp_buffer *source;
830 struct comp_buffer __sparse_cache *source_c;
831 uint32_t frames;
832
833 comp_dbg(dev, "test_keyword_copy()");
834
835 /* keyword components will only ever have 1 source */
836 source = list_first_item(&dev->bsource_list,
837 struct comp_buffer, sink_list);
838 source_c = buffer_acquire(source);
839
840 if (!source_c->stream.avail) {
841 buffer_release(source_c);
842 return PPL_STATUS_PATH_STOP;
843 }
844
845 frames = audio_stream_get_avail_frames(&source_c->stream);
846
847 /* copy and perform detection */
848 buffer_stream_invalidate(source_c, audio_stream_get_avail_bytes(&source_c->stream));
849 cd->detect_func(dev, &source_c->stream, frames);
850
851 /* calc new available */
852 comp_update_buffer_consume(source_c, audio_stream_get_avail_bytes(&source_c->stream));
853
854 buffer_release(source_c);
855
856 return 0;
857 }
858
test_keyword_reset(struct comp_dev * dev)859 static int test_keyword_reset(struct comp_dev *dev)
860 {
861 struct comp_data *cd = comp_get_drvdata(dev);
862
863 comp_info(dev, "test_keyword_reset()");
864
865 cd->activation = 0;
866 cd->detect_preamble = 0;
867 cd->detected = 0;
868
869 return comp_set_state(dev, COMP_TRIGGER_RESET);
870 }
871
test_keyword_prepare(struct comp_dev * dev)872 static int test_keyword_prepare(struct comp_dev *dev)
873 {
874 struct comp_data *cd = comp_get_drvdata(dev);
875 uint16_t valid_bits = cd->sample_valid_bytes * 8;
876 uint16_t sample_width;
877
878 #if CONFIG_IPC_MAJOR_4
879 sample_width = cd->base_cfg.audio_fmt.depth;
880 #else
881 sample_width = cd->config.sample_width;
882 #endif /* CONFIG_IPC_MAJOR_4 */
883
884 comp_info(dev, "test_keyword_prepare()");
885
886 if (valid_bits != sample_width) {
887 /* Default threshold value has to be changed
888 * according to host new format.
889 */
890 int ret = test_keyword_get_threshold(dev, valid_bits);
891
892 if (ret < 0) {
893 comp_err(dev, "test_keyword_prepare(): unsupported sample width %u",
894 valid_bits);
895 return ret;
896 }
897
898 cd->config.activation_threshold = ret;
899 }
900
901 cd->data_blob = comp_get_data_blob(cd->model_handler,
902 &cd->data_blob_size,
903 &cd->data_blob_crc);
904
905 return comp_set_state(dev, COMP_TRIGGER_PREPARE);
906 }
907
test_keyword_get_sample_valid_bytes(struct comp_dev * dev)908 uint16_t test_keyword_get_sample_valid_bytes(struct comp_dev *dev)
909 {
910 struct comp_data *cd = comp_get_drvdata(dev);
911
912 return cd->sample_valid_bytes;
913 }
914
test_keyword_get_detected(struct comp_dev * dev)915 uint32_t test_keyword_get_detected(struct comp_dev *dev)
916 {
917 struct comp_data *cd = comp_get_drvdata(dev);
918
919 return cd->detected;
920 }
921
test_keyword_set_detected(struct comp_dev * dev,uint32_t detected)922 void test_keyword_set_detected(struct comp_dev *dev, uint32_t detected)
923 {
924 struct comp_data *cd = comp_get_drvdata(dev);
925
926 cd->detected = detected;
927 }
928
929 #if CONFIG_KWD_NN_SAMPLE_KEYPHRASE
test_keyword_get_input(struct comp_dev * dev)930 const int16_t *test_keyword_get_input(struct comp_dev *dev)
931 {
932 struct comp_data *cd = comp_get_drvdata(dev);
933
934 return cd->input;
935 }
936
test_keyword_get_input_byte(struct comp_dev * dev,uint32_t index)937 int16_t test_keyword_get_input_byte(struct comp_dev *dev, uint32_t index)
938 {
939 struct comp_data *cd = comp_get_drvdata(dev);
940
941 if (index >= KWD_NN_IN_BUFF_SIZE * sizeof(int16_t))
942 return -EINVAL;
943
944 return *((unsigned char *)cd->input + index);
945 }
946
test_keyword_get_input_elem(struct comp_dev * dev,uint32_t index)947 int16_t test_keyword_get_input_elem(struct comp_dev *dev, uint32_t index)
948 {
949 struct comp_data *cd = comp_get_drvdata(dev);
950
951 if (index >= KWD_NN_IN_BUFF_SIZE)
952 return -EINVAL;
953 return cd->input[index];
954 }
955
test_keyword_set_input_elem(struct comp_dev * dev,uint32_t index,int16_t val)956 int test_keyword_set_input_elem(struct comp_dev *dev, uint32_t index, int16_t val)
957 {
958 struct comp_data *cd = comp_get_drvdata(dev);
959
960 if (index >= KWD_NN_IN_BUFF_SIZE)
961 return -EINVAL;
962
963 cd->input[index] = val;
964
965 return 0;
966 }
967
test_keyword_get_input_size(struct comp_dev * dev)968 size_t test_keyword_get_input_size(struct comp_dev *dev)
969 {
970 struct comp_data *cd = comp_get_drvdata(dev);
971
972 return cd->input_size;
973 }
974
test_keyword_set_input_size(struct comp_dev * dev,size_t input_size)975 void test_keyword_set_input_size(struct comp_dev *dev, size_t input_size)
976 {
977 struct comp_data *cd = comp_get_drvdata(dev);
978
979 cd->input_size = input_size;
980 }
981 #endif
982
test_keyword_get_drain_req(struct comp_dev * dev)983 uint32_t test_keyword_get_drain_req(struct comp_dev *dev)
984 {
985 struct comp_data *cd = comp_get_drvdata(dev);
986
987 return cd->drain_req;
988 }
989
test_keyword_set_drain_req(struct comp_dev * dev,uint32_t drain_req)990 void test_keyword_set_drain_req(struct comp_dev *dev, uint32_t drain_req)
991 {
992 struct comp_data *cd = comp_get_drvdata(dev);
993
994 cd->drain_req = drain_req;
995 }
996
997 static const struct comp_driver comp_keyword = {
998 .type = SOF_COMP_KEYWORD_DETECT,
999 .uid = SOF_RT_UUID(keyword_uuid),
1000 .tctx = &keyword_tr,
1001 .ops = {
1002 .create = test_keyword_new,
1003 .free = test_keyword_free,
1004 .params = test_keyword_params,
1005 #if CONFIG_IPC_MAJOR_4
1006 .set_large_config = test_keyword_set_large_config,
1007 .get_large_config = test_keyword_get_large_config,
1008 .get_attribute = test_keyword_get_attribute,
1009 #else
1010 .cmd = test_keyword_cmd,
1011 #endif /* CONFIG_IPC_MAJOR_4 */
1012 .trigger = test_keyword_trigger,
1013 .copy = test_keyword_copy,
1014 .prepare = test_keyword_prepare,
1015 .reset = test_keyword_reset,
1016 },
1017 };
1018
1019 static SHARED_DATA struct comp_driver_info comp_keyword_info = {
1020 .drv = &comp_keyword,
1021 };
1022
sys_comp_keyword_init(void)1023 UT_STATIC void sys_comp_keyword_init(void)
1024 {
1025 comp_register(platform_shared_get(&comp_keyword_info,
1026 sizeof(comp_keyword_info)));
1027 }
1028
1029 DECLARE_MODULE(sys_comp_keyword_init);
1030 SOF_MODULE_INIT(keyword, sys_comp_keyword_init);
1031