1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2020 Google LLC. All rights reserved.
4 //
5 // Author: Ben Zhang <benzh@chromium.org>
6 
7 #include <sof/audio/buffer.h>
8 #include <sof/audio/component.h>
9 #include <sof/audio/format.h>
10 #include <sof/audio/kpb.h>
11 #include <sof/common.h>
12 #include <sof/debug/panic.h>
13 #include <sof/ipc/msg.h>
14 #include <sof/lib/alloc.h>
15 #include <sof/lib/memory.h>
16 #include <sof/lib/notifier.h>
17 #include <sof/lib/wait.h>
18 #include <sof/lib/uuid.h>
19 #include <sof/list.h>
20 #include <sof/math/numbers.h>
21 #include <sof/string.h>
22 #include <sof/trace/trace.h>
23 #include <sof/ut.h>
24 #include <ipc/control.h>
25 #include <ipc/stream.h>
26 #include <ipc/topology.h>
27 #include <kernel/abi.h>
28 #include <user/trace.h>
29 #include <errno.h>
30 #include <stdbool.h>
31 #include <stddef.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34 
35 #include <hotword_dsp_api.h>
36 
37 /* IPC blob types */
38 #define GOOGLE_HOTWORD_DETECT_MODEL	0
39 
40 static const struct comp_driver ghd_driver;
41 
42 /* c3c74249-058e-414f-8240-4da5f3fc2389 */
43 DECLARE_SOF_RT_UUID("google-hotword-detect", ghd_uuid,
44 		    0xc3c74249, 0x058e, 0x414f,
45 		    0x82, 0x40, 0x4d, 0xa5, 0xf3, 0xfc, 0x23, 0x89);
46 DECLARE_TR_CTX(ghd_tr, SOF_UUID(ghd_uuid), LOG_LEVEL_INFO);
47 
48 struct comp_data {
49 	struct comp_data_blob_handler *model_handler;
50 	struct kpb_event_data event_data;
51 	struct kpb_client client_data;
52 
53 	struct sof_ipc_comp_event event;
54 	struct ipc_msg *msg;
55 
56 	int detected;
57 	size_t history_bytes;
58 };
59 
notify_host(const struct comp_dev * dev)60 static void notify_host(const struct comp_dev *dev)
61 {
62 	struct comp_data *cd = comp_get_drvdata(dev);
63 
64 	comp_dbg(dev, "notify_host()");
65 
66 	ipc_msg_send(cd->msg, &cd->event, true);
67 }
68 
notify_kpb(const struct comp_dev * dev)69 static void notify_kpb(const struct comp_dev *dev)
70 {
71 	struct comp_data *cd = comp_get_drvdata(dev);
72 
73 	comp_dbg(dev, "notify_kpb()");
74 
75 	cd->client_data.r_ptr = NULL;
76 	cd->client_data.sink = NULL;
77 	cd->client_data.id = 0;
78 	cd->event_data.event_id = KPB_EVENT_BEGIN_DRAINING;
79 	cd->event_data.client_data = &cd->client_data;
80 
81 	notifier_event(dev, NOTIFIER_ID_KPB_CLIENT_EVT,
82 		       NOTIFIER_TARGET_CORE_ALL_MASK, &cd->event_data,
83 		       sizeof(cd->event_data));
84 }
85 
ghd_create(const struct comp_driver * drv,struct sof_ipc_comp * comp_template)86 static struct comp_dev *ghd_create(const struct comp_driver *drv,
87 				   struct sof_ipc_comp *comp_template)
88 {
89 	struct comp_dev *dev = NULL;
90 	struct comp_data *cd = NULL;
91 	struct sof_ipc_comp_process *comp;
92 	int ret;
93 
94 	comp_cl_info(drv, "ghd_create()");
95 
96 	/* Create component device with an effect processing component */
97 	dev = comp_alloc(drv, COMP_SIZE(struct sof_ipc_comp_process));
98 	if (!dev)
99 		return NULL;
100 
101 	comp = COMP_GET_IPC(dev, sof_ipc_comp_process);
102 	ret = memcpy_s(comp, sizeof(*comp), comp_template,
103 		       sizeof(struct sof_ipc_comp_process));
104 	if (ret)
105 		goto fail;
106 
107 	/* Create private component data */
108 	cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM,
109 		     sizeof(*cd));
110 	if (!cd)
111 		goto fail;
112 	comp_set_drvdata(dev, cd);
113 
114 	/* Build component event */
115 	ipc_build_comp_event(&cd->event, comp->comp.type, comp->comp.id);
116 	cd->event.event_type = SOF_CTRL_EVENT_KD;
117 	cd->event.num_elems = 0;
118 
119 	cd->msg = ipc_msg_init(cd->event.rhdr.hdr.cmd, sizeof(cd->event));
120 	if (!cd->msg) {
121 		comp_err(dev, "ghd_create(): ipc_msg_init failed");
122 		goto cd_fail;
123 	}
124 
125 	/* Create component model data handler */
126 	cd->model_handler = comp_data_blob_handler_new(dev);
127 	if (!cd->model_handler) {
128 		comp_err(dev, "ghd_create(): comp_data_blob_handler_new failed");
129 		goto cd_fail;
130 	}
131 
132 	dev->state = COMP_STATE_READY;
133 	comp_dbg(dev, "ghd_create(): Ready");
134 	return dev;
135 
136 cd_fail:
137 	comp_data_blob_handler_free(cd->model_handler);
138 	ipc_msg_free(cd->msg);
139 	rfree(cd);
140 fail:
141 	rfree(dev);
142 	return NULL;
143 }
144 
ghd_free(struct comp_dev * dev)145 static void ghd_free(struct comp_dev *dev)
146 {
147 	struct comp_data *cd = comp_get_drvdata(dev);
148 
149 	comp_dbg(dev, "ghd_free()");
150 
151 	comp_data_blob_handler_free(cd->model_handler);
152 	ipc_msg_free(cd->msg);
153 	rfree(cd);
154 	rfree(dev);
155 }
156 
ghd_params(struct comp_dev * dev,struct sof_ipc_stream_params * params)157 static int ghd_params(struct comp_dev *dev,
158 		      struct sof_ipc_stream_params *params)
159 {
160 	struct comp_buffer *sourceb;
161 	int ret;
162 
163 	/* Detector is used only in KPB topology. It always requires channels
164 	 * parameter set to 1.
165 	 */
166 	params->channels = 1;
167 
168 	ret = comp_verify_params(dev, 0, params);
169 	if (ret < 0) {
170 		comp_err(dev, "ghd_params(): comp_verify_params failed.");
171 		return -EINVAL;
172 	}
173 
174 	/* This detector component will only ever have 1 source */
175 	sourceb = list_first_item(&dev->bsource_list, struct comp_buffer,
176 				  sink_list);
177 
178 	if (sourceb->stream.channels != 1) {
179 		comp_err(dev, "ghd_params(): Only single-channel supported");
180 		return -EINVAL;
181 	}
182 
183 	if (sourceb->stream.frame_fmt != SOF_IPC_FRAME_S16_LE) {
184 		comp_err(dev, "ghd_params(): Only S16_LE supported");
185 		return -EINVAL;
186 	}
187 
188 	if (sourceb->stream.rate != KPB_SAMPLNG_FREQUENCY) {
189 		comp_err(dev, "ghd_params(): Only 16KHz supported");
190 		return -EINVAL;
191 	}
192 
193 	return 0;
194 }
195 
ghd_setup_model(struct comp_dev * dev)196 static int ghd_setup_model(struct comp_dev *dev)
197 {
198 	struct comp_data *cd = comp_get_drvdata(dev);
199 	void *model;
200 	size_t size = 0;
201 	int ret;
202 
203 	/* Avoid the CRC calculation since it takes too long and causes XRUN.
204 	 *
205 	 * TODO: Add it back when there is support for running it in a low
206 	 * priority background task.
207 	 */
208 	model = comp_get_data_blob(cd->model_handler, &size, NULL);
209 	if (!model || !size) {
210 		comp_err(dev, "Model not set");
211 		return -EINVAL;
212 	}
213 	comp_info(dev, "Model: data=0x%08x, size=%zu",
214 		  (uint32_t)model, size);
215 
216 	comp_info(dev, "GoogleHotwordVersion %d",
217 		  GoogleHotwordVersion());
218 
219 	ret = GoogleHotwordDspInit(model);
220 	cd->detected = 0;
221 	cd->history_bytes = 0;
222 	if (ret != 1) {
223 		comp_err(dev, "GoogleHotwordDSPInit failed: %d", ret);
224 		return -EINVAL;
225 	}
226 
227 	return 0;
228 }
229 
ghd_ctrl_set_bin_data(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata)230 static int ghd_ctrl_set_bin_data(struct comp_dev *dev,
231 				 struct sof_ipc_ctrl_data *cdata)
232 {
233 	struct comp_data *cd = comp_get_drvdata(dev);
234 	int ret;
235 
236 	switch (cdata->data->type) {
237 	case GOOGLE_HOTWORD_DETECT_MODEL:
238 		ret = comp_data_blob_set_cmd(cd->model_handler, cdata);
239 		comp_dbg(dev, "ghd_ctrl_set_bin_data(): comp_data_blob_set_cmd=%d",
240 			 ret);
241 		return ret;
242 	default:
243 		comp_err(dev, "ghd_ctrl_set_bin_data(): Unknown cdata->data->type %d",
244 			 cdata->data->type);
245 		return -EINVAL;
246 	}
247 }
248 
ghd_ctrl_set_data(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata)249 static int ghd_ctrl_set_data(struct comp_dev *dev,
250 			     struct sof_ipc_ctrl_data *cdata)
251 {
252 	switch (cdata->cmd) {
253 	case SOF_CTRL_CMD_BINARY:
254 		return ghd_ctrl_set_bin_data(dev, cdata);
255 	default:
256 		comp_err(dev, "ghd_ctrl_set_data(): Only binary controls supported %d",
257 			 cdata->cmd);
258 		return -EINVAL;
259 	}
260 }
261 
ghd_ctrl_get_bin_data(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata,int max_data_size)262 static int ghd_ctrl_get_bin_data(struct comp_dev *dev,
263 				 struct sof_ipc_ctrl_data *cdata,
264 				 int max_data_size)
265 {
266 	struct comp_data *cd = comp_get_drvdata(dev);
267 	int ret;
268 
269 	switch (cdata->data->type) {
270 	case GOOGLE_HOTWORD_DETECT_MODEL:
271 		ret = comp_data_blob_get_cmd(cd->model_handler,
272 					     cdata,
273 					     max_data_size);
274 		comp_dbg(dev, "ghd_ctrl_get_bin_data(): comp_data_blob_get_cmd=%d, size=%d",
275 			 ret, max_data_size);
276 		return ret;
277 	default:
278 		comp_err(dev, "ghd_ctrl_get_bin_data(): Unknown cdata->data->type %d",
279 			 cdata->data->type);
280 		return -EINVAL;
281 	}
282 }
283 
ghd_ctrl_get_data(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata,int max_data_size)284 static int ghd_ctrl_get_data(struct comp_dev *dev,
285 			     struct sof_ipc_ctrl_data *cdata,
286 			     int max_data_size)
287 {
288 	switch (cdata->cmd) {
289 	case SOF_CTRL_CMD_BINARY:
290 		return ghd_ctrl_get_bin_data(dev, cdata, max_data_size);
291 	default:
292 		comp_err(dev, "ghd_ctrl_get_data(): Only binary controls supported %d",
293 			 cdata->cmd);
294 		return -EINVAL;
295 	}
296 }
297 
ghd_cmd(struct comp_dev * dev,int cmd,void * data,int max_data_size)298 static int ghd_cmd(struct comp_dev *dev, int cmd, void *data,
299 		   int max_data_size)
300 {
301 	struct sof_ipc_ctrl_data *cdata = data;
302 
303 	comp_dbg(dev, "ghd_cmd(): %d", cmd);
304 
305 	switch (cmd) {
306 	case COMP_CMD_SET_DATA:
307 		return ghd_ctrl_set_data(dev, cdata);
308 	case COMP_CMD_GET_DATA:
309 		return ghd_ctrl_get_data(dev, cdata, max_data_size);
310 	default:
311 		comp_err(dev, "ghd_cmd(): Unknown cmd %d", cmd);
312 		return -EINVAL;
313 	}
314 }
315 
ghd_trigger(struct comp_dev * dev,int cmd)316 static int ghd_trigger(struct comp_dev *dev, int cmd)
317 {
318 	struct comp_data *cd = comp_get_drvdata(dev);
319 
320 	comp_dbg(dev, "ghd_trigger(): %d", cmd);
321 
322 	if (cmd == COMP_TRIGGER_START || cmd == COMP_TRIGGER_RELEASE) {
323 		cd->detected = 0;
324 		cd->history_bytes = 0;
325 		GoogleHotwordDspReset();
326 	}
327 
328 	return comp_set_state(dev, cmd);
329 }
330 
ghd_detect(struct comp_dev * dev,struct audio_stream * stream,const void * samples,uint32_t bytes)331 static void ghd_detect(struct comp_dev *dev,
332 		       struct audio_stream *stream,
333 		       const void *samples,
334 		       uint32_t bytes)
335 {
336 	struct comp_data *cd = comp_get_drvdata(dev);
337 	int preamble_length_ms = 0;
338 	uint32_t sample_bytes;
339 	int ret;
340 
341 	if (cd->detected)
342 		return;
343 
344 	/* Assuming 1 channel, verified in ghd_params.
345 	 *
346 	 * TODO Make the logic multi channel safe when new hotword library can
347 	 * utilize multi channel data for detection.
348 	 */
349 	sample_bytes = audio_stream_sample_bytes(stream);
350 
351 	if (cd->history_bytes <
352 	    KPB_MAX_BUFF_TIME * KPB_SAMPLES_PER_MS * sample_bytes) {
353 		cd->history_bytes += bytes;
354 	}
355 
356 	comp_dbg(dev, "GoogleHotwordDspProcess(0x%x, %u)",
357 		 (uint32_t)samples, bytes / sample_bytes);
358 	ret = GoogleHotwordDspProcess(samples, bytes / sample_bytes,
359 				      &preamble_length_ms);
360 	if (ret == 1) {
361 		cd->detected = 1;
362 
363 		/* The current version of GoogleHotwordDspProcess always
364 		 * reports 2000ms preamble. Clamp this by the actual history
365 		 * length so KPB doesn't complain not enough data to drain when
366 		 * the hotword is detected right after pcm device open.
367 		 */
368 		cd->client_data.drain_req =
369 			MIN((size_t)preamble_length_ms,
370 			    (cd->history_bytes / sample_bytes) /
371 			     KPB_SAMPLES_PER_MS);
372 
373 		/* drain_req is actually in ms. See kpb_init_draining. */
374 		comp_info(dev, "Hotword detected %dms",
375 			  cd->client_data.drain_req);
376 		notify_host(dev);
377 		notify_kpb(dev);
378 	}
379 }
380 
ghd_copy(struct comp_dev * dev)381 static int ghd_copy(struct comp_dev *dev)
382 {
383 	struct comp_data *cd = comp_get_drvdata(dev);
384 	struct comp_buffer *source;
385 	struct audio_stream *stream;
386 	uint32_t flags = 0;
387 	uint32_t bytes, tail_bytes, head_bytes = 0;
388 	int ret;
389 
390 	/* Check for new model */
391 	if (comp_is_new_data_blob_available(cd->model_handler)) {
392 		comp_dbg(dev, "ghd_copy(): Switch to new model");
393 		ret = ghd_setup_model(dev);
394 		if (ret)
395 			return ret;
396 	}
397 
398 	/* keyword components will only ever have 1 source */
399 	source = list_first_item(&dev->bsource_list,
400 				 struct comp_buffer, sink_list);
401 	stream = &source->stream;
402 
403 	buffer_lock(source, &flags);
404 	bytes = audio_stream_get_avail_bytes(&source->stream);
405 	buffer_unlock(source, flags);
406 
407 	comp_dbg(dev, "ghd_copy() avail_bytes %u", bytes);
408 	comp_dbg(dev, "buffer begin/r_ptr/end [0x%x 0x%x 0x%x]",
409 		 (uint32_t)stream->addr,
410 		 (uint32_t)stream->r_ptr,
411 		 (uint32_t)stream->end_addr);
412 
413 	/* copy and perform detection */
414 	buffer_invalidate(source, bytes);
415 
416 	tail_bytes = (char *)stream->end_addr - (char *)stream->r_ptr;
417 	if (bytes <= tail_bytes)
418 		tail_bytes = bytes;
419 	else
420 		head_bytes = bytes - tail_bytes;
421 
422 	if (tail_bytes)
423 		ghd_detect(dev, stream, stream->r_ptr, tail_bytes);
424 	if (head_bytes)
425 		ghd_detect(dev, stream, stream->addr, head_bytes);
426 
427 	/* calc new available */
428 	comp_update_buffer_consume(source, bytes);
429 
430 	return 0;
431 }
432 
ghd_reset(struct comp_dev * dev)433 static int ghd_reset(struct comp_dev *dev)
434 {
435 	struct comp_data *cd = comp_get_drvdata(dev);
436 
437 	comp_dbg(dev, "ghd_reset()");
438 
439 	cd->detected = 0;
440 	cd->history_bytes = 0;
441 	GoogleHotwordDspReset();
442 
443 	return comp_set_state(dev, COMP_TRIGGER_RESET);
444 }
445 
ghd_prepare(struct comp_dev * dev)446 static int ghd_prepare(struct comp_dev *dev)
447 {
448 	int ret;
449 
450 	comp_dbg(dev, "ghd_prepare()");
451 
452 	ret = ghd_setup_model(dev);
453 	if (ret)
454 		return ret;
455 
456 	return comp_set_state(dev, COMP_TRIGGER_PREPARE);
457 }
458 
459 static const struct comp_driver ghd_driver = {
460 	.type	= SOF_COMP_KEYWORD_DETECT,
461 	.uid	= SOF_RT_UUID(ghd_uuid),
462 	.tctx	= &ghd_tr,
463 	.ops	= {
464 		.create		= ghd_create,
465 		.free		= ghd_free,
466 		.params		= ghd_params,
467 		.cmd		= ghd_cmd,
468 		.trigger	= ghd_trigger,
469 		.copy		= ghd_copy,
470 		.prepare	= ghd_prepare,
471 		.reset		= ghd_reset,
472 	},
473 };
474 
475 static SHARED_DATA struct comp_driver_info ghd_driver_info = {
476 	.drv = &ghd_driver,
477 };
478 
sys_comp_ghd_init(void)479 UT_STATIC void sys_comp_ghd_init(void)
480 {
481 	comp_register(platform_shared_get(&ghd_driver_info,
482 					  sizeof(ghd_driver_info)));
483 }
484 
485 DECLARE_MODULE(sys_comp_ghd_init);
486