blob: b72e2776d6ca330b3fa9edfef7c3c86c9469aeff [file] [log] [blame]
Quinn Male2e883752019-03-22 11:28:54 -07001/* st_session.c
2 *
3 * This file contains the state machine for a single sound trigger
4 * user session. This state machine implements logic for handling all user
5 * interactions, detectinos, SSR and Audio Concurencies.
6 *
Zhou Song388d0342020-02-16 16:31:05 +08007 * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
Quinn Male2e883752019-03-22 11:28:54 -07008 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
11 * met:
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * * Neither the name of The Linux Foundation nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
32 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34#define LOG_TAG "sound_trigger_hw"
35#define ATRACE_TAG (ATRACE_TAG_HAL)
36/* #define LOG_NDEBUG 0 */
37#define LOG_NDDEBUG 0
38
39#include <errno.h>
40#include <pthread.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <cutils/log.h>
44#include <cutils/trace.h>
45#include "st_session.h"
46#include "st_hw_session.h"
47#include "st_hw_session_lsm.h"
48#include "st_hw_session_gcs.h"
49#include "sound_trigger_hw.h"
50#include "st_hw_session_pcm.h"
51#include "st_hw_extn.h"
52#include "st_hw_common.h"
53#include "st_second_stage.h"
54
55#ifdef LINUX_ENABLED
56#define ST_SES_DEFERRED_STOP_DELAY_MS 0
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -070057#define ST_SES_DEFERRED_STOP_SS_DELAY_MS 0
Quinn Male2e883752019-03-22 11:28:54 -070058#else
59#define ST_SES_DEFERRED_STOP_DELAY_MS 1000
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -070060#define ST_SES_DEFERRED_STOP_SS_DELAY_MS 250
Quinn Male2e883752019-03-22 11:28:54 -070061#endif
62
63#define IS_SS_DETECTION_PENDING(det)\
64 (det & (KEYWORD_DETECTION_PENDING | USER_VERIFICATION_PENDING))
65#define IS_SS_DETECTION_SUCCESS(det)\
66 !(det & (KEYWORD_DETECTION_REJECT | USER_VERIFICATION_REJECT))
67
Dallas Delaneyf5132c72019-07-01 15:09:06 -070068#define IS_KEYWORD_DETECTION_MODEL(sm_id) (sm_id & ST_SM_ID_SVA_KWD)
69
70#define IS_USER_VERIFICATION_MODEL(sm_id) (sm_id & ST_SM_ID_SVA_VOP)
71
72#define IS_SECOND_STAGE_MODEL(sm_id)\
73 ((sm_id & ST_SM_ID_SVA_KWD) || (sm_id & ST_SM_ID_SVA_VOP))
74
75#define IS_MATCHING_SS_MODEL(usecase_sm_id, levels_sm_id)\
76 ((usecase_sm_id & levels_sm_id) ||\
77 ((usecase_sm_id & ST_SM_ID_SVA_RNN) && (levels_sm_id & ST_SM_ID_SVA_CNN)))
78
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -070079#define STATE_TRANSITION(st_session, new_state_fn)\
80do {\
81 if (st_session->current_state != new_state_fn) {\
82 st_session->current_state = new_state_fn;\
83 ALOGD("session[%d]: %s ---> %s", st_session->sm_handle, __func__, \
84 #new_state_fn);\
85 }\
86} while(0)
87
88#define DISPATCH_EVENT(st_session, event, status)\
89do {\
90 status = st_session->current_state(st_session, &event);\
91} while (0)
92
93#define REG_SM_RETRY_CNT 5
94#define REG_SM_WAIT_TIME_MS 100
95
96#define MAX_CONF_LEVEL_VALUE (100)
97#define MAX_KW_USERS_NAME_LEN (2 * MAX_STRING_LEN)
98
Quinn Male2e883752019-03-22 11:28:54 -070099/* below enum used in cleanup in error scenarios */
100enum hw_session_err_mask {
101 HW_SES_ERR_MASK_DEVICE_SET = 0x1,
102 HW_SES_ERR_MASK_REG_SM = 0x2,
103 HW_SES_ERR_MASK_REG_SM_PARAM = 0x4,
104 HW_SES_ERR_MASK_STARTED = 0x8,
105 HW_SES_ERR_MASK_BUFFERING = 0x10,
106};
107
Quinn Male2e883752019-03-22 11:28:54 -0700108typedef struct st_session_loadsm_payload {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700109 struct sound_trigger_phrase_sound_model *phrase_sm;
Quinn Male2e883752019-03-22 11:28:54 -0700110} st_session_loadsm_payload_t;
111
112typedef struct st_session_start_payload {
113 void *config;
114 size_t config_size;
115 recognition_callback_t callback;
116 void *cookie;
117} st_session_start_payload_t;
118
119typedef struct st_session_read_pcm_payload {
120 void *out_buff;
121 size_t out_buff_size;
122 size_t *actual_read_size;
123} st_session_readpcm_payload_t;
124
125typedef struct st_session_get_param_payload {
126 const char *param;
127 void *payload;
128 size_t payload_size;
129 size_t *param_data_size;
130} st_session_getparam_payload_t;
131
132struct st_session_ev {
133 st_session_event_id_t ev_id;
134 union {
135 st_session_loadsm_payload_t loadsm;
136 st_session_start_payload_t start;
137 st_hw_sess_detected_ev_t detected;
138 st_exec_mode_t exec_mode;
139 st_session_readpcm_payload_t readpcm;
140 enum ssr_event_status ssr;
141 char *chmix_coeff_str;
142 bool enable;
143 st_session_getparam_payload_t getparam;
144 } payload;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700145 st_session_t *stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -0700146};
147
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700148static int idle_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
149static int loaded_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
150static int active_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
151static int detected_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
152static int buffering_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
153static int ssr_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
154
155static inline int process_detection_event
156(
157 st_proxy_session_t *st_ses, uint64_t timestamp, int detect_status,
158 void *payload, size_t payload_size,
159 struct sound_trigger_recognition_event **event
160);
161
Quinn Male3d7d9d42019-05-20 13:35:01 -0700162ST_DBG_DECLARE(static int file_cnt = 0);
Quinn Male2e883752019-03-22 11:28:54 -0700163
164void hw_sess_cb(st_hw_sess_event_t *hw_event, void *cookie)
165{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700166 st_proxy_session_t *st_ses = (st_proxy_session_t *)cookie;
Quinn Male2e883752019-03-22 11:28:54 -0700167 int status = 0;
168 int lock_status = 0;
169
170 if (!hw_event || !cookie) {
171 ALOGE("%s: received NULL params", __func__);
172 return;
173 }
174
175 switch (hw_event->event_id) {
176 case ST_HW_SESS_EVENT_DETECTED:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700177 {
178 st_session_ev_t ev;
179 ev.ev_id = ST_SES_EV_DETECTED;
180 ev.payload.detected = hw_event->payload.detected;
Quinn Male2e883752019-03-22 11:28:54 -0700181
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700182 do {
183 lock_status = pthread_mutex_trylock(&st_ses->lock);
184 } while (lock_status && !st_ses->device_disabled &&
185 (st_ses->exec_mode != ST_EXEC_MODE_NONE) &&
186 (st_ses->current_state != ssr_state_fn));
Quinn Male2e883752019-03-22 11:28:54 -0700187
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700188 if (st_ses->device_disabled) {
189 ALOGV("%s:[%d] device switch in progress, ignore event",
190 __func__, st_ses->sm_handle);
191 } else if (st_ses->exec_mode == ST_EXEC_MODE_NONE) {
192 ALOGV("%s:[%d] transition in progress, ignore event",
193 __func__, st_ses->sm_handle);
194 } else if (st_ses->current_state == ssr_state_fn) {
195 ALOGV("%s:[%d] SSR handling in progress, ignore event",
196 __func__, st_ses->sm_handle);
197 } else if (!lock_status) {
Quinn Male2e883752019-03-22 11:28:54 -0700198 /*
199 * TODO: Add RECOGNITION_STATUS_GET_STATE_RESPONSE to
200 * the SoundTrigger API header.
201 */
202 if (st_ses->detection_requested)
203 ev.payload.detected.detect_status = 3;
204
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700205 DISPATCH_EVENT(st_ses, ev, status);
Quinn Male2e883752019-03-22 11:28:54 -0700206 }
207
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700208 if (!lock_status)
209 pthread_mutex_unlock(&st_ses->lock);
210 break;
211 }
212
Quinn Male48490df2020-03-25 10:25:42 -0700213 case ST_HW_SESS_EVENT_BUFFERING_STOPPED:
214 {
215 st_session_ev_t ev;
216 ev.ev_id = ST_SES_EV_DEFERRED_STOP;
217 ev.stc_ses = st_ses->det_stc_ses;
218
219 /*
220 * If detection is sent to client while in buffering state,
221 * and if internal buffering is stopped due to errors, stop
222 * session internally as client is expected to restart the
223 * detection if required.
224 * Note: It is possible that detection event is not sent to
225 * client if second stage is not yet detected during internal
226 * buffering stop, in which case restart is posted from second
227 * stage thread for further detections. Only if the second
228 * stage detection hasn't be started due to internal buffering
229 * stop too early, restart session should be explictily issued.
230 */
231
232 do {
233 lock_status = pthread_mutex_trylock(&st_ses->lock);
234 } while (lock_status && !st_ses->det_stc_ses->pending_stop &&
Quinn Male31afd392020-06-30 17:35:10 -0700235 (st_ses->current_state == buffering_state_fn) &&
236 !st_ses->stdev->ssr_offline_received);
Quinn Male48490df2020-03-25 10:25:42 -0700237
238 if (st_ses->det_stc_ses->pending_stop)
239 ALOGV("%s:[%d] pending stop already queued, ignore event",
240 __func__, st_ses->sm_handle);
241 else if (!st_ses->det_stc_ses->detection_sent)
242 ALOGV("%s:[%d] client callback hasn't been called, ignore event",
243 __func__, st_ses->sm_handle);
244 else if (st_ses->current_state != buffering_state_fn)
245 ALOGV("%s:[%d] session already stopped buffering, ignore event",
246 __func__, st_ses->sm_handle);
Quinn Male31afd392020-06-30 17:35:10 -0700247 else if (st_ses->stdev->ssr_offline_received)
248 ALOGV("%s:[%d] SSR handling in progress, ignore event",
249 __func__, st_ses->sm_handle);
Quinn Male48490df2020-03-25 10:25:42 -0700250 else if (!lock_status)
251 DISPATCH_EVENT(st_ses, ev, status);
252
253 if (!lock_status)
254 pthread_mutex_unlock(&st_ses->lock);
255 break;
256 }
257
Quinn Male2e883752019-03-22 11:28:54 -0700258 default:
259 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
260 break;
261 };
Quinn Male2e883752019-03-22 11:28:54 -0700262}
263
Quinn Male58749452020-03-26 17:14:56 -0700264static inline struct st_proxy_ses_sm_info_wrapper *get_sm_info_for_model_id
265(
266 st_proxy_session_t *st_ses,
267 uint32_t model_id
268)
269{
270 struct listnode *node = NULL;
271 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
272
273 list_for_each(node, &st_ses->sm_info_list) {
274 p_info = node_to_item(node, struct st_proxy_ses_sm_info_wrapper,
275 sm_list_node);
276
277 if (p_info->sm_info.model_id == model_id)
278 return p_info;
279 }
280
281 return NULL;
282}
283
284static inline struct st_hw_ses_config *get_sthw_cfg_for_model_id
285(
286 st_hw_session_t *hw_ses,
287 uint32_t model_id
288)
289{
290 struct listnode *node = NULL;
291 struct st_hw_ses_config *sthw_cfg = NULL;
292
293 list_for_each(node, &hw_ses->sthw_cfg_list) {
294 sthw_cfg = node_to_item(node, struct st_hw_ses_config,
295 sthw_cfg_list_node);
296
297 if (sthw_cfg->model_id == model_id)
298 return sthw_cfg;
299 }
300
301 return NULL;
302}
303
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700304static inline void free_array_ptrs(char **arr, unsigned int arr_len)
305{
306 int i = 0;
307
308 if (!arr)
309 return;
310
311 for (i = 0; i < arr_len; i++) {
312 if (arr[i]) {
313 free(arr[i]);
314 arr[i] = NULL;
315 }
316 }
317 free(arr);
318 arr = NULL;
319}
320
321static inline void alloc_array_ptrs(char ***arr, unsigned int arr_len,
322 unsigned int elem_len)
323{
324 char **str_arr = NULL;
325 int i = 0;
326
327 str_arr = (char **) calloc(arr_len, sizeof(char *));
328
329 if (!str_arr) {
330 *arr = NULL;
331 return;
332 }
333
334 for (i = 0; i < arr_len; i++) {
335 str_arr[i] = (char *) calloc(elem_len, sizeof(char));
336 if (str_arr[i] == NULL) {
337 free_array_ptrs(str_arr, i);
338 *arr = NULL;
339 return;
340 }
341 }
342 *arr = str_arr;
343 ALOGV("%s: string array %p", __func__, *arr);
344 for (i = 0; i < arr_len; i++)
345 ALOGV("%s: string array[%d] %p", __func__, i, (*arr)[i]);
346}
347
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700348static int merge_sound_models(struct sound_trigger_device *stdev,
349 unsigned int num_models, listen_model_type *in_models[],
350 listen_model_type *out_model)
351{
352 listen_status_enum sm_ret = 0;
353 int status = 0;
354
355 ALOGV("%s: num_models to merge %d", __func__, num_models);
356
357 if (!stdev->smlib_handle) {
358 ALOGE("%s: NULL sound model lib handle", __func__);
359 return -ENOSYS;
360 }
361
362 sm_ret = stdev->smlib_getMergedModelSize(num_models, in_models,
363 &out_model->size);
364 if ((sm_ret != kSucess) || !out_model->size) {
365 ALOGE("%s: smlib_getMergedModelSize failed, err %d, size %d", __func__,
366 sm_ret, out_model->size);
367 return -EINVAL;
368 }
369 ALOGD("%s: merge sound model size %d", __func__, out_model->size);
370
371 out_model->data = calloc(1, out_model->size * sizeof(char));
372 if (!out_model->data) {
373 ALOGE("%s: Merged sound model allocation failed", __func__);
374 return -ENOMEM;
375 }
376
377 sm_ret = stdev->smlib_mergeModels(num_models, in_models, out_model);
378 if (sm_ret != kSucess) {
379 ALOGE("%s: smlib_mergeModels failed, err %d", __func__, sm_ret);
380 status = -EINVAL;
381 goto cleanup;
382 }
383 if (!out_model->data || !out_model->size) {
384 ALOGE("%s: MergeModels returned NULL data or size %d", __func__,
385 out_model->size);
386 status = -EINVAL;
387 goto cleanup;
388 }
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -0700389 if (stdev->enable_debug_dumps) {
390 ST_DBG_DECLARE(FILE *sm_fd = NULL; static int sm_cnt = 0);
391 ST_DBG_FILE_OPEN_WR(sm_fd, ST_DEBUG_DUMP_LOCATION,
392 "st_smlib_output_merged_sm", "bin", sm_cnt++);
393 ST_DBG_FILE_WRITE(sm_fd, out_model->data, out_model->size);
394 ST_DBG_FILE_CLOSE(sm_fd);
395 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700396 ALOGV("%s: Exit", __func__);
397 return 0;
398
399cleanup:
400 if (out_model->data) {
401 free(out_model->data);
402 out_model->data = NULL;
403 out_model->size = 0;
404 }
405 return status;
406}
407
408static int delete_from_merged_sound_model(struct sound_trigger_device *stdev,
409 char **keyphrases, unsigned int num_keyphrases,
410 listen_model_type *in_model, listen_model_type *out_model)
411{
412 listen_model_type merge_model = {0};
413 listen_status_enum sm_ret = 0;
414 unsigned int out_model_sz = 0;
415 int status = 0, i = 0;
416
417 out_model->data = NULL;
418 out_model->size = 0;
419 merge_model.data = in_model->data;
420 merge_model.size = in_model->size;
421
422 for (i = 0; i < num_keyphrases; i++) {
423 sm_ret = stdev->smlib_getSizeAfterDeleting(&merge_model, keyphrases[i],
424 NULL, &out_model_sz);
425 if (sm_ret != kSucess) {
426 ALOGE("%s: smlib_getSizeAfterDeleting failed %d", __func__, sm_ret);
427 status = -EINVAL;
428 goto cleanup;
429 }
430 if (out_model_sz >= in_model->size) {
431 ALOGE("%s: unexpected, smlib_getSizeAfterDeleting returned size %d"
432 "not less than merged model size %d", __func__,
433 out_model_sz, in_model->size);
434 status = -EINVAL;
435 goto cleanup;
436 }
437 ALOGV("%s: Size after deleting kw[%d] = %d", __func__, i, out_model_sz);
438 if (!out_model->data) {
439 /* Valid if deleting multiple keyphrases one after other */
440 free (out_model->data);
441 out_model->size = 0;
442 }
443 out_model->data = calloc(1, out_model_sz * sizeof(char));
444 if (!out_model->data) {
445 ALOGE("%s: Merge sound model allocation failed, size %d ", __func__,
446 out_model_sz);
447 status = -ENOMEM;
448 goto cleanup;
449 }
450 out_model->size = out_model_sz;
451
452 sm_ret = stdev->smlib_deleteFromModel(&merge_model, keyphrases[i],
453 NULL, out_model);
454 if (sm_ret != kSucess) {
455 ALOGE("%s: smlib_getSizeAfterDeleting failed %d", __func__, sm_ret);
456 status = -EINVAL;
457 goto cleanup;
458 }
459 if (out_model->size != out_model_sz) {
460 ALOGE("%s: unexpected, out_model size %d != expected size %d",
461 __func__, out_model->size, out_model_sz);
462 status = -EINVAL;
463 goto cleanup;
464 }
465 /* Used if deleting multiple keyphrases one after other */
466 merge_model.data = out_model->data;
467 merge_model.size = out_model->size;
468 }
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -0700469 if (stdev->enable_debug_dumps && out_model->data && out_model->size) {
470 ST_DBG_DECLARE(FILE *sm_fd = NULL; static int sm_cnt = 0);
471 ST_DBG_FILE_OPEN_WR(sm_fd, ST_DEBUG_DUMP_LOCATION,
472 "st_smlib_output_deleted_sm", "bin", sm_cnt++);
473 ST_DBG_FILE_WRITE(sm_fd, out_model->data, out_model->size);
474 ST_DBG_FILE_CLOSE(sm_fd);
475 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700476 return 0;
477
478cleanup:
479 if (out_model->data) {
480 free(out_model->data);
481 out_model->data = NULL;
482 }
483 return status;
484}
485
486static void release_sound_model_info(struct sound_model_info *sm_info)
487{
488 ALOGV("%s", __func__);
489
490 if (sm_info->cf_levels) {
491 free(sm_info->cf_levels);
492 sm_info->cf_levels = NULL;
493 sm_info->det_cf_levels = NULL;
494 }
495 free_array_ptrs(sm_info->keyphrases, sm_info->num_keyphrases);
496 sm_info->keyphrases = NULL;
497
498 free_array_ptrs(sm_info->users, sm_info->num_users);
499 sm_info->users = NULL;
500
501 free_array_ptrs(sm_info->cf_levels_kw_users, sm_info->cf_levels_size);
502 sm_info->cf_levels_kw_users = NULL;
503}
504
505static inline void stdbg_print_sound_model_header(
506 listen_sound_model_header *smh)
507{
508 int i = 0, j = 0;
509
510 ALOGV("%s", __func__);
511 ALOGV("numKeywords = %d", smh->numKeywords);
512 ALOGV("numUsers = %d", smh->numUsers);
513 ALOGV("numActiveUserKeywordPairs = %d", smh->numActiveUserKeywordPairs);
514 ALOGV("isStripped = %d", smh->isStripped);
515 ALOGV("model_indicator = %d", smh->model_indicator);
516
517 for (i = 0; i < smh->numKeywords; i++) {
518 ALOGV("kw-%d langPerKw = %d", i, smh->langPerKw[i]);
519 ALOGV("kw-%d numUsersSetPerKw = %d", i, smh->numUsersSetPerKw[i]);
520 ALOGV("kw-%d isUserDefinedKeyword = %d", i,
521 smh->isUserDefinedKeyword[i]);
522 }
523 if (smh->userKeywordPairFlags) {
524 for (i = 0; i < smh->numUsers; i++) {
525 for (j = 0; j < smh->numKeywords; j++)
526 ALOGV("userKeywordPairFlags[%d][%d] = %d", i, j,
527 smh->userKeywordPairFlags[i][j]);
528 }
529 }
530}
531
532static int query_sound_model(struct sound_trigger_device *stdev,
533 struct sound_model_info *sm_info, unsigned char *sm_data,
534 unsigned int sm_size)
535{
536 listen_sound_model_header sm_header = {0};
537 listen_model_type model = {0};
538 listen_status_enum sm_ret = 0;
539 int status = 0, i = 0, j = 0, k = 0;
540 uint16_t tmp = 0;
541
542 ALOGV("%s: enter sm_size %d", __func__, sm_size);
543
544 if (!stdev->smlib_handle) {
545 ALOGE("%s: NULL sound model lib handle", __func__);
546 return -ENOSYS;
547 }
548
549 model.data = sm_data;
550 model.size = sm_size;
551
552 sm_ret = stdev->smlib_getSoundModelHeader(&model, &sm_header);
553 if (sm_ret != kSucess) {
554 ALOGE("%s: smlib_getSoundModelHeader failed, err %d ", __func__, sm_ret);
555 return -EINVAL;
556 }
557 if (sm_header.numKeywords == 0) {
558 ALOGE("%s: num keywords zero!!", __func__);
559 return -EINVAL;
560 }
561 if (sm_header.numActiveUserKeywordPairs < sm_header.numUsers) {
562 ALOGE("%s: smlib activeUserKwPairs(%d) < total users (%d)", __func__,
563 sm_header.numActiveUserKeywordPairs, sm_header.numUsers);
564 goto cleanup;
565 }
566 if (sm_header.numUsers && !sm_header.userKeywordPairFlags) {
567 ALOGE("%s: userKeywordPairFlags is NULL, numUsers (%d)", __func__,
568 sm_header.numUsers);
569 goto cleanup;
570 }
571 stdbg_print_sound_model_header(&sm_header);
572
573 /* MAX_STRING_LEN is part of listen sound model header file */
574 alloc_array_ptrs(&sm_info->keyphrases, sm_header.numKeywords,
575 MAX_STRING_LEN);
576 if (!sm_info->keyphrases) {
577 ALOGE("%s: keyphrases allocation failed", __func__);
578 status = -ENOMEM;
579 goto cleanup;
580 }
581 sm_info->num_keyphrases = sm_header.numKeywords;
582 sm_info->num_users = sm_header.numUsers;
583
584 tmp = sm_header.numKeywords;
Zhou Songdeddfcc2019-06-18 22:25:03 +0800585 ALOGV("%s: stdb: model.data %pK, model.size %d", __func__, model.data,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700586 model.size);
587 sm_ret = stdev->smlib_getKeywordPhrases(&model, &tmp, sm_info->keyphrases);
588 if (sm_ret) {
589 ALOGE("%s: smlib_getKeywordPhrases failed, err %d ", __func__, sm_ret);
590 goto cleanup;
591 }
592 if (tmp != sm_header.numKeywords) {
593 ALOGE("%s: smlib_getkeywordPhrases(%d) != sml header (%d)", __func__,
594 tmp, sm_header.numKeywords);
595 goto cleanup;
596 }
597 for (i = 0; i < sm_header.numKeywords; i++)
598 ALOGV("%s: keyphrases names = %s", __func__, sm_info->keyphrases[i]);
599
600 if (sm_header.numUsers) {
601 alloc_array_ptrs(&sm_info->users, sm_header.numUsers, MAX_STRING_LEN);
602 if (!sm_info->users) {
603 ALOGE("%s: users allocation failed", __func__);
604 status = -ENOMEM;
605 goto cleanup;
606 }
607
608 tmp = sm_header.numUsers;
609 sm_ret = stdev->smlib_getUserNames(&model, &tmp, sm_info->users);
610 if (sm_ret) {
611 ALOGE("%s: smlib_getUserNames failed, err %d ", __func__, sm_ret);
612 goto cleanup;
613 }
614 if (tmp != sm_header.numUsers) {
615 ALOGE("%s: smlib_getUserNames(%d) != sml header (%d)", __func__,
616 tmp, sm_header.numUsers);
617 status = -EINVAL;
618 goto cleanup;
619 }
620 for (i = 0; i < sm_header.numUsers; i++)
621 ALOGV("%s: users names = %s", __func__, sm_info->users[i]);
622 }
623
624 sm_info->cf_levels_size = sm_header.numKeywords +
625 sm_header.numActiveUserKeywordPairs;
626 alloc_array_ptrs(&sm_info->cf_levels_kw_users, sm_info->cf_levels_size,
627 MAX_KW_USERS_NAME_LEN);
628 if (!sm_info->cf_levels_kw_users) {
629 ALOGE("%s: cf_levels_kw_users allocation failed", __func__);
630 status = -ENOMEM;
631 goto cleanup;
632 }
633
634 /* Used later for mapping client to/from merged DSP confidence levels */
635 sm_info->cf_levels = calloc(1, 2 * sm_info->cf_levels_size);
636 if (!sm_info->cf_levels) {
637 ALOGE("%s: cf_levels allocation failed", __func__);
638 status = -ENOMEM;
639 goto cleanup;
640 }
641 /*
642 * Used for updating detection confidence level values from DSP merged
643 * detection conf levels
644 */
645 sm_info->det_cf_levels = sm_info->cf_levels + sm_info->cf_levels_size;
646
647 /*
648 * Used for conf level setting to DSP. Reset the conf value to max value,
649 * so that the keyword of a loaded and in-active model in a merged model
650 * doesn't detect.
651 */
652 memset(sm_info->cf_levels, MAX_CONF_LEVEL_VALUE, sm_info->cf_levels_size);
653
654 /*
655 * Derive the confidence level payload for keyword and user pairs.
656 * Store the user-keyword pair names in an array that will be used for
657 * mapping the DSP detection and confidence levels to the client.
658 */
659 char **kw_names = sm_info->cf_levels_kw_users;
660 char **ukw_names = &sm_info->cf_levels_kw_users[sm_header.numKeywords];
661 int ukw_idx = 0;
662
663 for (i = 0; i < sm_header.numKeywords; i++) {
664 strlcpy(kw_names[i], sm_info->keyphrases[i], MAX_KW_USERS_NAME_LEN);
665 if (!sm_header.numUsersSetPerKw)
666 continue;
667 for (j = 0, k = 0; j < sm_header.numUsers; j++) {
668 if (k >= sm_header.numUsersSetPerKw[i])
669 break;
670 if (sm_header.userKeywordPairFlags[j][i]) {
671 strlcpy(ukw_names[ukw_idx], sm_info->users[j],
672 MAX_KW_USERS_NAME_LEN);
673 strlcat(ukw_names[ukw_idx], sm_info->keyphrases[i],
674 MAX_KW_USERS_NAME_LEN);
675 ukw_idx++;
676 k++;
677 }
678 }
679 }
680 for (i = 0; i < sm_info->cf_levels_size; i++)
681 ALOGV("%s: cf_levels_kw_users = %s", __func__,
682 sm_info->cf_levels_kw_users[i]);
683
684 sm_ret = stdev->smlib_releaseSoundModelHeader(&sm_header);
685 if (sm_ret != kSucess) {
686 ALOGE("%s: smlib_releaseSoundModelHeader failed, err %d ", __func__,
687 sm_ret);
688 status = -EINVAL;
689 goto cleanup_1;
690 }
691 ALOGV("%s: exit", __func__);
692 return 0;
693
694cleanup:
695 sm_ret = stdev->smlib_releaseSoundModelHeader(&sm_header);
696 if (sm_ret != kSucess)
697 ALOGE("%s: smlib_releaseSoundModelHeader failed, err %d ", __func__,
698 sm_ret);
699
700cleanup_1:
701 release_sound_model_info(sm_info);
702
703 return status;
704}
705
706static int add_sound_model(st_session_t *stc_ses, unsigned char *sm_data,
707 unsigned int sm_size)
708{
709 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
710 struct listnode *node = NULL;
711 st_session_t *c_ses = NULL;
712 listen_model_type **in_models = NULL;
713 listen_model_type out_model = {0};
Quinn Male58749452020-03-26 17:14:56 -0700714 struct sound_model_info sm_info = {0};
715 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700716 int status = 0, num_models = 0;
717
718 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
719 if (stc_ses->sm_info.sm_data) {
720 ALOGD("%s:[c%d] Already added", __func__, stc_ses->sm_handle);
721 return 0;
722 }
Quinn Male58749452020-03-26 17:14:56 -0700723 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
724 stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700725 stc_ses->sm_info.sm_data = sm_data;
726 stc_ses->sm_info.sm_size = sm_size;
Quinn Male58749452020-03-26 17:14:56 -0700727 stc_ses->sm_info.sm_type = stc_ses->sm_type;
728 stc_ses->sm_info.model_id =
729 (stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) ?
730 stc_ses->sm_handle : 0;
731
732 p_info = calloc(1, sizeof(struct st_proxy_ses_sm_info_wrapper));
733 if (!p_info) {
734 ALOGE("%s: failed to alloc struct st_proxy_ses_sm_info_wrapper",
735 __func__);
736 return -ENOMEM;
737 }
738
739 memcpy((uint8_t *)&p_info->sm_info, (uint8_t *)&stc_ses->sm_info,
740 sizeof(struct sound_model_info));
741
742 if (stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
743 st_ses->recognition_mode |= stc_ses->recognition_mode;
744 p_info->sm_info.cf_levels = calloc(1, 2 * MAX_MULTI_SM_CONF_LEVELS);
745 if (!p_info->sm_info.cf_levels) {
746 ALOGE("%s: failed to alloc cf_levels",
747 __func__);
748 free(p_info);
749 return -ENOMEM;
750 }
751 memset(p_info->sm_info.cf_levels, MAX_CONF_LEVEL_VALUE,
752 MAX_MULTI_SM_CONF_LEVELS);
753 p_info->sm_info.det_cf_levels = p_info->sm_info.cf_levels +
754 MAX_MULTI_SM_CONF_LEVELS;
755 memset(p_info->sm_info.det_cf_levels, 0,
756 MAX_MULTI_SM_CONF_LEVELS);
757 stc_ses->sm_info.cf_levels = p_info->sm_info.cf_levels;
758 stc_ses->sm_info.det_cf_levels = p_info->sm_info.det_cf_levels;
759 }
760 list_add_tail(&st_ses->sm_info_list, &p_info->sm_list_node);
761 if (stc_ses->f_stage_version == ST_MODULE_TYPE_GMM)
762 ALOGD("%s:[c%d] no merge", __func__, stc_ses->sm_handle);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700763 return 0;
764 }
765 /* get sound model header information for client model */
766 status = query_sound_model(st_ses->stdev, &stc_ses->sm_info,
767 sm_data, sm_size);
768 if (status)
769 return status;
770
771 stc_ses->sm_info.sm_data = sm_data;
772 stc_ses->sm_info.sm_size = sm_size;
Zhou Songdeddfcc2019-06-18 22:25:03 +0800773 ALOGV("%s: stc_ses %pK - sm_data %pK, sm_size %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700774 stc_ses, stc_ses->sm_info.sm_data,
775 stc_ses->sm_info.sm_size);
776
777 /* Check for remaining client sound models to merge */
778 list_for_each(node, &st_ses->clients_list) {
779 c_ses = node_to_item(node, st_session_t, hw_list_node);
780 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data)
781 num_models++;
782 }
783 if (!num_models) {
Quinn Male58749452020-03-26 17:14:56 -0700784 p_info = calloc(1, sizeof(struct st_proxy_ses_sm_info_wrapper));
785 if (!p_info) {
786 ALOGE("%s: failed to alloc struct st_proxy_ses_sm_info_wrapper",
787 __func__);
788 return -ENOMEM;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700789 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700790 st_ses->recognition_mode = stc_ses->recognition_mode;
791 stc_ses->sm_info.sm_type = stc_ses->sm_type;
Quinn Male58749452020-03-26 17:14:56 -0700792 stc_ses->sm_info.model_id = 0;
793 memcpy((uint8_t *)&p_info->sm_info, (uint8_t *)&stc_ses->sm_info,
794 sizeof(struct sound_model_info));
795 st_ses->sm_merged = false;
796 list_add_tail(&st_ses->sm_info_list, &p_info->sm_list_node);
797 ALOGD("%s: Copy from single client c%d model, size %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700798 stc_ses->sm_handle, stc_ses->sm_info.sm_size);
799 return 0;
800 }
801 ALOGV("%s: num existing models %d", __func__, num_models);
802 /*
803 * Merge this client model with already existing merged model due to other
804 * clients models.
805 */
Quinn Male58749452020-03-26 17:14:56 -0700806 p_info = get_sm_info_for_model_id(st_ses, 0);
807 if (!p_info) {
808 ALOGE("%s: Unexpected, no matching model_id in sm_info list,"
809 "num current models %d", __func__, num_models);
810 status = -EINVAL;
811 goto cleanup;
812 }
813
814 if (!p_info->sm_info.sm_data) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700815 if (num_models == 1) {
816 /*
Quinn Male58749452020-03-26 17:14:56 -0700817 * Its not a merged model yet, but proxy ses sm_data is valid
818 * and must be pointing to client sm_data
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700819 */
Quinn Male58749452020-03-26 17:14:56 -0700820 ALOGE("%s: Unexpected, sm_data NULL, num current"
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700821 "models %d", __func__, num_models);
822 status = -EINVAL;
823 goto cleanup;
Quinn Male58749452020-03-26 17:14:56 -0700824 } else if (!st_ses->sm_merged) {
825 ALOGE("%s: Unexpected, no pre-existing merged model,"
826 "num current models %d", __func__, num_models);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700827 status = -EINVAL;
828 goto cleanup;
829 }
830 }
831
832 /* Merge this client model with remaining clients models */
833 num_models = 2;/* re-use */
834 alloc_array_ptrs((char***)&in_models, num_models, sizeof(listen_model_type));
835 if (!in_models) {
836 ALOGE("%s: in_models allocation failed", __func__);
837 status = -ENOMEM;
838 goto cleanup;
839 }
840 /* Add existing model */
Quinn Male58749452020-03-26 17:14:56 -0700841 in_models[0]->data = p_info->sm_info.sm_data;
842 in_models[0]->size = p_info->sm_info.sm_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700843 /* Add this client model */
844 in_models[1]->data = sm_data;
845 in_models[1]->size = sm_size;
846
847 status = merge_sound_models(st_ses->stdev, 2, in_models, &out_model);
848 if (status)
849 goto cleanup;
850
851 sm_info.sm_data = out_model.data;
852 sm_info.sm_size = out_model.size;
Quinn Male58749452020-03-26 17:14:56 -0700853 sm_info.model_id = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700854
855 status = query_sound_model(st_ses->stdev, &sm_info,
856 out_model.data, out_model.size);
857 if (status)
858 goto cleanup;
859
Quinn Male58749452020-03-26 17:14:56 -0700860 if (out_model.size < p_info->sm_info.sm_size) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700861 ALOGE("%s: Unexpected, merged model sz %d < current sz %d",
Quinn Male58749452020-03-26 17:14:56 -0700862 __func__, out_model.size, p_info->sm_info.sm_size);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700863 release_sound_model_info(&sm_info);
864 status = -EINVAL;
865 goto cleanup;
866 }
867 free_array_ptrs((char **)in_models, num_models);
868 in_models = NULL;
869
870 /* Update the new merged model */
Quinn Male58749452020-03-26 17:14:56 -0700871 if (st_ses->sm_merged && p_info->sm_info.sm_data) {
872 release_sound_model_info(&p_info->sm_info);
873 free(p_info->sm_info.sm_data);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700874 }
875 ALOGD("%s: Updated sound model: current size %d, new size %d", __func__,
Quinn Male58749452020-03-26 17:14:56 -0700876 p_info->sm_info.sm_size, out_model.size);
877 memcpy((uint8_t *)&p_info->sm_info, (uint8_t *)&sm_info,
878 sizeof(struct sound_model_info));
879 st_ses->sm_merged = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700880
881 /*
882 * If any of the clients has user identificaiton enabled, underlying
883 * hw session has to operate with user identification enabled.
884 */
885 if (stc_ses->recognition_mode & RECOGNITION_MODE_USER_IDENTIFICATION)
886 st_ses->recognition_mode |= stc_ses->recognition_mode;
887
888 return 0;
889
890cleanup:
891 release_sound_model_info(&stc_ses->sm_info);
892 stc_ses->sm_info.sm_data = NULL;
893
894 if (out_model.data)
895 free(out_model.data);
896
897 if (in_models)
898 free_array_ptrs((char **)in_models, num_models);
899
900 return status;
901}
902
903static int delete_sound_model(st_session_t *stc_ses)
904{
905 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
906 struct listnode *node = NULL;
907 st_session_t *c_ses = NULL, *c_ses_rem = NULL;
908 listen_model_type in_model = {0};
909 listen_model_type out_model = {0};
910 struct sound_model_info sm_info = {0};
Quinn Male58749452020-03-26 17:14:56 -0700911 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
912 struct st_hw_ses_config *sthw_cfg = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700913 int status = 0, num_models = 0;
914 unsigned int rec_mode = RECOGNITION_MODE_VOICE_TRIGGER;
915
916 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
917 if (!stc_ses->sm_info.sm_data) {
918 ALOGD("%s:[c%d] Already deleted", __func__, stc_ses->sm_handle);
919 return 0;
920 }
Quinn Male58749452020-03-26 17:14:56 -0700921
922 p_info = get_sm_info_for_model_id(st_ses, stc_ses->sm_info.model_id);
923 if (!p_info) {
924 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
925 return -EINVAL;
926 }
927
928 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
929 stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
930 list_remove(&p_info->sm_list_node);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700931 /*
Quinn Male58749452020-03-26 17:14:56 -0700932 * As it directly points to client model, just set sm_data
933 * as NULL without freeing
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700934 */
Quinn Male58749452020-03-26 17:14:56 -0700935 if (stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
936 /* Update overall recogniton mode from remaining clients */
937 list_for_each(node, &st_ses->clients_list) {
938 c_ses = node_to_item(node, st_session_t, hw_list_node);
939 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data) {
940 if (c_ses->recognition_mode &
941 RECOGNITION_MODE_USER_IDENTIFICATION)
942 rec_mode |= RECOGNITION_MODE_USER_IDENTIFICATION;
943 }
944 }
945 st_ses->recognition_mode = rec_mode;
946
947 if (p_info->sm_info.cf_levels) {
948 free(p_info->sm_info.cf_levels);
949 p_info->sm_info.cf_levels = NULL;
950 }
951 }
952 p_info->sm_info.sm_data = NULL;
953 free(p_info);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700954 stc_ses->sm_info.sm_data = NULL;
Quinn Male58749452020-03-26 17:14:56 -0700955 if (stc_ses->f_stage_version == ST_MODULE_TYPE_GMM)
956 ALOGD("%s:[c%d] no merge", __func__, stc_ses->sm_handle);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700957 return 0;
958 }
959
Zhou Songdeddfcc2019-06-18 22:25:03 +0800960 ALOGV("%s: stc_ses %pK - sm_data %pK, sm_size %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700961 stc_ses, stc_ses->sm_info.sm_data,
962 stc_ses->sm_info.sm_size);
963
964 /* Check for remaining clients sound models to merge */
965 list_for_each(node, &st_ses->clients_list) {
966 c_ses = node_to_item(node, st_session_t, hw_list_node);
967 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data) {
968 c_ses_rem = c_ses;
969 num_models++;
970 }
971 }
Quinn Male58749452020-03-26 17:14:56 -0700972
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700973 if (num_models == 0) {
974 ALOGD("%s: No remaining models", __func__);
975 /* Delete current client model */
Quinn Male58749452020-03-26 17:14:56 -0700976 release_sound_model_info(&p_info->sm_info);
977 list_remove(&p_info->sm_list_node);
978 p_info->sm_info.sm_data = NULL;
979 free(p_info);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700980 stc_ses->sm_info.sm_data = NULL;
981 return 0;
982 }
983
984 if (num_models == 1) {
985 ALOGD("%s: reuse only remaining client model, size %d", __func__,
986 c_ses_rem->sm_info.sm_size);
987 /* If only one remaining client model exists, re-use it */
Quinn Male58749452020-03-26 17:14:56 -0700988 if (st_ses->sm_merged) {
989 release_sound_model_info(&p_info->sm_info);
990 if (p_info->sm_info.sm_data)
991 free(p_info->sm_info.sm_data);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700992 }
Quinn Male58749452020-03-26 17:14:56 -0700993 memcpy((uint8_t *)&p_info->sm_info, (uint8_t *)&c_ses_rem->sm_info,
994 sizeof(struct sound_model_info));
995 st_ses->sm_merged = false;
996
997 sthw_cfg = get_sthw_cfg_for_model_id(st_ses->hw_ses_current, 0);
998 if (!sthw_cfg) {
999 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
1000 return -EINVAL;
1001 }
1002
1003 sthw_cfg->conf_levels = p_info->sm_info.cf_levels;
1004 sthw_cfg->num_conf_levels =
1005 p_info->sm_info.cf_levels_size;
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -07001006 st_ses->recognition_mode = c_ses_rem->recognition_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001007 /* Delete current client model */
1008 release_sound_model_info(&stc_ses->sm_info);
1009 stc_ses->sm_info.sm_data = NULL;
1010 return 0;
1011 }
1012 /* Update overall recogniton mode from remaining clients */
1013 list_for_each(node, &st_ses->clients_list) {
1014 c_ses = node_to_item(node, st_session_t, hw_list_node);
1015 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data) {
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -07001016 if (c_ses->recognition_mode & RECOGNITION_MODE_USER_IDENTIFICATION)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001017 rec_mode |= RECOGNITION_MODE_USER_IDENTIFICATION;
1018 }
1019 }
1020
1021 /*
1022 * Delete this client model with already existing merged model due to other
1023 * clients models.
1024 */
Quinn Male58749452020-03-26 17:14:56 -07001025 if (!st_ses->sm_merged || !p_info->sm_info.sm_data) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001026 ALOGE("%s: Unexpected, no pre-existing merged model to delete from,"
1027 "num current models %d", __func__, num_models);
1028 goto cleanup;
1029 }
1030
1031 /* Existing merged model from which the current client model to be deleted */
Quinn Male58749452020-03-26 17:14:56 -07001032 in_model.data = p_info->sm_info.sm_data;
1033 in_model.size = p_info->sm_info.sm_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001034
1035 status = delete_from_merged_sound_model(st_ses->stdev,
1036 stc_ses->sm_info.keyphrases, stc_ses->sm_info.num_keyphrases,
1037 &in_model, &out_model);
1038
1039 if (status)
1040 goto cleanup;
1041
1042 sm_info.sm_data = out_model.data;
1043 sm_info.sm_size = out_model.size;
Quinn Male58749452020-03-26 17:14:56 -07001044 sm_info.model_id = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001045
1046 /* Update existing merged model info with new merged model */
1047 status = query_sound_model(st_ses->stdev, &sm_info, out_model.data,
1048 out_model.size);
1049 if (status)
1050 goto cleanup;
1051
Quinn Male58749452020-03-26 17:14:56 -07001052 if (out_model.size > p_info->sm_info.sm_size) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001053 ALOGE("%s: Unexpected, merged model sz %d > current sz %d",
Quinn Male58749452020-03-26 17:14:56 -07001054 __func__, out_model.size, p_info->sm_info.sm_size);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001055 release_sound_model_info(&sm_info);
1056 status = -EINVAL;
1057 goto cleanup;
1058 }
1059
Quinn Male58749452020-03-26 17:14:56 -07001060 if (st_ses->sm_merged && p_info->sm_info.sm_data) {
1061 release_sound_model_info(&p_info->sm_info);
1062 free(p_info->sm_info.sm_data);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001063 }
1064
1065 ALOGD("%s: Updated sound model: current size %d, new size %d", __func__,
Quinn Male58749452020-03-26 17:14:56 -07001066 p_info->sm_info.sm_size, out_model.size);
1067 memcpy((uint8_t *)&p_info->sm_info, (uint8_t *)&sm_info,
1068 sizeof(struct sound_model_info));
1069 st_ses->sm_merged = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001070 /*
1071 * If any of the remaining clients has user identificaiton enabled,
1072 * underlying hw session has to operate with user identificaiton enabled.
1073 */
1074 st_ses->recognition_mode = rec_mode;
1075
1076 /* Release current client model */
1077 release_sound_model_info(&stc_ses->sm_info);
1078 stc_ses->sm_info.sm_data = NULL;
1079
1080 return 0;
1081
1082cleanup:
1083 release_sound_model_info(&stc_ses->sm_info);
1084 stc_ses->sm_info.sm_data = NULL;
1085
1086 if (out_model.data)
1087 free(out_model.data);
1088
1089 return status;
1090}
1091
1092static int update_sound_model(st_session_t *stc_ses, bool add)
1093{
1094 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
1095 struct sound_trigger_phrase_sound_model *phrase_sm = stc_ses->phrase_sm;
1096 struct sound_trigger_sound_model *common_sm =
1097 (struct sound_trigger_sound_model*)stc_ses->phrase_sm;
1098 unsigned char *sm_data = NULL;
1099 unsigned int sm_size = 0;
1100 int status = 0;
1101
1102 ALOGV("%s: Enter", __func__);
1103
1104 if (stc_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
1105 sm_data = (unsigned char*)phrase_sm + phrase_sm->common.data_offset;
1106 sm_size = phrase_sm->common.data_size;
1107 } else {
1108 sm_data = (unsigned char*)common_sm + common_sm->data_offset;
1109 sm_size = common_sm->data_size;
1110 }
1111
1112 pthread_mutex_lock(&st_ses->lock);
1113 if (add)
1114 status = add_sound_model(stc_ses, sm_data, sm_size);
1115 else
1116 status = delete_sound_model(stc_ses);
1117 pthread_mutex_unlock(&st_ses->lock);
1118
1119 ALOGV("%s: Exit", __func__);
1120 return status;
1121}
1122
1123static int update_merge_conf_levels_payload(st_proxy_session_t *st_ses,
1124 struct sound_model_info *src_sm_info, unsigned char *src,
1125 unsigned int src_size, bool set)
1126{
1127 int i = 0, j = 0;
Quinn Male58749452020-03-26 17:14:56 -07001128 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001129
1130 if (!st_ses || !src) {
1131 ALOGE("%s: NULL pointer", __func__);
1132 return -EINVAL;
1133 }
1134
Quinn Male58749452020-03-26 17:14:56 -07001135 if (!st_ses->sm_merged)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001136 return 0;
1137
Quinn Male58749452020-03-26 17:14:56 -07001138 p_info = get_sm_info_for_model_id(st_ses, 0);
1139 if (!p_info) {
1140 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
1141 return -EINVAL;
1142 }
1143
1144 if (src_size > p_info->sm_info.cf_levels_size) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001145 ALOGE("%s:[%d] Unexpected, client conf levels %d > "
1146 "merged conf levels %d", __func__, st_ses->sm_handle,
Quinn Male58749452020-03-26 17:14:56 -07001147 src_size, p_info->sm_info.cf_levels_size);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001148 return -EINVAL;
1149 }
1150
1151 for (i = 0; i < src_size; i++)
1152 ALOGV("%s: src cf_levels[%d]=%d", __func__, i, src[i]);
1153
1154 /* Populate DSP merged sound model conf levels */
1155 for (i = 0; i < src_size; i++) {
Quinn Male58749452020-03-26 17:14:56 -07001156 for (j = 0; j < p_info->sm_info.cf_levels_size; j++) {
1157 if (!strcmp(p_info->sm_info.cf_levels_kw_users[j],
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001158 src_sm_info->cf_levels_kw_users[i])) {
1159 if (set) {
Quinn Male58749452020-03-26 17:14:56 -07001160 p_info->sm_info.cf_levels[j] = src[i];
1161 ALOGV("%s: set: cf_levels[%d]=%d", __func__,
1162 j, p_info->sm_info.cf_levels[j]);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001163 } else {
Quinn Male58749452020-03-26 17:14:56 -07001164 p_info->sm_info.cf_levels[j] = MAX_CONF_LEVEL_VALUE;
1165 ALOGV("%s: reset: cf_levels[%d]=%d", __func__,
1166 j, p_info->sm_info.cf_levels[j]);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001167 }
1168 }
1169 }
1170 }
1171 return 0;
1172}
1173
1174static int update_merge_conf_levels_payload_with_active_clients(
1175 st_proxy_session_t *st_ses)
1176{
1177 int status = 0;
1178 struct listnode *node = NULL;
1179 st_session_t *c_ses = NULL;
1180
1181 list_for_each(node, &st_ses->clients_list) {
1182 c_ses = node_to_item(node, st_session_t, hw_list_node);
1183 if (c_ses->state == ST_STATE_ACTIVE) {
1184 ALOGV("%s: update merge conf levels with other active"
1185 "client %d ", __func__, c_ses->sm_handle);
1186 status = update_merge_conf_levels_payload(st_ses,
1187 &c_ses->sm_info, c_ses->sm_info.cf_levels,
1188 c_ses->sm_info.cf_levels_size, true);
1189 if (status)
1190 return status;
1191 }
1192 }
1193 return status;
1194}
1195
1196static void check_and_extract_det_conf_levels_payload(
1197 st_proxy_session_t *st_ses,
1198 unsigned char *src, unsigned int src_size,
1199 unsigned char **dst, unsigned int *dst_size)
1200{
1201 st_session_t *stc_ses = st_ses->det_stc_ses;
Quinn Male58749452020-03-26 17:14:56 -07001202 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001203 int i = 0, j = 0;
1204
1205 *dst = src;
1206 *dst_size = src_size;
1207
1208 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
Quinn Male58749452020-03-26 17:14:56 -07001209 !st_ses->sm_merged ||
1210 stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001211 ALOGV("%s:[%d] not merged", __func__, st_ses->sm_handle);
1212 return;
1213 }
1214
Quinn Male58749452020-03-26 17:14:56 -07001215 p_info = get_sm_info_for_model_id(st_ses, 0);
1216 if (!p_info) {
1217 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
1218 return;
1219 }
1220
1221 if (src_size < p_info->sm_info.cf_levels_size) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001222 ALOGE("%s:[%d] Unexpected, detection conf payload size %d < %d",
1223 __func__, st_ses->sm_handle, src_size,
Quinn Male58749452020-03-26 17:14:56 -07001224 p_info->sm_info.cf_levels_size);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001225 return;
1226 }
1227
1228 /* Reset any cached previous detection values */
1229 memset(stc_ses->sm_info.det_cf_levels, 0, stc_ses->sm_info.cf_levels_size);
1230
1231 /* Extract the client conf level values from DSP payload */
Quinn Male58749452020-03-26 17:14:56 -07001232 for(i = 0; i < p_info->sm_info.cf_levels_size; i++) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001233 if (!src[i])
1234 continue;
1235 for(j = 0; j < stc_ses->sm_info.cf_levels_size; j++) {
1236 if (!strcmp(stc_ses->sm_info.cf_levels_kw_users[j],
Quinn Male58749452020-03-26 17:14:56 -07001237 p_info->sm_info.cf_levels_kw_users[i])) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001238 stc_ses->sm_info.det_cf_levels[j] = src[i];
1239 }
1240 }
1241 }
1242 for (i = 0; i < stc_ses->sm_info.cf_levels_size; i++)
1243 ALOGD("%s: c%d det_cf_levels[%d]=%d", __func__, stc_ses->sm_handle, i,
1244 stc_ses->sm_info.det_cf_levels[i]);
1245
1246 *dst = stc_ses->sm_info.det_cf_levels;
1247 *dst_size = stc_ses->sm_info.cf_levels_size;
1248}
1249
1250static inline bool check_for_multi_clients(st_proxy_session_t *st_ses)
1251{
1252 struct listnode *node = NULL;
1253 int cnt = 0;
1254
1255 list_for_each(node, &st_ses->clients_list) {
1256 if (++cnt > 1)
1257 return true;
1258 }
1259 return false;
1260}
1261
1262static inline bool is_other_client_attached(st_proxy_session_t *st_ses,
1263 st_session_t *stc_ses)
1264{
1265 struct listnode *node = NULL;
1266 st_session_t *c_ses = NULL;
1267
1268 list_for_each(node, &st_ses->clients_list) {
1269 c_ses = node_to_item(node, st_session_t, hw_list_node);
1270 if (c_ses != stc_ses)
1271 return true;
1272 }
1273 return false;
1274}
1275
1276static inline void reset_clients_pending_load(st_proxy_session_t *st_ses)
1277{
1278 struct listnode *node = NULL;
1279 st_session_t *c_ses = NULL;
1280
1281 list_for_each(node, &st_ses->clients_list) {
1282 c_ses = node_to_item(node, st_session_t, hw_list_node);
1283 c_ses->pending_load = false;
1284 }
1285}
1286
1287static inline int is_any_client_not_pending_load(st_proxy_session_t *st_ses)
1288{
1289 struct listnode *node = NULL;
1290 st_session_t *c_ses = NULL;
1291
1292 list_for_each(node, &st_ses->clients_list) {
1293 c_ses = node_to_item(node, st_session_t, hw_list_node);
1294 if (!c_ses->pending_load)
1295 return true;
1296 }
1297 return false;
1298}
1299
1300static inline int is_any_client_not_pending_set_device(
1301 st_proxy_session_t *st_ses)
1302{
1303 struct listnode *node = NULL;
1304 st_session_t *c_ses = NULL;
1305
1306 list_for_each(node, &st_ses->clients_list) {
1307 c_ses = node_to_item(node, st_session_t, hw_list_node);
1308 if (!c_ses->pending_set_device)
1309 return true;
1310 }
1311 return false;
1312}
1313
1314static inline void reset_clients_pending_set_device(st_proxy_session_t *st_ses)
1315{
1316 struct listnode *node = NULL;
1317 st_session_t *c_ses = NULL;
1318
1319 list_for_each(node, &st_ses->clients_list) {
1320 c_ses = node_to_item(node, st_session_t, hw_list_node);
1321 c_ses->pending_set_device = false;
1322 }
1323}
1324
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001325static inline bool is_any_client_paused(st_proxy_session_t *st_ses)
1326{
1327 struct listnode *node = NULL;
1328 st_session_t *c_ses = NULL;
1329
1330 list_for_each(node, &st_ses->clients_list) {
1331 c_ses = node_to_item(node, st_session_t, hw_list_node);
1332 if (c_ses->paused)
1333 return true;
1334 }
1335 return false;
1336}
1337
1338static inline bool is_any_client_in_state(st_proxy_session_t *st_ses,
1339 enum client_states_t state)
1340{
1341 struct listnode *node = NULL;
1342 st_session_t *c_ses = NULL;
1343
1344 list_for_each(node, &st_ses->clients_list) {
1345 c_ses = node_to_item(node, st_session_t, hw_list_node);
1346 if (c_ses->state == state)
1347 return true;
1348 }
1349 return false;
1350}
1351
1352static void update_hw_config_on_restart(st_proxy_session_t *st_ses,
1353 st_session_t *stc_ses)
1354{
1355 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male58749452020-03-26 17:14:56 -07001356 struct st_hw_ses_config *sthw_cfg = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001357 struct listnode *node = NULL;
1358 st_session_t *c_ses = NULL;
1359 int hb_sz = 0, pr_sz = 0;
1360 bool enable_lab = false;
1361
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001362 /*
1363 * Adjust history buffer and preroll durations to highest of
1364 * all clients, including current restarting client.
1365 * If any of the clients requested capture or enabled the
1366 * second stage, the underlying hw session buffering needs to be
1367 * enabled.
1368 */
1369 list_for_each(node, &st_ses->clients_list) {
1370 c_ses = node_to_item(node, st_session_t, hw_list_node);
1371 if ((c_ses == stc_ses) || (c_ses->state == ST_STATE_ACTIVE)) {
1372 if (hb_sz < c_ses->hist_buf_duration)
1373 hb_sz = c_ses->hist_buf_duration;
1374 if (pr_sz < c_ses->preroll_duration)
1375 pr_sz = c_ses->preroll_duration;
1376 if (!enable_lab)
1377 enable_lab = (c_ses->rc_config &&
1378 c_ses->rc_config->capture_requested) ||
1379 !list_empty(&c_ses->second_stage_list);
1380 }
1381 }
1382
Quinn Male58749452020-03-26 17:14:56 -07001383 sthw_cfg = get_sthw_cfg_for_model_id(hw_ses, stc_ses->sm_info.model_id);
1384 if (!sthw_cfg) {
1385 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
1386 return;
1387 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001388
Quinn Male58749452020-03-26 17:14:56 -07001389 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
1390 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
1391 !st_ses->sm_merged)
1392 return;
1393
1394 sthw_cfg->client_req_hist_buf = hb_sz;
1395 hw_ses->max_hist_buf = hb_sz;
1396 sthw_cfg->client_req_preroll = pr_sz;
1397 hw_ses->max_preroll = pr_sz;
1398 st_ses->lab_enabled = enable_lab;
1399
1400 update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
1401 stc_ses->sm_info.cf_levels,
1402 stc_ses->sm_info.cf_levels_size,
1403 true);
1404 } else {
1405 sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
1406 hw_ses->max_hist_buf = hb_sz;
1407 sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
1408 hw_ses->max_preroll = pr_sz;
1409 st_ses->lab_enabled = enable_lab;
1410
1411 /*
1412 * During stop, the conf levels get set to the max value
1413 * to prevent detections while its client state is loaded
1414 * and another sound model's client state is active. So
1415 * during restart, the conf levels need to be reset from
1416 * the cached stc_values to enable detections again.
1417 */
1418 memset(sthw_cfg->conf_levels, MAX_CONF_LEVEL_VALUE,
1419 MAX_MULTI_SM_CONF_LEVELS);
1420 memcpy(sthw_cfg->conf_levels, stc_ses->sm_info.cf_levels,
1421 stc_ses->sm_info.cf_levels_size);
1422 sthw_cfg->num_conf_levels = stc_ses->sm_info.cf_levels_size;
1423 }
1424
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001425 hw_ses->sthw_cfg_updated = true;
1426
1427 ALOGV("%s:[%d] lab_enabled %d, hb_sz %d, pr_sz %d", __func__,
1428 st_ses->sm_handle, st_ses->lab_enabled,
1429 sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
1430}
1431
1432static bool update_hw_config_on_stop(st_proxy_session_t *st_ses,
1433 st_session_t *stc_ses)
1434{
1435 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male58749452020-03-26 17:14:56 -07001436 struct st_hw_ses_config *sthw_cfg = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001437 struct listnode *node = NULL;
1438 st_session_t *c_ses = NULL;
1439 int hb_sz = 0, pr_sz = 0;
1440 bool active = false, enable_lab = false;
1441
Quinn Male58749452020-03-26 17:14:56 -07001442 sthw_cfg = get_sthw_cfg_for_model_id(hw_ses, stc_ses->sm_info.model_id);
1443 if (!sthw_cfg) {
1444 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
1445 return false;
1446 }
1447
1448 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels &&
1449 stc_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
1450
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001451 if (sthw_cfg->conf_levels) {
1452 ALOGV("%s: free hw conf_levels", __func__);
1453 free(sthw_cfg->conf_levels);
1454 sthw_cfg->conf_levels = NULL;
1455 }
1456 return false;
1457 }
1458 /*
1459 * Adjust history buffer and preroll durations to highest of
1460 * remaining clients.
1461 * If any of the remaining clients requested capture or enabled the
1462 * second stage, the underlying hw session buffering needs to be
1463 * enabled.
1464 */
1465 list_for_each(node, &st_ses->clients_list) {
1466 c_ses = node_to_item(node, st_session_t, hw_list_node);
1467 if ((c_ses != stc_ses) && (c_ses->state == ST_STATE_ACTIVE)) {
1468 active = true;
1469 if (hb_sz < c_ses->hist_buf_duration)
1470 hb_sz = c_ses->hist_buf_duration;
1471 if (pr_sz < c_ses->preroll_duration)
1472 pr_sz = c_ses->preroll_duration;
1473 if (!enable_lab)
1474 enable_lab = c_ses->rc_config->capture_requested ||
1475 !list_empty(&c_ses->second_stage_list);
1476 }
1477 }
Quinn Male58749452020-03-26 17:14:56 -07001478
1479 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
1480 if (!active) {
1481 sthw_cfg->client_req_hist_buf = 0;
1482 hw_ses->max_hist_buf = 0;
1483 sthw_cfg->client_req_preroll = 0;
1484 hw_ses->max_preroll = 0;
1485 st_ses->lab_enabled = false;
1486 hw_ses->custom_data = NULL;
1487 hw_ses->custom_data_size = 0;
1488 hw_ses->sthw_cfg_updated = true;
1489 ALOGV("%s:[%d] no active client hw cfg is reset", __func__,
1490 st_ses->sm_handle);
1491 return false;
1492 }
1493
1494 sthw_cfg->client_req_hist_buf = hb_sz;
1495 hw_ses->max_hist_buf = hb_sz;
1496 sthw_cfg->client_req_preroll = pr_sz;
1497 hw_ses->max_preroll = pr_sz;
1498 st_ses->lab_enabled = enable_lab;
1499
1500 update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
1501 stc_ses->sm_info.cf_levels,
1502 stc_ses->sm_info.cf_levels_size,
1503 false);
1504 } else {
1505 if (!active) {
1506 hw_ses->max_hist_buf = 0;
1507 hw_ses->max_preroll = 0;
1508 st_ses->lab_enabled = false;
1509 hw_ses->custom_data = NULL;
1510 hw_ses->custom_data_size = 0;
1511 hw_ses->sthw_cfg_updated = true;
1512 return false;
1513 }
1514
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001515 sthw_cfg->client_req_hist_buf = 0;
Quinn Male58749452020-03-26 17:14:56 -07001516 hw_ses->max_hist_buf = hb_sz;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001517 sthw_cfg->client_req_preroll = 0;
Quinn Male58749452020-03-26 17:14:56 -07001518 hw_ses->max_preroll = pr_sz;
1519 st_ses->lab_enabled = enable_lab;
1520
1521 memset(sthw_cfg->conf_levels, MAX_CONF_LEVEL_VALUE,
1522 MAX_MULTI_SM_CONF_LEVELS);
1523 sthw_cfg->num_conf_levels = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001524 }
1525
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001526 hw_ses->sthw_cfg_updated = true;
1527
1528 ALOGV("%s:[%d] lab_enabled %d, hb_sz %d, pr_sz %d", __func__,
1529 st_ses->sm_handle, st_ses->lab_enabled,
1530 sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
1531
1532 return active;
1533}
1534
1535static void get_conf_levels_from_dsp_payload(st_proxy_session_t *st_ses,
1536 unsigned char *payload, unsigned int payload_size,
1537 unsigned char **conf_levels, unsigned int *conf_levels_size)
1538{
1539 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
1540 uint32_t key_id = 0, key_payload_size = 0;
1541 unsigned int i = 0;
1542
1543 if (hw_ses->is_generic_event) {
1544 while (i < payload_size) {
1545 key_id = *(uint32_t *)payload;
1546 key_payload_size = *((uint32_t *)payload + 1);
1547
1548 if (key_id == KEY_ID_CONFIDENCE_LEVELS) {
1549 *conf_levels = payload + (4 * sizeof(uint32_t));
1550 *conf_levels_size = *((uint32_t *)payload + 3);;
1551 ALOGV("%s: generic_event: DSP num conf levels %d", __func__,
1552 *conf_levels_size);
1553 break;
1554 }
1555 i += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Quinn Male58749452020-03-26 17:14:56 -07001556 payload += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001557 }
1558 } else {
Quinn Male9a345522020-03-12 17:49:25 -07001559 if (st_ses->exec_mode == ST_EXEC_MODE_CPE) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001560 *conf_levels = payload + 2;
1561 *conf_levels_size = payload_size - 2;
1562 } else {
1563 *conf_levels = payload;
1564 *conf_levels_size = payload_size;
1565 }
1566 }
1567}
1568
1569st_session_t* get_detected_client(st_proxy_session_t *st_ses,
1570 unsigned char *payload, unsigned int payload_size)
1571{
1572 struct listnode *node = NULL;
1573 st_session_t *c_ses = NULL;
1574 unsigned char *conf_levels = NULL;
Quinn Male58749452020-03-26 17:14:56 -07001575 unsigned int conf_levels_size = 0, key_id = 0, key_payload_size = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001576 int i = 0, j = 0;
Quinn Male58749452020-03-26 17:14:56 -07001577 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
1578 multi_model_result_info_t *result_info = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001579
Quinn Male58749452020-03-26 17:14:56 -07001580 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
1581 p_info = get_sm_info_for_model_id(st_ses, 0);
1582 if (!p_info) {
1583 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001584 return NULL;
1585 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001586
Quinn Male58749452020-03-26 17:14:56 -07001587 if (list_empty(&st_ses->clients_list)) {
1588 ALOGE("%s:[%d] no clients attached!!", __func__,
1589 st_ses->sm_handle);
1590 return NULL;
1591 }
1592 /*
1593 * If only single client exist, this detection is not for merged
1594 * sound model, hence return this as only available client
1595 */
1596 if (!check_for_multi_clients(st_ses)) {
1597 ALOGV("%s:[%d] single client detection", __func__,
1598 st_ses->sm_handle);
1599 node = list_head(&st_ses->clients_list);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001600 c_ses = node_to_item(node, st_session_t, hw_list_node);
Quinn Male58749452020-03-26 17:14:56 -07001601 if (c_ses->state == ST_STATE_ACTIVE) {
1602 ALOGD("%s: detected c%d", __func__, c_ses->sm_handle);
1603 return c_ses;
1604 } else {
1605 ALOGE("%s: detected c%d is not active", __func__,
1606 c_ses->sm_handle);
1607 return NULL;
1608 }
1609 }
1610
1611 get_conf_levels_from_dsp_payload(st_ses, payload, payload_size,
1612 &conf_levels, &conf_levels_size);
1613 if (!conf_levels) {
1614 ALOGE("%s:[%d] no conf levels payload found!!", __func__,
1615 st_ses->sm_handle);
1616 return NULL;
1617 }
1618 if (conf_levels_size < p_info->sm_info.num_keyphrases) {
1619 ALOGE("%s:[%d] detection conf levels size %d < num of keywords %d",
1620 __func__, st_ses->sm_handle, conf_levels_size,
1621 p_info->sm_info.num_keyphrases);
1622 return NULL;
1623 }
1624
1625 /*
1626 * The DSP payload contains the keyword conf levels from the beginning.
1627 * Only one keyword conf level is expected to be non-zero from keyword
1628 * detection. Find non-zero conf level up to number of keyphrases and
1629 * if one is found, match it to the corresponding keyphrase from list
1630 * of clients to obtain the detected client.
1631 */
1632 for (i = 0; i < p_info->sm_info.num_keyphrases; i++) {
1633 if (!conf_levels[i])
1634 continue;
1635 list_for_each(node, &st_ses->clients_list) {
1636 c_ses = node_to_item(node, st_session_t, hw_list_node);
1637 for (j = 0; j < c_ses->sm_info.num_keyphrases; j++) {
1638 if (!strcmp(p_info->sm_info.keyphrases[i],
1639 c_ses->sm_info.keyphrases[j])) {
1640 if (c_ses->state == ST_STATE_ACTIVE) {
1641 ALOGV("%s: detected c%d", __func__,
1642 c_ses->sm_handle);
1643 return c_ses;
1644 } else {
1645 ALOGE("%s: detected c%d is not active", __func__,
1646 c_ses->sm_handle);
1647 return NULL;
1648 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001649 }
1650 }
1651 }
1652 }
Quinn Male58749452020-03-26 17:14:56 -07001653 } else {
1654 while (i < payload_size) {
1655 key_id = *(uint32_t *)payload;
1656 key_payload_size = *((uint32_t *)payload + 1);
1657
1658 if (key_id == KEY_ID_MULTI_MODEL_RESULT_INFO) {
1659 result_info = (multi_model_result_info_t *)(payload +
1660 GENERIC_DET_EVENT_HEADER_SIZE);
1661 list_for_each(node, &st_ses->clients_list) {
1662 c_ses = node_to_item(node, st_session_t, hw_list_node);
1663 if (c_ses->sm_info.model_id ==
1664 result_info->detected_model_id) {
1665 if (c_ses->state == ST_STATE_ACTIVE) {
Quinn Malea15c5ff2020-06-18 18:05:20 -07001666 ALOGD("%s: detected c%d, 1st stage conf level = %d",
1667 __func__, c_ses->sm_handle,
1668 result_info->best_confidence_level);
Quinn Male58749452020-03-26 17:14:56 -07001669 return c_ses;
1670 } else {
1671 ALOGE("%s: detected c%d is not active", __func__,
1672 c_ses->sm_handle);
1673 return NULL;
1674 }
1675 }
1676 }
1677 break;
1678 } else {
1679 ALOGE("%s: Unexpected key id for PDK5 0x%x", __func__,
1680 key_id);
1681 break;
1682 }
1683 i += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
1684 payload += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
1685 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001686 }
1687 return c_ses;
1688}
1689
1690static int fill_conf_levels_payload_from_rc_config
1691(
1692 const struct sound_trigger_phrase_sound_model *phrase_sm,
1693 const struct sound_trigger_recognition_config *rc_config,
1694 unsigned char *conf_levels,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001695 unsigned int total_num_users
1696)
1697{
1698 int status = 0;
1699 unsigned int user_level, user_id;
1700 unsigned int i = 0, j = 0;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001701 unsigned int num_conf_levels = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001702 unsigned char *user_id_tracker;
1703
Zhou Songdeddfcc2019-06-18 22:25:03 +08001704 if (!phrase_sm || !rc_config || !conf_levels) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001705 ALOGE("%s: ERROR. Invalid inputs",__func__);
1706 return -EINVAL;
1707 }
1708
Zhou Songdeddfcc2019-06-18 22:25:03 +08001709 if ((UINT32_MAX - total_num_users) > rc_config->num_phrases)
1710 num_conf_levels = total_num_users + rc_config->num_phrases;
1711
1712 if (!num_conf_levels) {
1713 ALOGE("%s: ERROR. Invalid num_conf_levels input", __func__);
1714 return -EINVAL;
1715 }
1716
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001717 /* Example: Say the recognition structure has 3 keywords with users
1718 * |kid|
1719 * [0] k1 |uid|
1720 * [3] u1 - 1st trainer
1721 * [4] u2 - 4th trainer
1722 * [6] u3 - 3rd trainer
1723 * [1] k2
1724 * [5] u2 - 2nd trainer
1725 * [7] u3 - 5th trainer
1726 * [2] k3
1727 * [8] u4 - 6th trainer
1728 *
1729 * Output confidence level array will be
1730 * [k1, k2, k3, u1k1, u2k1, u2k2, u3k1, u3k2, u4k3]
1731 */
1732
1733 user_id_tracker = calloc(1, num_conf_levels);
1734 if (!user_id_tracker) {
1735 ALOGE("%s: failed to allocate user_id_tracker", __func__);
1736 return -ENOMEM;
1737 }
1738
1739 for (i = 0; i < rc_config->num_phrases; i++) {
1740 ALOGV("%s: [%d] kw level %d", __func__, i,
1741 rc_config->phrases[i].confidence_level);
1742 for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
1743 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
1744 rc_config->phrases[i].levels[j].user_id,
1745 rc_config->phrases[i].levels[j].level);
1746 }
1747 }
1748
1749 for (i = 0; i < rc_config->num_phrases; i++) {
Zhou Songdeddfcc2019-06-18 22:25:03 +08001750 if (i < num_conf_levels) {
1751 conf_levels[i] = rc_config->phrases[i].confidence_level;
1752 } else {
1753 ALOGE("%s: ERROR. Invalid number of phrases", __func__);
1754 status = -EINVAL;
1755 goto exit;
1756 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001757 for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
1758 user_level = rc_config->phrases[i].levels[j].level;
1759 user_id = rc_config->phrases[i].levels[j].user_id;
1760 if ((user_id < rc_config->num_phrases) ||
1761 (user_id >= num_conf_levels)) {
1762 ALOGE("%s: ERROR. Invalid params user id %d>%d",
1763 __func__, user_id, total_num_users);
1764 status = -EINVAL;
1765 goto exit;
1766 } else {
1767 if (user_id_tracker[user_id] == 1) {
1768 ALOGE("%s: ERROR. Duplicate user id %d",
1769 __func__, user_id);
1770 status = -EINVAL;
1771 goto exit;
1772 }
1773 conf_levels[user_id] = (user_level < 100) ? user_level: 100;
1774 user_id_tracker[user_id] = 1;
1775 ALOGV("%s: user_conf_levels[%d] = %d", __func__,
1776 user_id, conf_levels[user_id]);
1777 }
1778 }
1779 }
1780
1781exit:
1782 free(user_id_tracker);
1783 return status;
1784}
1785
1786int generate_conf_levels_payload_from_rc_config
1787(
1788 const struct sound_trigger_phrase_sound_model *phrase_sm,
1789 const struct sound_trigger_recognition_config *rc_config,
1790 unsigned char **out_payload,
1791 unsigned int *out_payload_size
1792)
1793{
1794 int status = 0;
1795 unsigned int total_num_users = 0, num_conf_levels = 0;
1796 unsigned int i = 0, j = 0;
1797 unsigned char *conf_levels = NULL;
1798
1799 if (!phrase_sm || !rc_config || !out_payload || !out_payload_size) {
1800 ALOGE("%s: ERROR. Invalid inputs",__func__);
1801 status = -EINVAL;
1802 goto exit;
1803 }
1804 *out_payload = NULL;
1805 *out_payload_size = 0;
1806
1807 if((rc_config->num_phrases == 0) ||
1808 (rc_config->num_phrases > phrase_sm->num_phrases)) {
1809 ALOGE("%s: ERROR. Invalid phrases %d!=%d",__func__,
1810 rc_config->num_phrases, phrase_sm->num_phrases);
1811 status = -EINVAL;
1812 goto exit;
1813 }
1814 for (i = 0; i < rc_config->num_phrases; i++) {
1815 for (j = 0; j < rc_config->phrases[i].num_levels; j++)
1816 total_num_users++;
1817 }
1818
1819 num_conf_levels = total_num_users + rc_config->num_phrases;
1820 conf_levels = calloc(1, num_conf_levels);
1821 if (!conf_levels) {
1822 ALOGE("%s: ERROR. conf levels alloc failed",__func__);
1823 status = -ENOMEM;
1824 goto exit;
1825 }
1826
1827 status = fill_conf_levels_payload_from_rc_config(phrase_sm, rc_config,
Zhou Songdeddfcc2019-06-18 22:25:03 +08001828 conf_levels, total_num_users);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001829 if (status) {
1830 ALOGE("%s: fill config payload failed, error %d", __func__, status);
1831 goto exit;
1832 }
1833
1834 *out_payload = conf_levels;
1835 *out_payload_size = num_conf_levels;
1836
1837 return status;
1838
1839exit:
1840 if (conf_levels)
1841 free(conf_levels);
1842 return status;
1843}
1844
1845int generate_conf_levels_payload_from_rc_config_v2
1846(
1847 const struct sound_trigger_phrase_sound_model *phrase_sm,
1848 const struct sound_trigger_recognition_config *rc_config,
1849 unsigned char **out_payload,
1850 unsigned int *out_payload_size
1851)
1852{
1853 int status = 0;
1854 unsigned int total_num_users = 0, num_conf_levels = 0;
1855 unsigned char *conf_levels = NULL;
1856 unsigned int i = 0, j = 0;
1857
1858 ALOGV("%s: Enter...", __func__);
1859
1860 if (!phrase_sm || !rc_config || !out_payload || !out_payload_size) {
1861 ALOGE("%s: ERROR. Invalid inputs",__func__);
1862 status = -EINVAL;
1863 goto exit;
1864 }
1865 *out_payload = NULL;
1866 *out_payload_size = 0;
1867
1868 if((rc_config->num_phrases == 0) ||
1869 (rc_config->num_phrases > phrase_sm->num_phrases)) {
1870 ALOGE("%s: ERROR. Invalid phrases %d!=%d",__func__,
1871 rc_config->num_phrases, phrase_sm->num_phrases);
1872 status = -EINVAL;
1873 goto exit;
1874 }
1875 for (i = 0; i < rc_config->num_phrases; i++) {
1876 for (j = 0; j < rc_config->phrases[i].num_levels; j++)
1877 total_num_users++;
1878 }
1879
1880 num_conf_levels = total_num_users + rc_config->num_phrases;
1881 /*
1882 * allocate dsp payload w/additional 2 bytes for minor_version and
1883 * num_active_models and additional num_conf_levels for KW enable
1884 * fields
1885 */
1886 conf_levels = calloc(1, 2 + 2 * num_conf_levels);
1887 if (!conf_levels) {
1888 ALOGE("%s: ERROR. conf levels alloc failed",__func__);
1889 status = -ENOMEM;
1890 goto exit;
1891 }
1892
1893 conf_levels[0] = 1; /* minor version */
1894 conf_levels[1] = num_conf_levels; /* num_active_models */
1895 status = fill_conf_levels_payload_from_rc_config(phrase_sm, rc_config,
Zhou Songdeddfcc2019-06-18 22:25:03 +08001896 conf_levels + 2, total_num_users);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001897 if (status) {
1898 ALOGE("%s: fill config payload failed, error %d", __func__, status);
1899 goto exit;
1900 }
1901
1902 /*
1903 * set KW enable fields to 1 for now
1904 * TODO: set appropriately based on what client is passing in rc_config
1905 */
1906 memset(&conf_levels[num_conf_levels + 2], 0x1, num_conf_levels);
1907 ALOGV("%s: here", __func__);
1908 *out_payload = conf_levels;
1909 /* add size of minor version and num_active_models */
1910 *out_payload_size = 2 + 2 * num_conf_levels;
1911 return status;
1912
1913exit:
1914 if (conf_levels)
1915 free(conf_levels);
1916 return status;
1917}
1918
1919static int fill_sound_trigger_recognition_config_payload
1920(
1921 const void *sm_levels_generic,
1922 unsigned char *conf_levels,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001923 unsigned int total_num_users,
1924 uint32_t version
1925)
1926{
1927 int status = 0;
1928 unsigned int user_level = 0, user_id = 0;
1929 unsigned int i = 0, j = 0;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001930 unsigned int num_conf_levels = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001931 unsigned char *user_id_tracker = NULL;
1932 struct st_sound_model_conf_levels *sm_levels = NULL;
1933 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
1934
1935 /* Example: Say the recognition structure has 3 keywords with users
1936 * |kid|
1937 * [0] k1 |uid|
1938 * [3] u1 - 1st trainer
1939 * [4] u2 - 4th trainer
1940 * [6] u3 - 3rd trainer
1941 * [1] k2
1942 * [5] u2 - 2nd trainer
1943 * [7] u3 - 5th trainer
1944 * [2] k3
1945 * [8] u4 - 6th trainer
1946 *
1947 * Output confidence level array will be
1948 * [k1, k2, k3, u1k1, u2k1, u2k2, u3k1, u3k2, u4k3]
1949 */
1950
1951 if (version != CONF_LEVELS_INTF_VERSION_0002) {
1952 sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001953 if (!sm_levels || !conf_levels) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001954 ALOGE("%s: ERROR. Invalid inputs", __func__);
1955 return -EINVAL;
1956 }
Zhou Songdeddfcc2019-06-18 22:25:03 +08001957
1958 if ((UINT32_MAX - total_num_users) > sm_levels->num_kw_levels)
1959 num_conf_levels = total_num_users + sm_levels->num_kw_levels;
1960
1961 if (!num_conf_levels) {
1962 ALOGE("%s: ERROR. Invalid num_conf_levels input", __func__);
1963 return -EINVAL;
1964 }
1965
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001966 user_id_tracker = calloc(1, num_conf_levels);
1967 if (!user_id_tracker) {
1968 ALOGE("%s: failed to allocate user_id_tracker", __func__);
1969 return -ENOMEM;
1970 }
1971
1972 for (i = 0; i < sm_levels->num_kw_levels; i++) {
1973 ALOGV("%s: [%d] kw level %d", __func__, i,
1974 sm_levels->kw_levels[i].kw_level);
1975 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++) {
1976 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
1977 sm_levels->kw_levels[i].user_levels[j].user_id,
1978 sm_levels->kw_levels[i].user_levels[j].level);
1979 }
1980 }
1981
1982 for (i = 0; i < sm_levels->num_kw_levels; i++) {
Zhou Songdeddfcc2019-06-18 22:25:03 +08001983 if (i < num_conf_levels) {
1984 conf_levels[i] = sm_levels->kw_levels[i].kw_level;
1985 } else {
1986 ALOGE("%s: ERROR. Invalid numver of kw levels", __func__);
1987 status = -EINVAL;
1988 goto exit;
1989 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001990 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++) {
1991 user_level = sm_levels->kw_levels[i].user_levels[j].level;
1992 user_id = sm_levels->kw_levels[i].user_levels[j].user_id;
1993 if ((user_id < sm_levels->num_kw_levels) ||
1994 (user_id >= num_conf_levels)) {
1995 ALOGE("%s: ERROR. Invalid params user id %d>%d",
1996 __func__, user_id, total_num_users);
1997 status = -EINVAL;
1998 goto exit;
1999 } else {
2000 if (user_id_tracker[user_id] == 1) {
2001 ALOGE("%s: ERROR. Duplicate user id %d",
2002 __func__, user_id);
2003 status = -EINVAL;
2004 goto exit;
2005 }
2006 conf_levels[user_id] = (user_level < 100) ?
2007 user_level: 100;
2008 user_id_tracker[user_id] = 1;
2009 ALOGV("%s: user_conf_levels[%d] = %d", __func__,
2010 user_id, conf_levels[user_id]);
2011 }
2012 }
2013 }
2014 } else {
2015 sm_levels_v2 =
2016 (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
Zhou Songdeddfcc2019-06-18 22:25:03 +08002017 if (!sm_levels_v2 || !conf_levels) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002018 ALOGE("%s: ERROR. Invalid inputs", __func__);
2019 return -EINVAL;
2020 }
Zhou Songdeddfcc2019-06-18 22:25:03 +08002021
2022 if ((UINT32_MAX - total_num_users) > sm_levels_v2->num_kw_levels)
2023 num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
2024
2025 if (!num_conf_levels) {
2026 ALOGE("%s: ERROR. Invalid num_conf_levels input", __func__);
2027 return -EINVAL;
2028 }
2029
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002030 user_id_tracker = calloc(1, num_conf_levels);
2031 if (!user_id_tracker) {
2032 ALOGE("%s: failed to allocate user_id_tracker", __func__);
2033 return -ENOMEM;
2034 }
2035
2036 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
2037 ALOGV("%s: [%d] kw level %d", __func__, i,
2038 sm_levels_v2->kw_levels[i].kw_level);
2039 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++) {
2040 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
2041 sm_levels_v2->kw_levels[i].user_levels[j].user_id,
2042 sm_levels_v2->kw_levels[i].user_levels[j].level);
2043 }
2044 }
2045
2046 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
Zhou Songdeddfcc2019-06-18 22:25:03 +08002047 if (i < num_conf_levels) {
2048 conf_levels[i] = sm_levels_v2->kw_levels[i].kw_level;
2049 } else {
2050 ALOGE("%s: ERROR. Invalid numver of kw levels", __func__);
2051 status = -EINVAL;
2052 goto exit;
2053 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002054 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++) {
2055 user_level = sm_levels_v2->kw_levels[i].user_levels[j].level;
2056 user_id = sm_levels_v2->kw_levels[i].user_levels[j].user_id;
2057 if ((user_id < sm_levels_v2->num_kw_levels) ||
2058 (user_id >= num_conf_levels)) {
2059 ALOGE("%s: ERROR. Invalid params user id %d>%d",
2060 __func__, user_id, total_num_users);
2061 status = -EINVAL;
2062 goto exit;
2063 } else {
2064 if (user_id_tracker[user_id] == 1) {
2065 ALOGE("%s: ERROR. Duplicate user id %d",
2066 __func__, user_id);
2067 status = -EINVAL;
2068 goto exit;
2069 }
2070 conf_levels[user_id] = (user_level < 100) ?
2071 user_level: 100;
2072 user_id_tracker[user_id] = 1;
2073 ALOGV("%s: user_conf_levels[%d] = %d", __func__,
2074 user_id, conf_levels[user_id]);
2075 }
2076 }
2077 }
2078 }
2079
2080exit:
2081 free(user_id_tracker);
2082 return status;
2083}
2084
2085static int generate_sound_trigger_recognition_config_payload
2086(
2087 const void *sm_levels_generic,
2088 unsigned char **out_payload,
2089 unsigned int *out_payload_size,
2090 uint32_t version
2091)
2092{
2093 int status = 0;
2094 unsigned int total_num_users = 0, num_conf_levels = 0;
2095 unsigned char *conf_levels = NULL;
2096 unsigned int i = 0, j = 0;
2097 struct st_sound_model_conf_levels *sm_levels = NULL;
2098 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
2099
2100 ALOGV("%s: Enter...", __func__);
2101
2102 if (version != CONF_LEVELS_INTF_VERSION_0002) {
2103 sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
2104 if (!sm_levels || !out_payload || !out_payload_size) {
2105 ALOGE("%s: ERROR. Invalid inputs", __func__);
2106 status = -EINVAL;
2107 goto exit;
2108 }
2109 *out_payload = NULL;
2110 *out_payload_size = 0;
2111
2112 if (sm_levels->num_kw_levels == 0) {
2113 ALOGE("%s: ERROR. No confidence levels present", __func__);
2114 status = -EINVAL;
2115 goto exit;
2116 }
2117 for (i = 0; i < sm_levels->num_kw_levels; i++) {
2118 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++)
2119 total_num_users++;
2120 }
2121
2122 num_conf_levels = total_num_users + sm_levels->num_kw_levels;
2123 conf_levels = calloc(1, num_conf_levels);
2124 if (!conf_levels) {
2125 ALOGE("%s: ERROR. conf levels alloc failed", __func__);
2126 status = -ENOMEM;
2127 goto exit;
2128 }
2129 } else {
2130 sm_levels_v2 =
2131 (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
2132 if (!sm_levels_v2 || !out_payload || !out_payload_size) {
2133 ALOGE("%s: ERROR. Invalid inputs", __func__);
2134 status = -EINVAL;
2135 goto exit;
2136 }
2137 *out_payload = NULL;
2138 *out_payload_size = 0;
2139
2140 if (sm_levels_v2->num_kw_levels == 0) {
2141 ALOGE("%s: ERROR. No confidence levels present", __func__);
2142 status = -EINVAL;
2143 goto exit;
2144 }
2145 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
2146 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++)
2147 total_num_users++;
2148 }
2149
2150 num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
2151 conf_levels = calloc(1, num_conf_levels);
2152 if (!conf_levels) {
2153 ALOGE("%s: ERROR. conf levels alloc failed", __func__);
2154 status = -ENOMEM;
2155 goto exit;
2156 }
2157 }
2158
2159 status = fill_sound_trigger_recognition_config_payload(sm_levels_generic,
Zhou Songdeddfcc2019-06-18 22:25:03 +08002160 conf_levels, total_num_users, version);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002161 if (status) {
2162 ALOGE("%s: fill config payload failed, error %d", __func__, status);
2163 goto exit;
2164 }
2165
2166 *out_payload = conf_levels;
2167 *out_payload_size = num_conf_levels;
2168
2169 return status;
2170
2171exit:
2172 if (conf_levels)
2173 free(conf_levels);
2174
2175 return status;
2176}
2177
2178static int generate_sound_trigger_recognition_config_payload_v2
2179(
2180 const void *sm_levels_generic,
2181 unsigned char **out_payload,
2182 unsigned int *out_payload_size,
2183 uint32_t version
2184)
2185{
2186 int status = 0;
2187 unsigned int total_num_users = 0, num_conf_levels = 0;
2188 unsigned char *conf_levels = NULL;
2189 unsigned int i = 0, j = 0;
2190 struct st_sound_model_conf_levels *sm_levels = NULL;
2191 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
2192
2193 ALOGV("%s: Enter...", __func__);
2194
2195 if (version != CONF_LEVELS_INTF_VERSION_0002) {
2196 sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
2197 if (!sm_levels || !out_payload || !out_payload_size) {
2198 ALOGE("%s: ERROR. Invalid inputs", __func__);
2199 status = -EINVAL;
2200 goto exit;
2201 }
2202 *out_payload = NULL;
2203 *out_payload_size = 0;
2204
2205 if (sm_levels->num_kw_levels == 0) {
2206 ALOGE("%s: ERROR. No confidence levels present", __func__);
2207 status = -EINVAL;
2208 goto exit;
2209 }
2210 for (i = 0; i < sm_levels->num_kw_levels; i++) {
2211 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++)
2212 total_num_users++;
2213 }
2214
2215 num_conf_levels = total_num_users + sm_levels->num_kw_levels;
2216 } else {
2217 sm_levels_v2 =
2218 (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
2219 if (!sm_levels_v2 || !out_payload || !out_payload_size) {
2220 ALOGE("%s: ERROR. Invalid inputs", __func__);
2221 status = -EINVAL;
2222 goto exit;
2223 }
2224 *out_payload = NULL;
2225 *out_payload_size = 0;
2226
2227 if (sm_levels_v2->num_kw_levels == 0) {
2228 ALOGE("%s: ERROR. No confidence levels present", __func__);
2229 status = -EINVAL;
2230 goto exit;
2231 }
2232 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
2233 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++)
2234 total_num_users++;
2235 }
2236 num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
2237 }
2238
2239 /*
2240 * allocate dsp payload w/additional 2 bytes for minor_version and
2241 * num_active_models and additional num_conf_levels for KW enable
2242 * fields
2243 */
2244 conf_levels = calloc(1, 2 + 2 * num_conf_levels);
2245 if (!conf_levels) {
2246 ALOGE("%s: ERROR. conf levels alloc failed", __func__);
2247 status = -ENOMEM;
2248 goto exit;
2249 }
2250
2251 conf_levels[0] = 1; /* minor version */
2252 conf_levels[1] = num_conf_levels; /* num_active_models */
2253 status = fill_sound_trigger_recognition_config_payload(sm_levels_generic,
Zhou Songdeddfcc2019-06-18 22:25:03 +08002254 conf_levels + 2, total_num_users, version);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002255 if (status) {
2256 ALOGE("%s: fill config payload failed, error %d", __func__, status);
2257 goto exit;
2258 }
2259
2260 /* set KW enable fields to 1 for now
2261 * TODO set appropriately based on what client is passing in rc_config
2262 */
2263 memset(&conf_levels[num_conf_levels + 2], 0x1, num_conf_levels);
2264 ALOGV("%s: here", __func__);
2265 *out_payload = conf_levels;
2266 /* add size of minor version and num_active_models */
2267 *out_payload_size = 2 + 2 * num_conf_levels;
2268
2269 return status;
2270
2271exit:
2272 if (conf_levels)
2273 free(conf_levels);
2274
2275 return status;
2276}
2277
2278static int parse_rc_config_key_conf_levels
2279(
2280 st_session_t *stc_ses,
2281 st_hw_session_t *st_hw_ses,
2282 void *opaque_conf_levels,
2283 unsigned char **out_conf_levels,
2284 unsigned int *out_num_conf_levels
2285)
2286{
2287 struct st_confidence_levels_info *conf_levels = NULL;
2288 struct st_confidence_levels_info_v2 *conf_levels_v2 = NULL;
2289 struct st_sound_model_conf_levels *sm_levels = NULL;
2290 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
2291 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
2292 struct listnode *node = NULL;
2293 st_lsm_ss_config_t *ss_cfg = NULL;
2294 st_arm_second_stage_t *st_sec_stage = NULL;
2295 int status = 0;
2296 uint32_t i = 0;
2297 bool gmm_conf_found = false;
2298 uint8_t confidence_level = 0;
2299 int32_t confidence_level_v2 = 0;
2300 bool arm_second_stage = !list_empty(&stc_ses->second_stage_list);
2301 bool adsp_second_stage = (st_hw_ses == st_ses->hw_ses_adsp &&
2302 !list_empty(&st_hw_ses->lsm_ss_cfg_list));
2303
2304 if (arm_second_stage || adsp_second_stage) {
2305 if (stc_ses->rc_config->num_phrases > 1) {
2306 ALOGE("%s: Multi keyword is unsupported with 2nd stage detection",
2307 __func__);
2308 return -EINVAL;
2309 }
2310
2311 if (stc_ses->rc_config->phrases[0].num_levels > 1) {
2312 ALOGE("%s: Multi user is unsupported with 2nd stage detection",
2313 __func__);
2314 return -EINVAL;
2315 }
2316 }
2317
2318 if (stc_ses->st_conf_levels) {
2319 free(stc_ses->st_conf_levels);
2320 stc_ses->st_conf_levels = NULL;
2321 }
2322
2323 if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002) {
2324 conf_levels = (struct st_confidence_levels_info *)
2325 ((char *)opaque_conf_levels + sizeof(struct st_param_header));
2326
2327 stc_ses->st_conf_levels =
2328 calloc(1, sizeof(struct st_confidence_levels_info));
2329 if (!stc_ses->st_conf_levels) {
2330 ALOGE("%s: failed to alloc st_conf_levels", __func__);
2331 return -ENOMEM;
2332 }
2333 /* Cache to use during detection event processing */
2334 memcpy(stc_ses->st_conf_levels, (char *)conf_levels,
2335 sizeof(struct st_confidence_levels_info));
2336
2337 for (i = 0; i < conf_levels->num_sound_models; i++) {
2338 sm_levels = &conf_levels->conf_levels[i];
2339 if (sm_levels->sm_id == ST_SM_ID_SVA_GMM) {
Quinn Male9a345522020-03-12 17:49:25 -07002340 if (st_hw_ses == st_ses->hw_ses_cpe)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002341 status =
2342 generate_sound_trigger_recognition_config_payload_v2(
2343 (void *)sm_levels, out_conf_levels, out_num_conf_levels,
2344 stc_ses->conf_levels_intf_version);
2345 else
2346 status =
2347 generate_sound_trigger_recognition_config_payload(
2348 (void *)sm_levels, out_conf_levels, out_num_conf_levels,
2349 stc_ses->conf_levels_intf_version);
2350 gmm_conf_found = true;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002351 } else if (IS_SECOND_STAGE_MODEL(sm_levels->sm_id)) {
2352 confidence_level = IS_KEYWORD_DETECTION_MODEL(sm_levels->sm_id) ?
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002353 sm_levels->kw_levels[0].kw_level:
2354 sm_levels->kw_levels[0].user_levels[0].level;
2355 if (arm_second_stage) {
2356 list_for_each(node, &stc_ses->second_stage_list) {
2357 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
2358 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002359 if (IS_MATCHING_SS_MODEL(st_sec_stage->ss_info->sm_id,
2360 sm_levels->sm_id))
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002361 st_sec_stage->ss_session->confidence_threshold =
2362 confidence_level;
2363 }
2364 } else if (adsp_second_stage) {
2365 list_for_each(node, &st_hw_ses->lsm_ss_cfg_list) {
2366 ss_cfg = node_to_item(node, st_lsm_ss_config_t,
2367 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002368 if (IS_MATCHING_SS_MODEL(ss_cfg->ss_info->sm_id,
2369 sm_levels->sm_id))
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002370 ss_cfg->confidence_threshold = confidence_level;
2371 }
2372 }
2373 } else {
2374 ALOGE("%s: Unsupported sm id (%d), exiting", __func__,
2375 sm_levels->sm_id);
2376 status = -EINVAL;
2377 break;
2378 }
2379 }
2380 } else {
2381 conf_levels_v2 = (struct st_confidence_levels_info_v2 *)
2382 ((char *)opaque_conf_levels + sizeof(struct st_param_header));
2383
2384 stc_ses->st_conf_levels =
2385 calloc(1, sizeof(struct st_confidence_levels_info_v2));
2386 if (!stc_ses->st_conf_levels) {
2387 ALOGE("%s: failed to alloc st_conf_levels", __func__);
2388 return -ENOMEM;
2389 }
2390 /* Cache to use during detection event processing */
2391 memcpy(stc_ses->st_conf_levels, (char *)conf_levels_v2,
2392 sizeof(struct st_confidence_levels_info_v2));
2393
2394 for (i = 0; i < conf_levels_v2->num_sound_models; i++) {
2395 sm_levels_v2 = &conf_levels_v2->conf_levels[i];
2396 if (sm_levels_v2->sm_id == ST_SM_ID_SVA_GMM) {
Quinn Male9a345522020-03-12 17:49:25 -07002397 if (st_hw_ses == st_ses->hw_ses_cpe)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002398 status =
2399 generate_sound_trigger_recognition_config_payload_v2(
2400 (void *)sm_levels_v2, out_conf_levels, out_num_conf_levels,
2401 stc_ses->conf_levels_intf_version);
2402 else
2403 status =
2404 generate_sound_trigger_recognition_config_payload(
2405 (void *)sm_levels_v2, out_conf_levels,
2406 out_num_conf_levels, stc_ses->conf_levels_intf_version);
2407 gmm_conf_found = true;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002408 } else if (IS_SECOND_STAGE_MODEL(sm_levels_v2->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002409 confidence_level_v2 =
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002410 (IS_KEYWORD_DETECTION_MODEL(sm_levels_v2->sm_id)) ?
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002411 sm_levels_v2->kw_levels[0].kw_level:
2412 sm_levels_v2->kw_levels[0].user_levels[0].level;
2413 if (arm_second_stage) {
2414 list_for_each(node, &stc_ses->second_stage_list) {
2415 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
2416 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002417 if (IS_MATCHING_SS_MODEL(st_sec_stage->ss_info->sm_id,
2418 sm_levels_v2->sm_id))
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002419 st_sec_stage->ss_session->confidence_threshold =
2420 confidence_level_v2;
2421 }
2422 } else if (adsp_second_stage) {
2423 list_for_each(node, &st_hw_ses->lsm_ss_cfg_list) {
2424 ss_cfg = node_to_item(node, st_lsm_ss_config_t,
2425 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002426 if (IS_MATCHING_SS_MODEL(ss_cfg->ss_info->sm_id,
2427 sm_levels_v2->sm_id))
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002428 ss_cfg->confidence_threshold = confidence_level_v2;
2429 }
2430 }
2431 } else {
2432 ALOGE("%s: Unsupported sm id (%d), exiting", __func__,
2433 sm_levels_v2->sm_id);
2434 status = -EINVAL;
2435 break;
2436 }
2437 }
2438 }
2439
2440 if (!gmm_conf_found) {
2441 ALOGE("%s: Did not receive GMM confidence threshold, error!", __func__);
2442 status = -EINVAL;
2443 }
2444
2445 if (status && stc_ses->st_conf_levels) {
2446 free(stc_ses->st_conf_levels);
2447 stc_ses->st_conf_levels = NULL;
2448 }
2449 return status;
2450}
2451
2452static int update_hw_config_on_start(st_session_t *stc_ses,
2453 st_hw_session_t *st_hw_ses)
2454{
2455 struct st_param_header *param_hdr = NULL;
2456 struct st_hist_buffer_info *hist_buf = NULL;
2457 struct st_det_perf_mode_info *det_perf_mode = NULL;
2458 struct sound_trigger_recognition_config *rc_config = stc_ses->rc_config;
2459 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
2460 struct st_vendor_info *v_info = NULL;
2461 struct st_hw_ses_config *sthw_cfg = NULL;
2462 unsigned char *conf_levels = NULL;
2463 unsigned int num_conf_levels = 0;
2464 uint8_t *opaque_ptr = NULL;
2465 unsigned int opaque_size = 0, conf_levels_payload_size = 0;
2466 int status = 0;
2467 bool enable_lab = false;
Quinn Male58749452020-03-26 17:14:56 -07002468 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002469
Quinn Maleaba13db2019-07-11 15:52:14 -07002470 if (st_ses->stdev->enable_debug_dumps) {
2471 ST_DBG_DECLARE(FILE *rc_opaque_fd = NULL;
2472 static int rc_opaque_cnt = 0);
2473 ST_DBG_FILE_OPEN_WR(rc_opaque_fd, ST_DEBUG_DUMP_LOCATION,
2474 "rc_config_opaque_data", "bin", rc_opaque_cnt++);
2475 ST_DBG_FILE_WRITE(rc_opaque_fd,
2476 (uint8_t *)rc_config + rc_config->data_offset,
2477 rc_config->data_size);
2478 ST_DBG_FILE_CLOSE(rc_opaque_fd);
2479 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002480
2481 if (!st_hw_ses) {
2482 ALOGE("%s: NULL hw session !!!", __func__);
2483 return -EINVAL;
2484 }
2485
2486 v_info = st_hw_ses->vendor_uuid_info;
2487
2488 if ((rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
2489 v_info->is_qcva_uuid) {
2490 stc_ses->client_req_det_mode = ST_DET_UNKNOWN_MODE;
2491
2492 opaque_ptr = (uint8_t *)rc_config + rc_config->data_offset;
2493 while (opaque_size < rc_config->data_size) {
2494 param_hdr = (struct st_param_header *)opaque_ptr;
2495 ALOGV("%s: key %d, payload size %d", __func__,
2496 param_hdr->key_id, param_hdr->payload_size);
2497
2498 switch(param_hdr->key_id) {
2499 case ST_PARAM_KEY_CONFIDENCE_LEVELS:
2500 stc_ses->conf_levels_intf_version =
2501 *(uint32_t *)(opaque_ptr + sizeof(struct st_param_header));
2502
2503 if (stc_ses->conf_levels_intf_version !=
2504 CONF_LEVELS_INTF_VERSION_0002) {
2505 conf_levels_payload_size =
2506 sizeof(struct st_confidence_levels_info);
2507 } else {
2508 conf_levels_payload_size =
2509 sizeof(struct st_confidence_levels_info_v2);
2510 }
2511 if (param_hdr->payload_size != conf_levels_payload_size) {
2512 ALOGE("%s: Conf level format error, exiting", __func__);
2513 return -EINVAL;
2514 }
2515 status = parse_rc_config_key_conf_levels(stc_ses, st_hw_ses,
2516 opaque_ptr, &conf_levels, &num_conf_levels);
2517 opaque_size += sizeof(struct st_param_header) +
2518 conf_levels_payload_size;
2519 opaque_ptr += sizeof(struct st_param_header) +
2520 conf_levels_payload_size;
2521 if (status) {
2522 ALOGE("%s: parsing conf levels failed(status=%d)",
2523 __func__, status);
2524 return -EINVAL;
2525 }
2526 break;
2527 case ST_PARAM_KEY_HISTORY_BUFFER_CONFIG:
2528 if (param_hdr->payload_size !=
2529 sizeof(struct st_hist_buffer_info)) {
2530 ALOGE("%s: History buffer config format error, exiting",
2531 __func__);
2532 return -EINVAL;
2533 }
2534 hist_buf = (struct st_hist_buffer_info *)(opaque_ptr +
2535 sizeof(struct st_param_header));
2536 stc_ses->hist_buf_duration =
2537 hist_buf->hist_buffer_duration_msec;
2538 stc_ses->preroll_duration = hist_buf->pre_roll_duration_msec;
2539 ALOGV("%s: recognition config history buf len = %d, "
2540 "preroll len = %d, minor version = %d",
2541 __func__, hist_buf->hist_buffer_duration_msec,
2542 hist_buf->pre_roll_duration_msec, hist_buf->version);
2543 opaque_size += sizeof(struct st_param_header) +
2544 sizeof(struct st_hist_buffer_info);
2545 opaque_ptr += sizeof(struct st_param_header) +
2546 sizeof(struct st_hist_buffer_info);
2547 break;
2548 case ST_PARAM_KEY_DETECTION_PERF_MODE:
2549 if (param_hdr->payload_size !=
2550 sizeof(struct st_det_perf_mode_info)) {
2551 ALOGE("%s: Opaque data format error, exiting", __func__);
2552 return -EINVAL;
2553 }
2554 det_perf_mode = (struct st_det_perf_mode_info *)(opaque_ptr +
2555 sizeof(struct st_param_header));
2556 ALOGV("set perf mode to %d", det_perf_mode->mode);
2557 stc_ses->client_req_det_mode = det_perf_mode->mode;
2558 opaque_size += sizeof(struct st_param_header) +
2559 sizeof(struct st_det_perf_mode_info);
2560 opaque_ptr += sizeof(struct st_param_header) +
2561 sizeof(struct st_det_perf_mode_info);
2562 break;
2563 default:
2564 ALOGE("%s: Unsupported opaque data key id, exiting", __func__);
2565 return -EINVAL;
2566 }
2567 }
2568 } else if (stc_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
2569 struct sound_trigger_phrase_sound_model *phrase_sm = stc_ses->phrase_sm;
2570
2571 ALOGV("%s: num_phrases=%d, id=%d", __func__,
2572 rc_config->num_phrases, rc_config->phrases[0].id);
2573
2574 if (st_ses->vendor_uuid_info->is_qcva_uuid ||
2575 st_ses->vendor_uuid_info->is_qcmd_uuid) {
Quinn Male9a345522020-03-12 17:49:25 -07002576 if (st_hw_ses == st_ses->hw_ses_cpe)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002577 status = generate_conf_levels_payload_from_rc_config_v2(
2578 phrase_sm, rc_config, &conf_levels, &num_conf_levels);
2579 else
2580 status = generate_conf_levels_payload_from_rc_config(
2581 phrase_sm, rc_config, &conf_levels, &num_conf_levels);
2582 if (status || !conf_levels) {
2583 ALOGE("%s: failed to get conf levels from lib handle",
2584 __func__);
2585 return status;
2586 }
2587 } else {
2588 ALOGD("%s: No smlib, opaque data would be sent as is", __func__);
2589 }
2590 }
2591
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002592 enable_lab = stc_ses->rc_config->capture_requested ||
2593 !list_empty(&stc_ses->second_stage_list);
2594
Quinn Male58749452020-03-26 17:14:56 -07002595 sthw_cfg = get_sthw_cfg_for_model_id(st_hw_ses,
2596 stc_ses->sm_info.model_id);
2597 if (!sthw_cfg) {
2598 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
2599 return -EINVAL;
2600 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002601
Quinn Male58749452020-03-26 17:14:56 -07002602 if (stc_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
2603 if (v_info->merge_fs_soundmodels) {
2604 /* merge_fs_soundmodels is true only for QC SVA UUID */
2605
Xiaoyu Yeb067f472020-07-31 09:09:08 -07002606 if (conf_levels == NULL) {
2607 ALOGE("%s: Unexpected, conf_levels pointer is NULL",
2608 __func__);
2609 status = -EINVAL;
2610 return status;
2611 }
Quinn Male58749452020-03-26 17:14:56 -07002612 /*
2613 * Note:
2614 * For ADSP case, the generated conf levles size must be equal to
2615 * SML queried conf levels.
2616 * For WDSP gcs case, there is additional payload for KW enable
2617 * fields in generated conf_levels. If merge sound model is supported
2618 * on WDSP case, update logic here accordingly.
2619 */
2620 if (num_conf_levels != stc_ses->sm_info.cf_levels_size) {
2621 ALOGE("%s: Unexpected, client cf levels %d != sm_info cf levels %d",
2622 __func__, num_conf_levels, stc_ses->sm_info.cf_levels_size);
2623 return -EINVAL;
2624 }
2625
2626 /*
2627 * If any of the active clients requested capture or enabled the
2628 * second stage, the underlying hw session buffering needs to
2629 * be enabled. Ignore if it is already enabled.
2630 */
2631 if (!st_ses->lab_enabled && enable_lab)
2632 st_ses->lab_enabled = true;
2633
2634 /* Aggregate DSP configuration for highest client configuration */
2635
2636 /* SVA2.0 sound models */
2637 if (!stc_ses->hist_buf_duration &&
2638 stc_ses->rc_config->capture_requested &&
2639 (stc_ses->rc_config->data_size > 0)) {
2640 stc_ses->hist_buf_duration = st_ses->vendor_uuid_info->kw_duration;
2641 stc_ses->preroll_duration = 0;
2642 }
2643
2644 if (stc_ses->hist_buf_duration > sthw_cfg->client_req_hist_buf) {
2645 sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
2646 st_hw_ses->max_hist_buf = stc_ses->hist_buf_duration;
2647 }
2648 if (stc_ses->preroll_duration > sthw_cfg->client_req_preroll) {
2649 sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
2650 st_hw_ses->max_preroll = stc_ses->preroll_duration;
2651 }
2652
2653 ALOGV("%s: client hb_sz %d pr_sz %d, sthw lab %d hb_sz %d "
2654 "pr_sz %d", __func__, stc_ses->hist_buf_duration,
2655 stc_ses->preroll_duration, st_ses->lab_enabled,
2656 sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
2657
2658 /* Cache it to use when client restarts without config update or
2659 * during only one remaining client model as there won't be a
2660 * merged model yet.
2661 */
2662 memcpy(stc_ses->sm_info.cf_levels, conf_levels,
2663 stc_ses->sm_info.cf_levels_size);
2664
2665 status = update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
2666 conf_levels, num_conf_levels, true);
2667 free(conf_levels); /* Merged model conf levels will be used further */
2668 if (status)
2669 return status;
2670
2671 p_info = get_sm_info_for_model_id(st_ses, 0);
2672 if (!p_info) {
2673 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
2674 status = -EINVAL;
2675 return status;
2676 }
2677
2678 sthw_cfg->conf_levels = p_info->sm_info.cf_levels;
2679 sthw_cfg->num_conf_levels = p_info->sm_info.cf_levels_size;
2680 sthw_cfg->model_id = 0;
2681 st_hw_ses->sthw_cfg_updated = true;
2682
2683 /*
2684 * Merging further unknown custom data is not needed, as
2685 * SVA doesn't support unkown custom data. if required in future,
2686 * handle here.
2687 * For now just copy the the current client data which is same
2688 * across SVA engines.
2689 * Update the custom data for the case in which one client session
2690 * does not have custom data and another one does.
2691 */
2692 if (rc_config->data_size > st_hw_ses->custom_data_size) {
2693 st_hw_ses->custom_data = (char *)rc_config + rc_config->data_offset;
2694 st_hw_ses->custom_data_size = rc_config->data_size;
2695 }
2696 } else {
2697 st_ses->recognition_mode = stc_ses->recognition_mode;
2698 st_ses->lab_enabled = enable_lab;
2699 sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
2700 st_hw_ses->max_hist_buf = stc_ses->hist_buf_duration;
2701 sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
2702 st_hw_ses->max_preroll = stc_ses->preroll_duration;
2703
2704 if (sthw_cfg->conf_levels)
2705 free(sthw_cfg->conf_levels);
2706 sthw_cfg->conf_levels = conf_levels;
2707 sthw_cfg->num_conf_levels = num_conf_levels;
2708
2709 st_hw_ses->custom_data = (char *)rc_config + rc_config->data_offset;
2710 st_hw_ses->custom_data_size = rc_config->data_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002711 }
2712
Quinn Male58749452020-03-26 17:14:56 -07002713
2714 } else {
Xiaoyu Yeb067f472020-07-31 09:09:08 -07002715 if (conf_levels == NULL) {
2716 ALOGE("%s: Unexpected, conf_levels pointer is NULL",
2717 __func__);
2718 status = -EINVAL;
2719 return status;
2720 }
2721
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002722 if (!st_ses->lab_enabled && enable_lab)
2723 st_ses->lab_enabled = true;
2724
Quinn Male58749452020-03-26 17:14:56 -07002725 sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
2726 if (st_hw_ses->max_hist_buf < stc_ses->hist_buf_duration)
2727 st_hw_ses->max_hist_buf = stc_ses->hist_buf_duration;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002728
Quinn Male58749452020-03-26 17:14:56 -07002729 sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
2730 if (st_hw_ses->max_preroll < stc_ses->preroll_duration)
2731 st_hw_ses->max_preroll = stc_ses->preroll_duration;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002732
2733 /*
Quinn Malebed88ad2020-07-10 14:51:12 -07002734 * User verification confidence is not required
2735 * in SVA5 PDK_UV case. As first stage doesn't
2736 * support user verification.
2737 */
2738 num_conf_levels = 1;
2739
2740 /*
Quinn Male58749452020-03-26 17:14:56 -07002741 * Cache it to use when client restarts without
2742 * config update
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002743 */
Quinn Male58749452020-03-26 17:14:56 -07002744 memcpy(stc_ses->sm_info.cf_levels, conf_levels,
2745 num_conf_levels);
2746 stc_ses->sm_info.cf_levels_size = num_conf_levels;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002747
Quinn Male58749452020-03-26 17:14:56 -07002748 memcpy(sthw_cfg->conf_levels, conf_levels,
2749 num_conf_levels);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002750 sthw_cfg->num_conf_levels = num_conf_levels;
Quinn Male58749452020-03-26 17:14:56 -07002751 free(conf_levels);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002752
Quinn Male58749452020-03-26 17:14:56 -07002753 if (rc_config->data_size >= st_hw_ses->custom_data_size) {
2754 st_hw_ses->custom_data = (char *)rc_config + rc_config->data_offset;
2755 st_hw_ses->custom_data_size = rc_config->data_size;
2756 }
2757 st_hw_ses->sthw_cfg_updated = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002758 }
2759 ALOGD("%s:[%d] lab enabled %d", __func__, st_ses->sm_handle,
2760 st_ses->lab_enabled);
2761
2762 return status;
2763}
2764
Quinn Male58749452020-03-26 17:14:56 -07002765static int reg_all_sm(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses)
2766{
2767 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
2768 struct listnode *node = NULL;
2769 int status = 0;
2770
2771 list_for_each(node, &st_ses->sm_info_list) {
2772 p_info = node_to_item(node, struct st_proxy_ses_sm_info_wrapper,
2773 sm_list_node);
2774 status = hw_ses->fptrs->reg_sm(hw_ses, p_info->sm_info.sm_data,
2775 p_info->sm_info.sm_size, p_info->sm_info.model_id);
2776 if (status) {
2777 ALOGE("%s:[%d] reg_sm failed, model_id = %d, status = %d", __func__,
2778 st_ses->sm_handle, p_info->sm_info.model_id, status);
2779 return status;
2780 }
2781 }
2782
2783 return 0;
2784}
2785
2786static int dereg_all_sm(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses)
2787{
2788 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
2789 struct listnode *node = NULL;
2790 int status = 0, ret = 0;
2791
2792 list_for_each(node, &st_ses->sm_info_list) {
2793 p_info = node_to_item(node, struct st_proxy_ses_sm_info_wrapper,
2794 sm_list_node);
2795 status = hw_ses->fptrs->dereg_sm(hw_ses, p_info->sm_info.model_id);
2796 if (status) {
2797 ALOGE("%s:[%d] dereg_sm failed, model_id = %d, status = %d", __func__,
2798 st_ses->sm_handle, p_info->sm_info.model_id, status);
2799 ret = status;
2800 }
2801 }
2802
2803 return ret;
2804}
2805
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002806static void do_hw_sess_cleanup(st_proxy_session_t *st_ses,
2807 st_hw_session_t *hw_ses, enum hw_session_err_mask err)
Quinn Male2e883752019-03-22 11:28:54 -07002808{
2809 if (err & HW_SES_ERR_MASK_BUFFERING)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002810 hw_ses->fptrs->stop_buffering(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002811
2812 if (err & HW_SES_ERR_MASK_STARTED) {
2813 hw_ses->fptrs->stop(hw_ses);
2814 st_ses->hw_session_started = false;
2815 }
2816
2817 if (err & HW_SES_ERR_MASK_REG_SM_PARAM)
2818 hw_ses->fptrs->dereg_sm_params(hw_ses);
2819
2820 if (err & HW_SES_ERR_MASK_DEVICE_SET)
2821 hw_ses->fptrs->set_device(hw_ses, false);
2822
2823 if (err & HW_SES_ERR_MASK_REG_SM)
Quinn Male58749452020-03-26 17:14:56 -07002824 dereg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002825}
2826
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002827static void reg_hal_event_session(st_session_t *stc_ses,
2828 st_hw_session_t *hw_ses)
Quinn Male2e883752019-03-22 11:28:54 -07002829{
2830 struct sound_trigger_event_info event_info;
2831 /* Pass the pcm information to audio hal for capturing LAB */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002832 if ((stc_ses->rc_config &&
2833 stc_ses->rc_config->capture_requested) &&
2834 stc_ses->stdev->audio_hal_cb) {
2835 ALOGD("%s:[c%d] ST_EVENT_SESSION_REGISTER capture_handle %d",
2836 __func__, stc_ses->sm_handle, stc_ses->capture_handle);
2837 event_info.st_ses.p_ses = (void *)stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07002838 event_info.st_ses.config = hw_ses->config;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002839 event_info.st_ses.capture_handle = stc_ses->capture_handle;
Quinn Male2e883752019-03-22 11:28:54 -07002840 /*
2841 * set pcm to NULL as this version of st_hal doesn't pass pcm to
2842 * audio HAL
2843 */
2844 event_info.st_ses.pcm = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002845 stc_ses->stdev->audio_hal_cb(ST_EVENT_SESSION_REGISTER, &event_info);
Quinn Male2e883752019-03-22 11:28:54 -07002846 }
2847}
2848
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002849static void dereg_hal_event_session(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07002850{
2851 struct sound_trigger_event_info event_info;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002852 /* Indicate to audio hal that to stop reading LAB data */
2853 if ((stc_ses->rc_config &&
2854 stc_ses->rc_config->capture_requested) &&
2855 stc_ses->stdev->audio_hal_cb) {
2856 ALOGD("%s:[c%d] ST_EVENT_SESSION_DEREGISTER capture_handle %d",
2857 __func__, stc_ses->sm_handle, stc_ses->capture_handle);
2858 event_info.st_ses.p_ses = (void *)stc_ses;
2859 event_info.st_ses.capture_handle = stc_ses->capture_handle;
Quinn Male2e883752019-03-22 11:28:54 -07002860 event_info.st_ses.pcm = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002861 stc_ses->stdev->audio_hal_cb(ST_EVENT_SESSION_DEREGISTER, &event_info);
Quinn Male2e883752019-03-22 11:28:54 -07002862 }
2863}
2864
Zhou Songcd3c8e62019-07-16 13:30:19 +08002865static bool check_gcs_usecase_switch
2866(
2867 st_proxy_session_t *st_ses
2868)
2869{
2870 struct st_vendor_info *v_info = NULL;
2871 st_hw_session_t *p_ses = NULL;
2872 st_hw_session_gcs_t *p_gcs_ses = NULL;
2873 int st_device = 0;
2874 unsigned int device_acdb_id = 0;
2875 int capture_device;
2876
2877 if (!st_ses || st_ses->exec_mode != ST_EXEC_MODE_CPE) {
2878 ALOGE("%s: Invalid session or non CPE session!", __func__);
2879 return false;
2880 }
2881
2882 p_ses = st_ses->hw_ses_cpe;
2883 p_gcs_ses = (st_hw_session_gcs_t *)p_ses;
2884 v_info = p_ses->vendor_uuid_info;
2885
2886 if (list_empty(&v_info->gcs_usecase_list)) {
2887 ALOGE("%s: gcs usecase not available", __func__);
2888 return false;
2889 }
2890
2891 /* check if need to switch gcs usecase for new capture device */
2892 capture_device = platform_stdev_get_capture_device(p_ses->stdev->platform);
2893 st_device = platform_stdev_get_device(p_ses->stdev->platform,
2894 v_info, capture_device, p_ses->exec_mode);
2895 device_acdb_id = platform_stdev_get_acdb_id(st_device,
2896 p_ses->exec_mode);
2897 if (platform_stdev_get_xml_version(p_ses->stdev->platform) >=
2898 PLATFORM_XML_VERSION_0x0102) {
2899 int i = 0;
2900 while ((i < MAX_GCS_USECASE_ACDB_IDS) &&
2901 p_gcs_ses->gcs_usecase->acdb_ids[i]) {
2902 if (p_gcs_ses->gcs_usecase->acdb_ids[i] == device_acdb_id)
2903 return false;
2904 i++;
2905 }
2906 ALOGD("%s: gcs usecase doesn't match for new device", __func__);
2907 return true;
2908 } else {
2909 return false;
2910 }
2911}
2912
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002913static int start_hw_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
2914 bool load_sm)
Quinn Male2e883752019-03-22 11:28:54 -07002915{
2916 int status = 0, err = 0;
Zhou Songcd3c8e62019-07-16 13:30:19 +08002917 bool do_unload = false;
Quinn Male2e883752019-03-22 11:28:54 -07002918
2919 /*
Quinn Male3d7d9d42019-05-20 13:35:01 -07002920 * It is possible the BE LPI mode has been updated, but not the FE mode.
2921 * DSP requires both FE and BE to be in the same mode for any configuration
2922 * changes between LPI and non-LPI switch, so update the FE mode to the
Quinn Malecc1affd2019-07-18 16:13:31 -07002923 * same as BE mode by re-opening LSM session. This is also used for
2924 * other transition usecases which require dereg_sm and reg_sm.
Quinn Male2e883752019-03-22 11:28:54 -07002925 */
Quinn Malecc1affd2019-07-18 16:13:31 -07002926 if (hw_ses->lpi_enable != hw_ses->stdev->lpi_enable ||
2927 (hw_ses->barge_in_mode != hw_ses->stdev->barge_in_mode &&
2928 !hw_ses->stdev->support_dynamic_ec_update)) {
Quinn Male3d7d9d42019-05-20 13:35:01 -07002929 hw_ses->lpi_enable = hw_ses->stdev->lpi_enable;
Quinn Malecc1affd2019-07-18 16:13:31 -07002930 hw_ses->barge_in_mode = hw_ses->stdev->barge_in_mode;
Zhou Songcd3c8e62019-07-16 13:30:19 +08002931 do_unload = true;
Zhou Song388d0342020-02-16 16:31:05 +08002932 platform_stdev_reset_backend_cfg(hw_ses->stdev->platform);
Zhou Songcd3c8e62019-07-16 13:30:19 +08002933 }
2934
2935 /*
2936 * For gcs sessions, uid may be changed for new capture device,
2937 * in this case, sm must be dereg and reg again.
2938 */
2939 if (check_gcs_usecase_switch(st_ses))
2940 do_unload = true;
2941
2942 if (do_unload) {
Quinn Male2e883752019-03-22 11:28:54 -07002943 if (!load_sm) {
2944 load_sm = true;
Quinn Male58749452020-03-26 17:14:56 -07002945 status = dereg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002946 if (status)
2947 ALOGW("%s:[%d] failed to dereg_sm err %d", __func__,
2948 st_ses->sm_handle, status);
2949 }
2950 }
2951
2952 if (load_sm) {
Quinn Male58749452020-03-26 17:14:56 -07002953 status = reg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002954 if (status) {
2955 ALOGE("%s:[%d] failed to reg_sm err %d", __func__,
2956 st_ses->sm_handle, status);
2957 goto cleanup;
2958 }
2959 err |= HW_SES_ERR_MASK_REG_SM;
2960 }
2961
2962 status = hw_ses->fptrs->set_device(hw_ses, true);
2963 if (status) {
2964 ALOGE("%s:[%d] failed to set_device err %d", __func__,
2965 st_ses->sm_handle, status);
2966 goto cleanup;
2967 }
2968 err |= HW_SES_ERR_MASK_DEVICE_SET;
2969
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002970 status = hw_ses->fptrs->reg_sm_params(hw_ses, st_ses->recognition_mode,
Quinn Male58749452020-03-26 17:14:56 -07002971 st_ses->lab_enabled, st_ses->rc_config);
Quinn Male2e883752019-03-22 11:28:54 -07002972 if (status) {
2973 ALOGE("%s:[%d] failed to reg_sm_params err %d", __func__,
2974 st_ses->sm_handle, status);
2975 goto cleanup;
2976 }
2977 err |= HW_SES_ERR_MASK_REG_SM_PARAM;
2978
2979 status = hw_ses->fptrs->start(hw_ses);
2980 if (status) {
2981 ALOGE("%s:[%d] failed to start err %d", __func__,
2982 st_ses->sm_handle, status);
2983 goto cleanup;
2984 }
2985 err |= HW_SES_ERR_MASK_STARTED;
2986
2987 st_ses->hw_session_started = true;
2988 return status;
2989
2990cleanup:
2991 do_hw_sess_cleanup(st_ses, hw_ses, err);
2992 return status;
2993}
2994
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002995static int stop_hw_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
2996 bool unload_sm)
Quinn Male2e883752019-03-22 11:28:54 -07002997{
2998 int status = 0;
2999 int rc = 0;
3000
3001 status = hw_ses->fptrs->stop(hw_ses);
3002 if (status) {
3003 ALOGE("%s:[%d] failed to stop err %d", __func__,
3004 st_ses->sm_handle, status);
3005 rc = status;
3006 }
3007
3008 status = hw_ses->fptrs->dereg_sm_params(hw_ses);
3009 if (status) {
3010 ALOGE("%s:[%d] failed to dereg_sm_params err %d", __func__,
3011 st_ses->sm_handle, status);
3012 rc = status;
3013 }
3014
3015 status = hw_ses->fptrs->set_device(hw_ses, false);
3016 if (status) {
3017 ALOGE("%s:[%d] failed to set_device err %d", __func__,
3018 st_ses->sm_handle, status);
3019 rc = status;
3020 }
3021 if (unload_sm) {
Quinn Male58749452020-03-26 17:14:56 -07003022 status = dereg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07003023 if (status) {
3024 ALOGE("%s:[%d] failed to dereg_sm, err %d", __func__,
3025 st_ses->sm_handle, status);
3026 rc = status;
3027 }
3028 }
3029
3030 /* This must be set to false irrespective as the above calls may
3031 * return error (esp for SSR)
3032 */
3033 st_ses->hw_session_started = false;
3034 return rc;
3035}
3036
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003037static int start_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
3038 bool load_sm)
Quinn Male2e883752019-03-22 11:28:54 -07003039{
3040 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003041
Quinn Male2e883752019-03-22 11:28:54 -07003042 if (st_ses->hw_session_started) {
3043 ALOGE("%s:[%d] already started", __func__, st_ses->sm_handle);
3044 return -1;
3045 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003046
Quinn Male2e883752019-03-22 11:28:54 -07003047 status = start_hw_session(st_ses, hw_ses, load_sm);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003048 hw_ses->sthw_cfg_updated = false;
3049
Quinn Male2e883752019-03-22 11:28:54 -07003050 return status;
3051}
3052
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003053static int restart_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses)
Quinn Male2e883752019-03-22 11:28:54 -07003054{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003055 int status = 0;
3056
3057 status = hw_ses->fptrs->restart(hw_ses, st_ses->recognition_mode,
Quinn Male58749452020-03-26 17:14:56 -07003058 st_ses->rc_config);
Quinn Male2e883752019-03-22 11:28:54 -07003059 if (status == 0) {
3060 st_ses->hw_session_started = true;
3061 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003062 ALOGE("%s:[%d] failed to restart", __func__, st_ses->sm_handle);
Zhou Song944d8742019-09-26 16:22:06 +08003063 /*
3064 * lower layers like gcs/lsm need to handle double stop calls properly
3065 * to avoid possible crash, as some of the clean ups are already issued
3066 * during fptrs->restart() when it's failed.
3067 */
3068 stop_hw_session(st_ses, hw_ses, true);
Quinn Male2e883752019-03-22 11:28:54 -07003069 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003070
Quinn Male2e883752019-03-22 11:28:54 -07003071 return status;
3072}
3073
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003074static int stop_session(st_proxy_session_t *st_ses,
3075 st_hw_session_t *hw_ses, bool unload_sm)
Quinn Male2e883752019-03-22 11:28:54 -07003076{
3077 if (!st_ses->hw_session_started) {
3078 ALOGV("%s:[%d] already stopped", __func__, st_ses->sm_handle);
3079 return 0;
3080 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003081 st_ses->detection_requested = false;
Quinn Male2e883752019-03-22 11:28:54 -07003082 return stop_hw_session(st_ses, hw_ses, unload_sm);
3083}
3084
3085/*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003086 * This function gets the first stage detection keyword indices, which are
3087 * needed by the second stage sessions. If the legacy DSP is used, which does
3088 * not provide keyword indices, set the indices to include the entire keyword
3089 * duration. This function also gets the user confidence level if there is an
3090 * active voiceprint session.
Quinn Male2e883752019-03-22 11:28:54 -07003091 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003092static int get_first_stage_detection_params(st_proxy_session_t *st_ses,
3093 void *payload, size_t payload_size)
Quinn Male2e883752019-03-22 11:28:54 -07003094{
3095 size_t count_size = 0;
3096 uint8_t *payload_ptr = (uint8_t *)payload;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003097 uint8_t *cf_levels = NULL;
3098 uint32_t key_id = 0, key_payload_size = 0, cf_levels_size = 0;
Quinn Male2e883752019-03-22 11:28:54 -07003099 uint32_t kw_start_ms = 0, kw_end_ms = 0;
3100 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003101 struct listnode *node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07003102 st_arm_second_stage_t *st_sec_stage = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003103 st_session_t *stc_ses = st_ses->det_stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07003104 bool is_active_vop_session = false;
Quinn Male58749452020-03-26 17:14:56 -07003105 multi_model_result_info_t *result_info = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07003106
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003107 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07003108 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003109 if (st_sec_stage->ss_info->sm_detection_type ==
3110 ST_SM_TYPE_USER_VERIFICATION) {
Quinn Male2e883752019-03-22 11:28:54 -07003111 is_active_vop_session = true;
3112 break;
3113 }
3114 }
3115
3116 if (hw_ses->is_generic_event) {
3117 /*
3118 * This case is for the generic detection event from the DSP. Set the
3119 * keyword start and end indices and user confidence level based on key
3120 * id, if applicable.
3121 */
3122 while (count_size < payload_size) {
3123 key_id = *(uint32_t *)payload_ptr;
3124 key_payload_size = *((uint32_t *)payload_ptr + 1);
3125
3126 switch (key_id) {
Quinn Male58749452020-03-26 17:14:56 -07003127 case KEY_ID_MULTI_MODEL_RESULT_INFO:
3128 result_info = (multi_model_result_info_t *)(payload_ptr +
3129 GENERIC_DET_EVENT_HEADER_SIZE);
3130 hw_ses->kw_start_idx = result_info->keyword_start_idx_bytes;
3131 hw_ses->kw_end_idx = result_info->keyword_end_idx_bytes;
3132 break;
3133
Quinn Male2e883752019-03-22 11:28:54 -07003134 case KEY_ID_CONFIDENCE_LEVELS:
3135 if (is_active_vop_session) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003136 /*
3137 * It is expected that VoP is supported with single KW/user
3138 * SVA3.0 model, hence get it directly with hard offset.
3139 */
Quinn Male58749452020-03-26 17:14:56 -07003140 if (!st_ses->sm_merged) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003141 hw_ses->user_level = (int32_t)(*(payload_ptr +
3142 GENERIC_DET_EVENT_USER_LEVEL_OFFSET));
3143 } else {
3144 /* Extract from first stage merged conf levels */
3145 check_and_extract_det_conf_levels_payload(st_ses,
3146 payload_ptr + (4 * sizeof(uint32_t)),
3147 *((uint32_t *)payload_ptr + 3),
3148 &cf_levels, &cf_levels_size);
3149 if (!cf_levels || !cf_levels_size)
3150 break;
3151 hw_ses->user_level = cf_levels[1];
3152 ALOGV("%s:hw_ses->user_level %d at cf_levels[1]",
3153 __func__, hw_ses->user_level);
3154 }
Quinn Male2e883752019-03-22 11:28:54 -07003155 }
3156 break;
3157
3158 case KEY_ID_KEYWORD_POSITION_STATS:
3159 hw_ses->kw_start_idx = *((uint32_t *)payload_ptr +
3160 GENERIC_DET_EVENT_KW_START_OFFSET);
3161 hw_ses->kw_end_idx = *((uint32_t *)payload_ptr +
3162 GENERIC_DET_EVENT_KW_END_OFFSET);
3163 break;
3164
Quinn Male58749452020-03-26 17:14:56 -07003165 case KEY_ID_TIMESTAMP_INFO:
3166 /* No op */
3167 break;
3168
Quinn Male2e883752019-03-22 11:28:54 -07003169 default:
3170 ALOGW("%s: Unsupported generic detection event key id",
3171 __func__);
3172 break;
3173 }
3174 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Quinn Male58749452020-03-26 17:14:56 -07003175 payload_ptr += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Quinn Male2e883752019-03-22 11:28:54 -07003176 }
3177 } else {
3178 /*
3179 * This case is for the DSP detection events which are not the generic
3180 * detection event. There will be no keyword indices from first stage
3181 * detection, so the start index will be 0 and the end index will be the
3182 * buffer duration sent from the app. If this is not sent, the keyword
3183 * duration from platform xml will be used.
3184 */
3185 hw_ses->kw_start_idx = 0;
Quinn Male58749452020-03-26 17:14:56 -07003186 if (hw_ses->max_hist_buf) {
Quinn Male2e883752019-03-22 11:28:54 -07003187 hw_ses->kw_end_idx =
Quinn Male58749452020-03-26 17:14:56 -07003188 convert_ms_to_bytes(hw_ses->max_hist_buf,
Quinn Male2e883752019-03-22 11:28:54 -07003189 &hw_ses->config);
3190 } else {
3191 hw_ses->kw_end_idx =
3192 convert_ms_to_bytes(st_ses->vendor_uuid_info->kw_duration,
3193 &hw_ses->config);
3194 }
3195
3196 if (is_active_vop_session) {
Quinn Male9a345522020-03-12 17:49:25 -07003197 if (st_ses->exec_mode == ST_EXEC_MODE_CPE) {
Quinn Male2e883752019-03-22 11:28:54 -07003198 hw_ses->user_level = (int32_t)(*(payload_ptr +
3199 GCS_NON_GENERIC_USER_LEVEL_OFFSET));
Quinn Male9a345522020-03-12 17:49:25 -07003200 } else if (st_ses->exec_mode == ST_EXEC_MODE_ADSP) {
Quinn Male2e883752019-03-22 11:28:54 -07003201 hw_ses->user_level = (int32_t)(*(payload_ptr +
3202 LSM_NON_GENERIC_USER_LEVEL_OFFSET));
3203 }
3204 }
3205 }
3206
3207 kw_start_ms = convert_bytes_to_ms(hw_ses->kw_start_idx, &hw_ses->config);
3208 kw_end_ms = convert_bytes_to_ms(hw_ses->kw_end_idx, &hw_ses->config);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003209 ALOGD("%s:[%d] 1st stage kw_start = %dms, kw_end = %dms,"
3210 "is_generic_event %d", __func__, st_ses->sm_handle,
3211 kw_start_ms, kw_end_ms, hw_ses->is_generic_event);
Quinn Male2e883752019-03-22 11:28:54 -07003212
3213 return 0;
3214}
3215
Quinn Male12f5c6f2019-11-14 17:34:10 -08003216static inline int prepare_second_stage_for_client(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07003217{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003218 struct listnode *node = NULL;
3219 st_arm_second_stage_t *st_sec_stage = NULL;
3220 int status = 0;
3221
3222 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
3223
3224 list_for_each(node, &stc_ses->second_stage_list) {
3225 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
3226 status = st_second_stage_prepare_session(st_sec_stage);
3227 }
3228 return status;
3229}
3230
3231static inline int start_second_stage_for_client(st_session_t *stc_ses)
3232{
3233 struct listnode *node = NULL;
3234 st_arm_second_stage_t *st_sec_stage = NULL;
3235 int status = 0;
3236
3237 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
3238
3239 list_for_each(node, &stc_ses->second_stage_list) {
3240 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
3241 status = st_second_stage_start_session(st_sec_stage);
3242 }
3243 return status;
3244}
3245
3246static inline void stop_second_stage_for_client(st_session_t *stc_ses)
3247{
3248 struct listnode *node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07003249 st_arm_second_stage_t *st_sec_stage = NULL;
3250
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003251 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
3252
3253 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07003254 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
3255 st_second_stage_stop_session(st_sec_stage);
3256 }
3257}
3258
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003259static int generate_legacy_st_phrase_recognition_event
3260(
3261 const struct sound_trigger_phrase_sound_model *phrase_sm,
3262 const struct sound_trigger_recognition_config *rc_config,
3263 const void *payload,
3264 unsigned int payload_size,
3265 struct sound_trigger_phrase_recognition_event **out_rc_event
3266)
3267{
3268 struct sound_trigger_phrase_recognition_event *event;
3269 unsigned int i = 0, j = 0, user_id = 0;
3270
3271 ALOGD("%s: Enter payload_size %d", __func__, payload_size);
3272
3273 if(!payload || !phrase_sm || !rc_config || !out_rc_event) {
3274 ALOGE("%s: Null params", __func__);
3275 return -EINVAL;
3276 }
3277
3278 *out_rc_event = NULL;
3279 event = calloc(1, sizeof(*event) + payload_size);
3280 if (!event) {
3281 ALOGE("%s: event allocation failed size %d", __func__, payload_size);
3282 return -ENODEV;
3283 }
3284
3285 event->num_phrases = rc_config->num_phrases;
3286 event->common.data_offset = sizeof(*event);
3287 event->common.data_size = payload_size;
3288 memcpy((char *)event + event->common.data_offset, payload, payload_size);
3289
3290 /* fill confidence levels */
3291 for (i = 0; i < rc_config->num_phrases; i++) {
3292 event->phrase_extras[i].id = rc_config->phrases[i].id;
3293 event->phrase_extras[i].recognition_modes =
3294 phrase_sm->phrases[0].recognition_mode;
3295 event->phrase_extras[i].confidence_level = ((char *)payload)[i];
3296 event->phrase_extras[i].num_levels = rc_config->phrases[i].num_levels;
3297 for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
3298 user_id = rc_config->phrases[i].levels[j].user_id;
3299 event->phrase_extras[i].levels[j].user_id = user_id;
3300 event->phrase_extras[i].levels[j].level =
3301 ((char *)payload)[user_id];
3302 }
3303 }
3304
3305 *out_rc_event = event;
3306 return 0;
3307}
3308
3309/*
3310 * This function sets the opaque data size for the DSP's generic detection
3311 * events. This opaque data can now have varying size based on the requested
3312 * params.
3313 */
3314static size_t set_opaque_data_size(char *payload, size_t payload_size,
3315 uint32_t version)
3316{
3317 size_t count_size = 0, opaque_size = 0;
3318 uint32_t key_id = 0, key_payload_size = 0;
3319
3320 while (count_size < payload_size) {
3321 key_id = *(uint32_t *)payload;
3322 key_payload_size = *((uint32_t *)payload + 1);
3323
3324 switch (key_id) {
Quinn Male58749452020-03-26 17:14:56 -07003325 case KEY_ID_MULTI_MODEL_RESULT_INFO:
3326 opaque_size += sizeof(struct st_param_header);
3327 if (version != CONF_LEVELS_INTF_VERSION_0002) {
3328 opaque_size +=
3329 sizeof(struct st_confidence_levels_info);
3330 } else {
3331 opaque_size +=
3332 sizeof(struct st_confidence_levels_info_v2);
3333 }
3334
3335 opaque_size += sizeof(struct st_param_header) +
3336 sizeof(struct st_keyword_indices_info);
3337 opaque_size += sizeof(struct st_param_header) +
3338 sizeof(struct st_timestamp_info);
3339 break;
3340
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003341 case KEY_ID_CONFIDENCE_LEVELS:
3342 opaque_size += sizeof(struct st_param_header);
3343 if (version != CONF_LEVELS_INTF_VERSION_0002) {
3344 opaque_size +=
3345 sizeof(struct st_confidence_levels_info);
3346 } else {
3347 opaque_size +=
3348 sizeof(struct st_confidence_levels_info_v2);
3349 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003350 break;
3351
3352 case KEY_ID_KEYWORD_POSITION_STATS:
3353 opaque_size += sizeof(struct st_param_header) +
3354 sizeof(struct st_keyword_indices_info);
Quinn Male58749452020-03-26 17:14:56 -07003355 break;
3356
3357 case KEY_ID_TIMESTAMP_INFO:
3358 opaque_size += sizeof(struct st_param_header) +
3359 sizeof(struct st_timestamp_info);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003360 break;
3361
3362 default:
3363 ALOGE("%s: Unsupported generic detection event key id", __func__);
Quinn Male58749452020-03-26 17:14:56 -07003364 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003365 }
Quinn Male58749452020-03-26 17:14:56 -07003366 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
3367 payload += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003368 }
3369
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003370 return opaque_size;
3371}
3372
3373/*
3374 * This function packs the updated opaque data confidence levels which are
3375 * passed to the client via callback.
3376 */
3377static int pack_opaque_data_conf_levels(
3378 st_proxy_session_t *st_ses, void *opaque_data,
3379 uint8_t *payload,
3380 unsigned int payload_size)
3381{
3382 uint8_t *payload_ptr = payload;
3383 unsigned int i = 0, j = 0, k = 0, user_id = 0;
3384 st_arm_second_stage_t *st_sec_stage = NULL;
3385 struct listnode *node = NULL;
3386 struct st_confidence_levels_info *conf_levels = NULL;
3387 struct st_confidence_levels_info_v2 *conf_levels_v2 = NULL;
3388 st_session_t *stc_ses = st_ses->det_stc_ses;
3389 int32_t kw_level = 0, user_level = 0;
3390
3391 list_for_each(node, &stc_ses->second_stage_list) {
3392 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003393 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003394 kw_level = st_sec_stage->ss_session->confidence_score;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003395 } else if (IS_USER_VERIFICATION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003396 user_level = st_sec_stage->ss_session->confidence_score;
3397 }
3398 }
3399
3400 if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002) {
3401 conf_levels = (struct st_confidence_levels_info *)opaque_data;
3402 for (i = 0; i < conf_levels->num_sound_models; i++) {
3403 if (conf_levels->conf_levels[i].sm_id == ST_SM_ID_SVA_GMM) {
3404 for (j = 0;
3405 j < conf_levels->conf_levels[i].num_kw_levels; j++) {
3406 if (j <= payload_size)
3407 conf_levels->conf_levels[i].kw_levels[j].kw_level =
3408 payload_ptr[j];
3409 else
3410 ALOGE("%s: unexpected conf size %d < %d", __func__,
3411 payload_size, j);
3412 for (k = 0;
3413 k < conf_levels->conf_levels[i].kw_levels[j].num_user_levels;
3414 k++) {
3415 user_id =
3416 conf_levels->conf_levels[i].kw_levels[j].
3417 user_levels[k].user_id;
3418 if (user_id <= payload_size)
3419 conf_levels->conf_levels[i].kw_levels[j].
3420 user_levels[k].level = payload_ptr[user_id];
3421 else
3422 ALOGE("%s: Unexpected conf size %d < %d", __func__,
3423 payload_size, user_id);
3424 }
3425 }
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003426 } else if (IS_KEYWORD_DETECTION_MODEL(conf_levels->conf_levels[i].sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003427 conf_levels->conf_levels[i].kw_levels[0].kw_level = kw_level;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003428 } else if (IS_USER_VERIFICATION_MODEL(conf_levels->conf_levels[i].sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003429 /*
3430 * Fill both the keyword and user confidence level with the
3431 * confidence score returned from the voiceprint algorithm.
3432 */
3433 conf_levels->conf_levels[i].kw_levels[0].kw_level =
3434 (uint8_t)user_level;
3435 conf_levels->conf_levels[i].kw_levels[0].user_levels[0].level =
3436 (uint8_t)user_level;
3437 }
3438 }
3439 } else {
3440 conf_levels_v2 = (struct st_confidence_levels_info_v2 *)opaque_data;
3441 for (i = 0; i < conf_levels_v2->num_sound_models; i++) {
3442 if (conf_levels_v2->conf_levels[i].sm_id == ST_SM_ID_SVA_GMM) {
3443 for (j = 0;
3444 j < conf_levels_v2->conf_levels[i].num_kw_levels; j++) {
3445 if (j <= payload_size)
3446 conf_levels_v2->conf_levels[i].kw_levels[j].kw_level =
3447 payload_ptr[j];
3448 else
3449 ALOGE("%s: unexpected conf size %d < %d", __func__,
3450 payload_size, j);
3451
3452 for (k = 0;
3453 k < conf_levels_v2->conf_levels[i].kw_levels[j].num_user_levels;
3454 k++) {
3455 user_id =
3456 conf_levels_v2->conf_levels[i].kw_levels[j].
3457 user_levels[k].user_id;
3458 if (user_id <= payload_size)
3459 conf_levels_v2->conf_levels[i].kw_levels[j].
3460 user_levels[k].level = payload_ptr[user_id];
3461 else
3462 ALOGE("%s: Unexpected conf size %d < %d", __func__,
3463 payload_size, user_id);
3464 }
3465 }
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003466 } else if (IS_KEYWORD_DETECTION_MODEL(conf_levels_v2->conf_levels[i].sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003467 conf_levels_v2->conf_levels[i].kw_levels[0].kw_level = kw_level;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003468 } else if (IS_USER_VERIFICATION_MODEL(conf_levels_v2->conf_levels[i].sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003469 /*
3470 * Fill both the keyword and user confidence level with the
3471 * confidence score returned from the voiceprint algorithm.
3472 */
3473 conf_levels_v2->conf_levels[i].kw_levels[0].kw_level =
3474 user_level;
3475 conf_levels_v2->conf_levels[i].kw_levels[0].user_levels[0].level =
3476 user_level;
3477 }
3478 }
3479 }
3480
3481 return 0;
3482}
3483
3484/* This function packs the sound trigger API confidence levels */
3485static int pack_recognition_event_conf_levels(
3486 st_proxy_session_t *st_ses, uint8_t *payload,
3487 unsigned int payload_size,
3488 struct sound_trigger_phrase_recognition_event *local_event)
3489{
3490 unsigned int j = 0, k = 0, user_id = 0;
3491 st_arm_second_stage_t *st_sec_stage = NULL;
3492 struct listnode *node = NULL;
3493 st_session_t *stc_ses = st_ses->det_stc_ses;
3494 struct sound_trigger_phrase_sound_model *phrase_sm =
3495 (struct sound_trigger_phrase_sound_model *)stc_ses->phrase_sm;
3496
3497 /*
3498 * Fill in the GMM confidence levels to the sound trigger recognition event
3499 * APIs first. If any second stage session is enabled, overwrite the APIs
3500 * with the second stage confidence levels.
3501 */
3502 for (j = 0; j < stc_ses->rc_config->num_phrases; j++) {
3503 local_event->phrase_extras[j].id = stc_ses->rc_config->phrases[j].id;
3504 local_event->phrase_extras[j].recognition_modes =
3505 phrase_sm->phrases[j].recognition_mode;
3506 local_event->phrase_extras[j].num_levels =
3507 stc_ses->rc_config->phrases[j].num_levels;
3508 if (j <= payload_size)
3509 local_event->phrase_extras[j].confidence_level = payload[j];
3510 else
3511 ALOGE("%s: unexpected conf size %d < %d", __func__,
3512 payload_size, j);
3513
3514 for (k = 0; k < stc_ses->rc_config->phrases[j].num_levels; k++) {
3515 user_id = stc_ses->rc_config->phrases[j].levels[k].user_id;
3516 if (user_id <= payload_size) {
3517 local_event->phrase_extras[j].levels[k].user_id = user_id;
3518 local_event->phrase_extras[j].levels[k].level =
3519 payload[user_id];
3520 } else {
3521 ALOGE("%s: Unexpected conf size %d < %d", __func__,
3522 payload_size, user_id);
3523 }
3524 }
3525 }
3526
3527 list_for_each(node, &stc_ses->second_stage_list) {
3528 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003529 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003530 local_event->phrase_extras[0].confidence_level =
3531 (uint8_t)st_sec_stage->ss_session->confidence_score;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003532 } else if (IS_USER_VERIFICATION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003533 local_event->phrase_extras[0].levels[0].level =
3534 (uint8_t)st_sec_stage->ss_session->confidence_score;
3535 }
3536 }
3537 return 0;
3538}
3539
3540static int parse_generic_event_and_pack_opaque_data(
3541 st_proxy_session_t *st_ses, uint8_t *opaque_data,
3542 uint8_t *payload, size_t payload_size,
3543 struct sound_trigger_phrase_recognition_event *local_event)
3544{
3545 uint32_t key_id = 0, key_payload_size = 0;
Quinn Male58749452020-03-26 17:14:56 -07003546 uint32_t timestamp_msw = 0, timestamp_lsw = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003547 struct st_param_header *param_hdr = NULL;
3548 struct st_keyword_indices_info *kw_indices = NULL;
3549 struct st_timestamp_info *timestamps = NULL;
3550 size_t count_size = 0;
3551 st_arm_second_stage_t *st_sec_stage = NULL;
3552 struct listnode *node = NULL;
3553 st_session_t *stc_ses = st_ses->det_stc_ses;
3554 int status = 0;
3555 unsigned char *cf_levels = NULL;
3556 unsigned int cf_levels_size = 0;
Quinn Male58749452020-03-26 17:14:56 -07003557 multi_model_result_info_t *result_info = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003558
3559 while (count_size < payload_size) {
3560 key_id = *(uint32_t *)payload;
3561 key_payload_size = *((uint32_t *)payload + 1);
3562
3563 switch (key_id) {
Quinn Male58749452020-03-26 17:14:56 -07003564 case KEY_ID_MULTI_MODEL_RESULT_INFO:
3565 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
3566 ALOGE("%s: Error. Multi sm result info supported on PDK5 only",
3567 __func__);
3568 status = -EINVAL;
3569 goto exit;
3570 }
3571 /* Set confidence levels */
3572 param_hdr = (struct st_param_header *)opaque_data;
3573 param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
3574 opaque_data += sizeof(struct st_param_header);
3575 if (stc_ses->conf_levels_intf_version !=
3576 CONF_LEVELS_INTF_VERSION_0002) {
3577 param_hdr->payload_size =
3578 sizeof(struct st_confidence_levels_info);
3579 } else {
3580 param_hdr->payload_size =
3581 sizeof(struct st_confidence_levels_info_v2);
3582 }
3583 result_info = (multi_model_result_info_t *)(payload +
3584 GENERIC_DET_EVENT_HEADER_SIZE);
3585
3586 memset(stc_ses->sm_info.det_cf_levels, 0,
3587 MAX_MULTI_SM_CONF_LEVELS);
3588
3589 cf_levels = stc_ses->sm_info.det_cf_levels;
3590 cf_levels_size = stc_ses->sm_info.cf_levels_size;
3591 memcpy(opaque_data, stc_ses->st_conf_levels,
3592 param_hdr->payload_size);
3593 *(cf_levels + result_info->detected_keyword_id) =
3594 result_info->best_confidence_level;
3595 pack_opaque_data_conf_levels(st_ses, opaque_data,
3596 cf_levels, cf_levels_size);
3597 pack_recognition_event_conf_levels(st_ses, cf_levels,
3598 cf_levels_size, local_event);
3599 opaque_data += param_hdr->payload_size;
3600
3601 /* Set keyword indices */
3602 param_hdr = (struct st_param_header *)opaque_data;
3603 param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
3604 param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
3605 opaque_data += sizeof(struct st_param_header);
3606 kw_indices = (struct st_keyword_indices_info *)opaque_data;
3607 kw_indices->version = 0x1;
3608 kw_indices->start_index = result_info->keyword_start_idx_bytes;
3609 kw_indices->end_index = result_info->keyword_end_idx_bytes;
3610
3611 list_for_each(node, &stc_ses->second_stage_list) {
3612 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
3613 list_node);
3614 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
3615 kw_indices->start_index =
3616 st_sec_stage->ss_session->kw_start_idx;
3617 kw_indices->end_index =
3618 st_sec_stage->ss_session->kw_end_idx;
3619 }
3620 }
3621 opaque_data += sizeof(struct st_keyword_indices_info);
3622
3623 /* Set timestamp */
3624 param_hdr = (struct st_param_header *)opaque_data;
3625 param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
3626 param_hdr->payload_size = sizeof(struct st_timestamp_info);
3627 opaque_data += sizeof(struct st_param_header);
3628 timestamps = (struct st_timestamp_info *)opaque_data;
3629 timestamps->version = 0x1;
3630 timestamps->first_stage_det_event_time =
3631 (uint64_t)result_info->timestamp_msw_us << 32 |
3632 result_info->timestamp_lsw_us;
3633 if (!list_empty(&stc_ses->second_stage_list))
3634 timestamps->second_stage_det_event_time =
3635 st_ses->hw_ses_current->second_stage_det_event_time;
3636 opaque_data += sizeof(struct st_timestamp_info);
3637 break;
3638
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003639 case KEY_ID_CONFIDENCE_LEVELS:
3640 /* Pack the opaque data confidence levels structure */
Quinn Male58749452020-03-26 17:14:56 -07003641 param_hdr = (struct st_param_header *)opaque_data;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003642 param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
3643 opaque_data += sizeof(struct st_param_header);
3644 if (stc_ses->conf_levels_intf_version !=
3645 CONF_LEVELS_INTF_VERSION_0002) {
3646 param_hdr->payload_size =
3647 sizeof(struct st_confidence_levels_info);
3648 } else {
3649 param_hdr->payload_size =
3650 sizeof(struct st_confidence_levels_info_v2);
3651 }
3652 check_and_extract_det_conf_levels_payload(st_ses,
3653 payload + (4 * sizeof(uint32_t)), *((uint32_t *)payload + 3),
3654 &cf_levels, &cf_levels_size);
3655 if (!cf_levels || !cf_levels_size) {
3656 status = -EINVAL;
3657 goto exit;
3658 }
3659 memcpy(opaque_data, stc_ses->st_conf_levels,
3660 param_hdr->payload_size);
3661 pack_opaque_data_conf_levels(st_ses, opaque_data,
3662 cf_levels, cf_levels_size);
3663 pack_recognition_event_conf_levels(st_ses, cf_levels,
3664 cf_levels_size, local_event);
3665 opaque_data += param_hdr->payload_size;
3666 break;
3667
3668 case KEY_ID_KEYWORD_POSITION_STATS:
3669 /* Pack the opaque data keyword indices structure */
Quinn Male58749452020-03-26 17:14:56 -07003670 param_hdr = (struct st_param_header *)opaque_data;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003671 param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
3672 param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
3673 opaque_data += sizeof(struct st_param_header);
Quinn Male58749452020-03-26 17:14:56 -07003674 kw_indices = (struct st_keyword_indices_info *)opaque_data;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003675 kw_indices->version = 0x1;
3676 kw_indices->start_index = *((uint32_t *)payload + 3);
3677 kw_indices->end_index = *((uint32_t *)payload + 4);
3678
3679 list_for_each(node, &stc_ses->second_stage_list) {
3680 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
3681 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003682 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003683 kw_indices->start_index =
3684 st_sec_stage->ss_session->kw_start_idx;
3685 kw_indices->end_index =
3686 st_sec_stage->ss_session->kw_end_idx;
3687 }
3688 }
3689 opaque_data += sizeof(struct st_keyword_indices_info);
3690 break;
3691
Quinn Male58749452020-03-26 17:14:56 -07003692 case KEY_ID_TIMESTAMP_INFO:
3693 /* Pack the opaque data detection timestamp structure */
3694 param_hdr = (struct st_param_header *)opaque_data;
3695 param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
3696 param_hdr->payload_size = sizeof(struct st_timestamp_info);
3697 opaque_data += sizeof(struct st_param_header);
3698 timestamp_lsw = *((uint32_t *)payload + 3);
3699 timestamp_msw = *((uint32_t *)payload + 4);
3700 timestamps = (struct st_timestamp_info *)opaque_data;
3701 timestamps->version = 0x1;
3702 timestamps->first_stage_det_event_time =
3703 (uint64_t)timestamp_msw << 32 | timestamp_lsw;
3704 if (!list_empty(&stc_ses->second_stage_list))
3705 timestamps->second_stage_det_event_time =
3706 st_ses->hw_ses_current->second_stage_det_event_time;
3707 opaque_data += sizeof(struct st_timestamp_info);
3708 break;
3709
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003710 default:
3711 ALOGE("%s: Unsupported generic detection event key id", __func__);
3712 status = -EINVAL;
3713 goto exit;
3714 }
3715 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Quinn Male58749452020-03-26 17:14:56 -07003716 payload += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003717 }
3718
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003719exit:
3720 return status;
3721}
3722
3723static int parse_generic_event_without_opaque_data(
3724 st_proxy_session_t *st_ses, uint8_t *payload, size_t payload_size,
3725 struct sound_trigger_phrase_recognition_event *local_event)
3726{
3727 uint32_t key_id = 0, key_payload_size = 0;
3728 size_t count_size = 0;
3729 int status = 0;
3730 unsigned char *cf_levels = NULL;
Quinn Male58749452020-03-26 17:14:56 -07003731 unsigned int cf_levels_size = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003732
3733 while (count_size < payload_size) {
3734 key_id = *(uint32_t *)payload;
3735 key_payload_size = *((uint32_t *)payload + 1);
3736
3737 switch (key_id) {
3738 case KEY_ID_CONFIDENCE_LEVELS:
3739 check_and_extract_det_conf_levels_payload(st_ses,
3740 payload + (4 * sizeof(uint32_t)), *((uint32_t *)payload + 3),
3741 &cf_levels, &cf_levels_size);
3742 if (!cf_levels || !cf_levels_size) {
3743 status = -EINVAL;
3744 return status;
3745 }
3746 pack_recognition_event_conf_levels(st_ses, cf_levels,
3747 cf_levels_size, local_event);
3748 return status;
3749
3750 case KEY_ID_KEYWORD_POSITION_STATS:
3751 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Quinn Male58749452020-03-26 17:14:56 -07003752 payload += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
3753 break;
3754
3755 case KEY_ID_TIMESTAMP_INFO:
3756 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
3757 payload += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003758 break;
3759
3760 default:
3761 ALOGE("%s: Unsupported generic detection event key id", __func__);
3762 status = -EINVAL;
3763 return status;
3764 }
3765 }
3766 return status;
3767}
3768
3769/*
3770 * This function handles detection payloads in the format of the DSP's
3771 * generic detection event.
3772 */
3773int process_detection_event_keyphrase_v2(
3774 st_proxy_session_t *st_ses, int detect_status,
3775 void *payload, size_t payload_size,
3776 struct sound_trigger_phrase_recognition_event **event)
3777{
3778 st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
3779 st_session_t *stc_ses = st_ses->det_stc_ses;
3780 unsigned int i = 0, j = 0;
3781 int status = 0;
3782 uint8_t *opaque_data = NULL;
3783 size_t opaque_size = 0;
3784 struct sound_trigger_phrase_recognition_event *local_event = NULL;
3785
3786 if (st_ses->vendor_uuid_info->is_qcva_uuid)
3787 opaque_size = set_opaque_data_size(payload, payload_size,
3788 stc_ses->conf_levels_intf_version);
3789 else
3790 opaque_size = payload_size;
3791
3792 local_event = calloc(1,
3793 sizeof(struct sound_trigger_phrase_recognition_event) + opaque_size);
3794 if (!local_event) {
3795 ALOGE("%s: local_event allocation failed, opaque data size = %d",
3796 __func__, (unsigned int)opaque_size);
3797 return -ENOMEM;
3798 }
3799
3800 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3801 local_event->common.data_offset =
3802 sizeof(struct sound_trigger_phrase_recognition_event);
3803 local_event->common.data_size = opaque_size;
3804 opaque_data = (uint8_t *)local_event + local_event->common.data_offset;
3805
3806 if (st_ses->vendor_uuid_info->is_qcva_uuid) {
3807 if (stc_ses->rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) {
3808 status = parse_generic_event_and_pack_opaque_data(st_ses,
3809 opaque_data, payload, payload_size, local_event);
3810 if (status) {
3811 ALOGE("%s: Failed to parse generic detection event with opaque"
3812 "data %d", __func__, status);
3813 goto exit;
3814 }
3815
Quinn Maleaba13db2019-07-11 15:52:14 -07003816 if (st_ses->stdev->enable_debug_dumps) {
3817 ST_DBG_DECLARE(FILE *opaque_fd = NULL;
3818 static int opaque_cnt = 0);
3819 ST_DBG_FILE_OPEN_WR(opaque_fd, ST_DEBUG_DUMP_LOCATION,
3820 "detection_opaque_data", "bin", opaque_cnt++);
3821 ST_DBG_FILE_WRITE(opaque_fd, opaque_data, opaque_size);
3822 ST_DBG_FILE_CLOSE(opaque_fd);
3823 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003824 } else {
3825 status = parse_generic_event_without_opaque_data(st_ses, payload,
3826 payload_size, local_event);
3827 if (status) {
3828 ALOGE("%s: Failed to parse generic detection event without"
3829 "opaque data %d", __func__, status);
3830 goto exit;
3831 }
3832 }
3833 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003834 memcpy(local_event->phrase_extras,
3835 stc_ses->rc_config->phrases, stc_ses->rc_config->num_phrases *
3836 sizeof(struct sound_trigger_phrase_recognition_extra));
3837 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3838 local_event->common.data_offset = sizeof(*local_event);
3839 local_event->common.data_size = opaque_size;
3840 memcpy(opaque_data, payload, opaque_size);
3841 opaque_data += opaque_size;
3842 }
3843
3844 /*
3845 * fill the remaining recognition event parameters not specific
3846 * to soundmodel lib
3847 */
3848 local_event->common.status = detect_status;
3849 local_event->common.type = stc_ses->phrase_sm->common.type;
3850 local_event->common.model = stc_ses->sm_handle;
3851 local_event->common.capture_available =
3852 stc_ses->rc_config->capture_requested;
3853 local_event->common.capture_delay_ms = 0;
3854 local_event->common.capture_preamble_ms = 0;
3855 local_event->common.audio_config.sample_rate =
3856 SOUND_TRIGGER_SAMPLING_RATE_16000;
3857 local_event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
3858 local_event->common.audio_config.channel_mask =
3859 audio_channel_in_mask_from_count(st_hw_ses->config.channels);
3860
3861 for (i = 0; i < local_event->num_phrases; ++i) {
3862 ALOGV("%s: [%d] kw_id %d level %d", __func__, i,
3863 local_event->phrase_extras[i].id,
3864 local_event->phrase_extras[i].confidence_level);
3865 for (j = 0; j < local_event->phrase_extras[i].num_levels; ++j) {
3866 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
3867 local_event->phrase_extras[i].levels[j].user_id,
3868 local_event->phrase_extras[i].levels[j].level);
3869 }
3870 }
3871
3872 ALOGI("%s:[c%d]", __func__, stc_ses->sm_handle);
3873
3874 ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
3875 "num_phrases=%d id=%d", __func__, stc_ses->sm_handle,
3876 local_event->common.status, local_event->common.type,
3877 local_event->common.model, local_event->common.capture_available,
3878 local_event->num_phrases, local_event->phrase_extras[0].id);
3879
3880 *event = local_event;
3881 return 0;
3882
3883exit:
3884 if (local_event)
3885 free(local_event);
3886 return status;
3887}
3888
3889/*
3890 * This function handles detection payloads in the format of the DSP's
3891 * legacy (non-generic) detection event.
3892 * TODO: Deprecate this when DSP for all shared targets of this component
3893 * move to generic event.
3894 */
3895static int process_detection_event_keyphrase(
3896 st_proxy_session_t *st_ses, int detect_status,
3897 void *payload, size_t payload_size,
3898 struct sound_trigger_phrase_recognition_event **event)
3899{
3900 st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
3901 st_session_t *stc_ses = st_ses->det_stc_ses;
3902 unsigned int i = 0, j = 0;
3903 int status = 0;
3904 struct sound_trigger_phrase_recognition_event *local_event = NULL;
3905 size_t opaque_size = 0;
3906 uint8_t *opaque_data = NULL, *payload_ptr = NULL;
3907 struct st_param_header *param_hdr = NULL;
3908 st_arm_second_stage_t *st_sec_stage = NULL;
3909 struct listnode *node = NULL;
3910 struct st_keyword_indices_info *kw_indices = NULL;
3911 struct st_timestamp_info *timestamps = NULL;
3912 bool enable_kw_indices = false;
3913 unsigned char *cf_levels = NULL;
3914 unsigned int cf_levels_size = 0;
3915
3916 if ((stc_ses->rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
3917 st_ses->vendor_uuid_info->is_qcva_uuid) {
3918 /*
3919 * This logic is for the updated opaque data format. Sound trigger
3920 * recognition event APIs are filled along with the opaque data's
3921 * confidence levels, keyword indices, and timestamp parameters.
3922 */
3923 opaque_size = (2 * sizeof(struct st_param_header)) +
3924 sizeof(struct st_timestamp_info);
3925 if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002)
3926 opaque_size += sizeof(struct st_confidence_levels_info);
3927 else
3928 opaque_size += sizeof(struct st_confidence_levels_info_v2);
3929
3930 list_for_each(node, &stc_ses->second_stage_list) {
3931 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003932 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003933 enable_kw_indices = true;
3934 opaque_size += sizeof(struct st_param_header) +
3935 sizeof(struct st_keyword_indices_info);
3936 break;
3937 }
3938 }
3939
3940 local_event = calloc(1,
3941 sizeof(struct sound_trigger_phrase_recognition_event) +
3942 opaque_size);
3943 if (!local_event) {
3944 ALOGE("%s: local_event allocation failed, opaque data size = %d",
3945 __func__, (unsigned int)opaque_size);
3946 return -ENOMEM;
3947 }
3948
3949 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3950 local_event->common.data_offset =
3951 sizeof(struct sound_trigger_phrase_recognition_event);
3952 local_event->common.data_size = opaque_size;
3953 opaque_data = (uint8_t *)local_event + local_event->common.data_offset;
Quinn Male9a345522020-03-12 17:49:25 -07003954 if (st_ses->exec_mode == ST_EXEC_MODE_CPE) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003955 payload_ptr = (uint8_t *)payload + 2;
3956 payload_size -= 2; /* Re-use */
Quinn Male9a345522020-03-12 17:49:25 -07003957 } else if (st_ses->exec_mode == ST_EXEC_MODE_ADSP) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003958 payload_ptr = (uint8_t *)payload;
3959 } else {
3960 ALOGE("%s: Invalid execution mode, exiting", __func__);
3961 status = -EINVAL;
3962 goto err_exit;
3963 }
3964
3965 /* Pack the opaque data confidence levels structure */
3966 param_hdr = (struct st_param_header *)opaque_data;
3967 param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
3968 opaque_data += sizeof(struct st_param_header);
3969 if (stc_ses->conf_levels_intf_version !=
3970 CONF_LEVELS_INTF_VERSION_0002) {
3971 param_hdr->payload_size =
3972 sizeof(struct st_confidence_levels_info);
3973 } else {
3974 param_hdr->payload_size =
3975 sizeof(struct st_confidence_levels_info_v2);
3976 }
3977 check_and_extract_det_conf_levels_payload(st_ses, payload_ptr,
3978 payload_size, &cf_levels, &cf_levels_size);
3979 if (!cf_levels || !cf_levels_size) {
3980 status = -EINVAL;
3981 goto err_exit;
3982 }
3983 memcpy(opaque_data, stc_ses->st_conf_levels, param_hdr->payload_size);
3984 pack_opaque_data_conf_levels(st_ses, opaque_data, cf_levels,
3985 cf_levels_size);
3986 pack_recognition_event_conf_levels(st_ses, cf_levels, cf_levels_size,
3987 local_event);
3988 opaque_data += param_hdr->payload_size;
3989
3990 /* Pack the opaque data keyword indices structure */
3991 if (enable_kw_indices) {
3992 param_hdr = (struct st_param_header *)opaque_data;
3993 param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
3994 param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
3995 opaque_data += sizeof(struct st_param_header);
3996 kw_indices = (struct st_keyword_indices_info *)opaque_data;
3997 kw_indices->version = 0x1;
3998 list_for_each(node, &stc_ses->second_stage_list) {
3999 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
4000 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07004001 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004002 kw_indices->start_index =
4003 st_sec_stage->ss_session->kw_start_idx;
4004 kw_indices->end_index =
4005 st_sec_stage->ss_session->kw_end_idx;
4006 }
4007 }
4008 opaque_data += sizeof(struct st_keyword_indices_info);
4009 }
4010
4011 /* Pack the opaque data detection timestamp structure */
4012 param_hdr = (struct st_param_header *)opaque_data;
4013 param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
4014 param_hdr->payload_size = sizeof(struct st_timestamp_info);
4015 opaque_data += sizeof(struct st_param_header);
4016 timestamps = (struct st_timestamp_info *)opaque_data;
4017 timestamps->version = 0x1;
4018 timestamps->first_stage_det_event_time =
4019 st_hw_ses->first_stage_det_event_time;
4020 if (!list_empty(&stc_ses->second_stage_list))
4021 timestamps->second_stage_det_event_time =
4022 st_hw_ses->second_stage_det_event_time;
4023 opaque_data += sizeof(struct st_timestamp_info);
4024
Quinn Maleaba13db2019-07-11 15:52:14 -07004025 if (st_ses->stdev->enable_debug_dumps) {
4026 ST_DBG_DECLARE(FILE *opaque_fd = NULL; static int opaque_cnt = 0);
4027 ST_DBG_FILE_OPEN_WR(opaque_fd, ST_DEBUG_DUMP_LOCATION,
4028 "detection_opaque_data", "bin", opaque_cnt++);
4029 ST_DBG_FILE_WRITE(opaque_fd, (opaque_data - opaque_size),
4030 opaque_size);
4031 ST_DBG_FILE_CLOSE(opaque_fd);
4032 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004033
4034 } else {
4035 if (st_ses->vendor_uuid_info->is_qcva_uuid ||
4036 st_ses->vendor_uuid_info->is_qcmd_uuid) {
Quinn Male9a345522020-03-12 17:49:25 -07004037 if (ST_EXEC_MODE_CPE == st_ses->exec_mode &&
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004038 !st_hw_ses->is_generic_event) {
4039 payload_ptr = payload;
4040 payload_ptr += 2; /* Skip minor_version and num_active_models */
4041 payload_size -= 2;
4042 } else {
4043 payload_ptr = payload;
4044 }
4045 status = generate_legacy_st_phrase_recognition_event(
4046 stc_ses->phrase_sm, stc_ses->rc_config, payload_ptr,
4047 payload_size, &local_event);
4048
4049 if (status)
4050 goto exit;
4051 } else {
4052 ALOGD("%s: Send detection payload as is", __func__);
4053
4054 local_event = calloc(1, sizeof(*local_event) + payload_size);
4055 if (!local_event) {
4056 ALOGE("%s: event allocation failed, size %zd", __func__,
4057 payload_size);
4058 status = -ENOMEM;
4059 goto exit;
4060 }
4061 memcpy(local_event->phrase_extras,
4062 stc_ses->rc_config->phrases, stc_ses->rc_config->num_phrases *
4063 sizeof(struct sound_trigger_phrase_recognition_extra));
4064 local_event->num_phrases = stc_ses->rc_config->num_phrases;
4065 local_event->common.data_offset = sizeof(*local_event);
4066 local_event->common.data_size = payload_size;
4067 memcpy((char *)local_event + local_event->common.data_offset,
4068 payload, payload_size);
4069 }
4070 }
4071
4072 /* fill the remaining recognition event parameters not specific
4073 to soundmodel lib */
4074 local_event->common.status = detect_status;
4075 local_event->common.type = stc_ses->phrase_sm->common.type;
4076 local_event->common.model = stc_ses->sm_handle;
4077 local_event->common.capture_available =
4078 stc_ses->rc_config->capture_requested;
4079 local_event->common.capture_delay_ms = 0;
4080 local_event->common.capture_preamble_ms = 0;
4081 local_event->common.audio_config.sample_rate =
4082 SOUND_TRIGGER_SAMPLING_RATE_16000;
4083 local_event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
4084 local_event->common.audio_config.channel_mask =
4085 audio_channel_in_mask_from_count(st_hw_ses->config.channels);
4086
4087 for (i = 0; i < local_event->num_phrases; ++i) {
4088 ALOGV("%s: [%d] kw_id %d level %d", __func__, i,
4089 local_event->phrase_extras[i].id,
4090 local_event->phrase_extras[i].confidence_level);
4091 for (j = 0; j < local_event->phrase_extras[i].num_levels; ++j) {
4092 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
4093 local_event->phrase_extras[i].levels[j].user_id,
4094 local_event->phrase_extras[i].levels[j].level);
4095 }
4096 }
4097
4098 ALOGI("%s:[c%d]", __func__, stc_ses->sm_handle);
4099
4100 ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
4101 "num_phrases=%d id=%d", __func__, stc_ses->sm_handle,
4102 local_event->common.status, local_event->common.type,
4103 local_event->common.model, local_event->common.capture_available,
4104 local_event->num_phrases, local_event->phrase_extras[0].id);
4105
4106 *event = local_event;
4107 return 0;
4108
4109err_exit:
4110 if (local_event)
4111 free(local_event);
4112
4113exit:
4114 return status;
4115}
4116
4117static int process_detection_event_generic(st_proxy_session_t *st_ses,
4118 int detect_status,
4119 void *payload, size_t payload_size,
4120 struct sound_trigger_recognition_event **event)
4121{
4122 st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
4123 st_session_t *stc_ses = st_ses->det_stc_ses;
4124 struct st_vendor_info *v_info = st_ses->vendor_uuid_info;
4125 int status = 0;
4126 struct sound_trigger_recognition_event *local_event = NULL;
4127
4128 local_event = calloc(1, sizeof(*local_event) + payload_size);
4129 if (!local_event) {
4130 ALOGE("%s: event allocation failed, size %zd", __func__,
4131 payload_size);
4132 status = -ENOMEM;
4133 goto exit;
4134 }
4135
4136 local_event->status = detect_status;
4137 local_event->type = stc_ses->sm_type;
4138 local_event->model = stc_ses->sm_handle;
4139 local_event->capture_available = stc_ses->rc_config->capture_requested;
4140 local_event->capture_delay_ms = 0;
4141 local_event->capture_preamble_ms = 0;
4142 local_event->audio_config.sample_rate = v_info ?
4143 v_info->sample_rate : SOUND_TRIGGER_SAMPLING_RATE_16000;
4144 local_event->audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
4145 local_event->audio_config.channel_mask =
4146 audio_channel_in_mask_from_count(st_hw_ses->config.channels);
4147
4148 local_event->data_offset = sizeof(*local_event);
4149 local_event->data_size = payload_size;
4150 memcpy((char *)local_event + local_event->data_offset,
4151 payload, payload_size);
4152
4153 ALOGI("%s:[%d]", __func__, stc_ses->sm_handle);
4154 ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d",
4155 __func__, stc_ses->sm_handle, local_event->status,
4156 local_event->type, local_event->model,
4157 local_event->capture_available);
4158
4159 *event = local_event;
4160
4161exit:
4162 return status;
4163}
4164
4165static inline int process_detection_event(st_proxy_session_t *st_ses,
4166 uint64_t timestamp __unused,
4167 int detect_status,
4168 void *payload, size_t payload_size,
4169 struct sound_trigger_recognition_event **event)
4170{
4171 int ret;
4172 struct sound_trigger_phrase_recognition_event *phrase_event = NULL;
4173
4174 *event = NULL;
Quinn Male58749452020-03-26 17:14:56 -07004175 if (st_ses->det_stc_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004176 if (sthw_extn_check_process_det_ev_support())
4177 ret = sthw_extn_process_detection_event_keyphrase(st_ses,
4178 timestamp, detect_status, payload, payload_size, &phrase_event);
4179 else if (st_ses->hw_ses_current->is_generic_event &&
4180 !st_ses->vendor_uuid_info->is_qcmd_uuid)
4181 ret = process_detection_event_keyphrase_v2(st_ses, detect_status,
4182 payload, payload_size, &phrase_event);
4183 else
4184 ret = process_detection_event_keyphrase(st_ses, detect_status,
4185 payload, payload_size, &phrase_event);
4186 if (phrase_event)
4187 *event = &phrase_event->common;
4188 } else {
4189 ret = process_detection_event_generic(st_ses, detect_status, payload,
4190 payload_size, event);
4191 }
4192 return ret;
4193}
4194
4195
4196/*
4197 * If the keyword detection session detects before the user verification
4198 * session, signal to process user verification. If the keyword detection
4199 * session rejects before the user verification session, signal to stop
4200 * processing user verification.
4201 */
4202static void handle_vop_pending_detection(st_arm_ss_session_t *ss_session,
4203 unsigned int det_status, unsigned int kw_det_buff_sz)
4204{
4205 if (det_status & KEYWORD_DETECTION_SUCCESS) {
4206 if (kw_det_buff_sz > ss_session->unread_bytes)
4207 ss_session->buff_sz = kw_det_buff_sz;
4208 else
4209 ss_session->buff_sz = ss_session->unread_bytes;
4210
4211 /*
4212 * It is possible that VOP started processing by already consuming
4213 * data from unread_bytes while CNN detects. In this case, it does
4214 * not need to be signaled.
4215 */
4216 if (ss_session->unread_bytes >= ss_session->buff_sz) {
4217 ALOGD("%s: Processing UV due to KW detection success", __func__);
4218 pthread_cond_signal(&ss_session->cond);
4219 }
4220 } else if (det_status & KEYWORD_DETECTION_REJECT) {
4221 ss_session->exit_buffering = true;
4222 ALOGD("%s: Exiting from UV due to KW detection rejection", __func__);
4223 pthread_cond_signal(&ss_session->cond);
4224 }
4225}
4226
4227/*
4228 * If the user verification session rejects before the keyword detection
4229 * session, signal to stop processing keyword detection.
4230 */
4231static void handle_cnn_pending_detection(st_arm_ss_session_t *ss_session,
4232 unsigned int det_status)
4233{
4234 if (det_status & USER_VERIFICATION_REJECT) {
4235 ss_session->exit_buffering = true;
4236 ALOGD("%s: Exiting from KW detection due to UV rejection", __func__);
4237 pthread_cond_signal(&ss_session->cond);
4238 }
4239}
4240
4241/*
4242 * This thread handles detection events from the second stage sessions
4243 * and aggregates them into 1 final decision. It will call the client callback
4244 * or restart the first stage session based on this decision.
4245 */
4246static void *aggregator_thread_loop(void *st_session)
4247{
4248 st_proxy_session_t *st_ses = (st_proxy_session_t *)st_session;
4249 st_session_t *stc_ses = NULL;
4250 recognition_callback_t callback = NULL;
4251 void *cookie = NULL;
4252 struct listnode *node = NULL;
4253 st_arm_second_stage_t *st_sec_stage = NULL;
4254 int status = 0, lock_status = 0;
4255 unsigned int kw_det_buff_sz = 0, det_status = 0;
4256 struct timespec tspec = {0};
4257 struct sound_trigger_recognition_event *event = NULL;
4258 bool capture_requested = false;
Quinn Maled0814de2019-05-29 17:33:22 -07004259 uint64_t callback_time = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004260
4261 ALOGV("%s: Enter", __func__);
4262
4263 /*
4264 * For multi-clients it is expected only one of the clients detection
4265 * happens at a time. Continue processing on a run time detected client
4266 */
4267 pthread_mutex_lock(&st_ses->ss_detections_lock);
4268 while (!st_ses->exit_aggregator_loop) {
4269 det_status = 0;
4270 lock_status = 0;
4271 ALOGV("%s: waiting on cond", __func__);
4272 pthread_cond_wait(&st_ses->ss_detections_cond,
4273 &st_ses->ss_detections_lock);
4274 ALOGV("%s: done waiting on cond", __func__);
4275 if (st_ses->exit_aggregator_loop) {
4276 ALOGV("%s: exit", __func__);
4277 pthread_mutex_unlock(&st_ses->ss_detections_lock);
4278 return NULL;
4279 }
4280 if (!st_ses->det_stc_ses)
4281 continue;
4282 stc_ses = st_ses->det_stc_ses;
4283
4284 list_for_each(node, &stc_ses->second_stage_list) {
4285 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
4286 list_node);
4287
4288 pthread_mutex_lock(&st_sec_stage->ss_session->lock);
4289 det_status |= st_sec_stage->ss_session->det_status;
4290 if (st_sec_stage->ss_session->det_status ==
4291 KEYWORD_DETECTION_SUCCESS)
4292 kw_det_buff_sz = st_sec_stage->ss_session->bytes_processed;
4293 pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
4294 }
4295
4296 list_for_each(node, &stc_ses->second_stage_list) {
4297 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
4298 list_node);
4299
4300 pthread_mutex_lock(&st_sec_stage->ss_session->lock);
4301 if ((st_sec_stage->ss_info->sm_detection_type ==
4302 ST_SM_TYPE_USER_VERIFICATION) &&
4303 (det_status & USER_VERIFICATION_PENDING)) {
4304 handle_vop_pending_detection(st_sec_stage->ss_session,
4305 det_status, kw_det_buff_sz);
4306 } else if ((st_sec_stage->ss_info->sm_detection_type ==
4307 ST_SM_TYPE_KEYWORD_DETECTION) &&
4308 (det_status & KEYWORD_DETECTION_PENDING)) {
4309 handle_cnn_pending_detection(st_sec_stage->ss_session,
4310 det_status);
4311 }
4312 pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
4313 }
4314
4315 if (!IS_SS_DETECTION_PENDING(det_status)) {
4316 pthread_mutex_lock(&st_ses->lock);
4317 /*
4318 * If the client stops before 2nd stage finishes processing, or a
4319 * transition is in progress, the detection event should not be
4320 * handled.
4321 */
4322 if ((st_ses->current_state != buffering_state_fn) ||
4323 (st_ses->exec_mode == ST_EXEC_MODE_NONE)) {
4324 ALOGW("%s: First stage is not in a valid state, continuing",
4325 __func__);
4326 pthread_mutex_unlock(&st_ses->lock);
4327 continue;
4328 }
4329 if (IS_SS_DETECTION_SUCCESS(det_status)) {
4330 clock_gettime(CLOCK_MONOTONIC, &tspec);
4331 st_ses->hw_ses_current->second_stage_det_event_time =
4332 get_current_time_ns();
4333 ATRACE_ASYNC_END("sthal: detection success",
4334 st_ses->sm_handle);
4335
4336 status = process_detection_event(st_ses,
4337 st_ses->det_session_ev->payload.detected.timestamp,
4338 st_ses->det_session_ev->payload.detected.detect_status,
4339 st_ses->det_session_ev->payload.detected.detect_payload,
4340 st_ses->det_session_ev->payload.detected.payload_size,
4341 &event);
4342 if (status || !event) {
4343 ALOGE("%s:[%d] process_detection_event failed err %d",
4344 __func__, st_ses->sm_handle, status);
4345 /*
4346 * Stop buffering if this is not a successful detection and
4347 * LAB is triggered in hw automatically
4348 */
4349 st_ses->hw_ses_current->fptrs->stop_buffering(
4350 st_ses->hw_ses_current);
4351
4352 pthread_mutex_unlock(&st_ses->lock);
4353 if (event) {
4354 free(event);
4355 event = NULL;
4356 }
4357 goto exit;
4358 }
Venkatesh Mangalappalib4243f42019-08-19 15:25:39 -07004359 stc_ses->detection_sent = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004360 callback = stc_ses->callback;
4361 capture_requested = stc_ses->rc_config->capture_requested;
4362 cookie = stc_ses->cookie;
Quinn Maled0814de2019-05-29 17:33:22 -07004363 callback_time = get_current_time_ns();
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004364 ALOGD("%s:[c%d] Second stage detected successfully, "
4365 "calling client callback", __func__, stc_ses->sm_handle);
Quinn Maled0814de2019-05-29 17:33:22 -07004366 ALOGD("%s: Total sthal processing time: %llums", __func__,
4367 (callback_time - st_ses->detection_event_time) /
4368 NSECS_PER_MSEC);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004369 pthread_mutex_unlock(&st_ses->lock);
4370 ATRACE_BEGIN("sthal: client detection callback");
4371 callback(event, cookie);
4372 free(event);
4373 ATRACE_END();
4374
4375 /*
4376 * The client could unload the sound model during the callback,
4377 * which would join this thread and wait for this thread exit
4378 * as part of st_session_deinit() with st_session_lock held. By
4379 * this time, the state is also moved to idle. To avoid
4380 * deadlock, upon return from client callback, try acquiring
4381 * lock only if not in idle state, else exit right away.
4382 */
4383 do {
4384 lock_status = pthread_mutex_trylock(&st_ses->lock);
4385 } while (lock_status && (st_ses->current_state !=
4386 idle_state_fn));
4387
4388 if (st_ses->current_state == idle_state_fn) {
4389 ALOGV("%s:[%d] client unloaded after callback"
4390 ", lock status %d", __func__, st_ses->sm_handle,
4391 lock_status);
4392 if (!lock_status)
4393 pthread_mutex_unlock(&st_ses->lock);
4394 goto exit;
4395 }
4396 /*
4397 * If client has not requested capture data,
4398 * stop hw session buffering here to resume next
4399 * detection
4400 */
4401 if (!capture_requested)
4402 st_ses->hw_ses_current->fptrs->stop_buffering(
4403 st_ses->hw_ses_current);
4404 } else {
4405 ATRACE_ASYNC_END("sthal: detection reject",
4406 st_ses->sm_handle);
4407 ALOGD("%s: Second stage did NOT detect, restarting st_session",
4408 __func__);
4409 st_ses->hw_ses_current->fptrs->stop_buffering(
4410 st_ses->hw_ses_current);
4411 start_second_stage_for_client(stc_ses);
4412 st_session_ev_t ev = {.ev_id = ST_SES_EV_RESTART,
4413 .stc_ses = stc_ses};
4414 DISPATCH_EVENT(st_ses, ev, status);
4415 }
4416 pthread_mutex_unlock(&st_ses->lock);
4417 } else {
4418 ALOGV("%s: There is a second stage session pending, continuing",
4419 __func__);
4420 }
4421 }
4422exit:
4423 pthread_mutex_unlock(&st_ses->ss_detections_lock);
4424 ALOGV("%s: Exit", __func__);
4425 return NULL;
4426}
4427
4428static void init_det_event_aggregator(st_proxy_session_t *st_ses)
4429{
4430 int status = 0;
4431 pthread_condattr_t attr;
4432
4433 ALOGV("%s", __func__);
4434
4435 st_ses->exit_aggregator_loop = false;
4436 pthread_mutex_init(&st_ses->ss_detections_lock, NULL);
4437 pthread_condattr_init(&attr);
4438 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
4439 pthread_cond_init(&st_ses->ss_detections_cond, &attr);
4440 pthread_condattr_destroy(&attr);
4441 status = pthread_create(&st_ses->aggregator_thread, NULL,
4442 aggregator_thread_loop, st_ses);
4443 if (status) {
4444 ALOGE("%s: Error creating aggregator thread. status = %d",
4445 __func__, status);
4446 } else {
4447 st_ses->aggregator_thread_created = true;
4448 }
4449}
4450
4451static void destroy_det_event_aggregator(st_proxy_session_t *st_ses)
4452{
4453 int status = 0;
4454
4455 ALOGV("%s", __func__);
4456
4457 st_ses->exit_aggregator_loop = true;
4458 pthread_mutex_lock(&st_ses->ss_detections_lock);
4459 pthread_cond_signal(&st_ses->ss_detections_cond);
4460 pthread_mutex_unlock(&st_ses->ss_detections_lock);
4461 status = pthread_join(st_ses->aggregator_thread, NULL);
4462 if (status)
4463 ALOGE("%s: Error joining aggregator thread. status = %d",
4464 __func__, status);
4465 pthread_cond_destroy(&st_ses->ss_detections_cond);
4466 pthread_mutex_destroy(&st_ses->ss_detections_lock);
4467 st_ses->aggregator_thread_created = false;
4468}
4469
Quinn Male58749452020-03-26 17:14:56 -07004470static int init_st_hw_config(st_hw_session_t *hw_ses, uint32_t model_id)
4471{
4472 struct st_hw_ses_config *sthw_cfg = NULL;
4473 int status;
4474
Quinn Malea15c5ff2020-06-18 18:05:20 -07004475 sthw_cfg = get_sthw_cfg_for_model_id(hw_ses, model_id);
4476 if (sthw_cfg) {
4477 ALOGD("%s: Already initialized sthw_cfg with m_id[%d]",
4478 __func__, model_id);
4479 return 0;
4480 }
4481
Quinn Male58749452020-03-26 17:14:56 -07004482 sthw_cfg = calloc(1, sizeof(struct st_hw_ses_config));
4483 if (!sthw_cfg) {
4484 ALOGE("%s: Failed to allocate struct st_hw_ses_config, exiting",
4485 __func__);
4486 return -ENOMEM;
4487 }
4488 sthw_cfg->model_id = model_id;
4489
4490 if (hw_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
4491 sthw_cfg->conf_levels = calloc(1, MAX_MULTI_SM_CONF_LEVELS);
4492 if (!sthw_cfg->conf_levels) {
4493 ALOGE("%s: Failed to allocate conf_levels, exiting",
4494 __func__);
4495 status = -ENOMEM;
4496 goto exit;
4497 }
4498 memset(sthw_cfg->conf_levels, MAX_CONF_LEVEL_VALUE,
4499 MAX_MULTI_SM_CONF_LEVELS);
4500 }
4501
4502 list_add_tail(&hw_ses->sthw_cfg_list,
4503 &sthw_cfg->sthw_cfg_list_node);
4504
4505 return 0;
4506
4507exit:
4508 if (sthw_cfg) {
4509 free(sthw_cfg);
4510 sthw_cfg = NULL;
4511 }
4512 return status;
4513}
4514
4515static int deinit_st_hw_config(st_hw_session_t *hw_ses, uint32_t model_id)
4516{
4517 struct st_hw_ses_config *sthw_cfg = NULL;
4518
4519 sthw_cfg = get_sthw_cfg_for_model_id(hw_ses, model_id);
4520 if (!sthw_cfg) {
4521 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
4522 return -EINVAL;
4523 }
4524
4525 if (hw_ses->f_stage_version == ST_MODULE_TYPE_PDK5 &&
4526 sthw_cfg->conf_levels) {
4527 free(sthw_cfg->conf_levels);
4528 sthw_cfg->conf_levels = NULL;
4529 }
4530
4531 list_remove(&sthw_cfg->sthw_cfg_list_node);
4532 free(sthw_cfg);
4533 sthw_cfg = NULL;
4534
4535 return 0;
4536}
4537
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004538/* This function is called for multi-client */
4539static int handle_load_sm(st_proxy_session_t *st_ses, st_session_t *stc_ses)
4540{
4541 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male049e47e2019-10-29 16:35:32 -07004542 st_proxy_session_state_fn_t curr_state = st_ses->current_state;
Quinn Male58749452020-03-26 17:14:56 -07004543 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
4544 struct st_hw_ses_config *sthw_cfg = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004545 int status = 0;
4546
4547 ALOGV("%s:[c%d-%d]", __func__, stc_ses->sm_handle, st_ses->sm_handle);
4548 if (!stc_ses->phrase_sm) {
4549 ALOGE("%s:[c%d] sound model data is not initialzed", __func__,
4550 stc_ses->sm_handle);
4551 return -EINVAL;
4552 }
4553
4554 if (!is_other_client_attached(st_ses, stc_ses)) {
4555 ALOGE("%s:[c%d] Unexpected without multi-clients", __func__,
4556 stc_ses->sm_handle);
4557 return -EINVAL;
4558 }
4559
4560 if (st_ses->current_state == buffering_state_fn)
4561 hw_ses->fptrs->stop_buffering(hw_ses);
4562
4563 if (st_ses->current_state == active_state_fn ||
4564 st_ses->current_state == detected_state_fn ||
4565 st_ses->current_state == buffering_state_fn) {
4566 status = stop_session(st_ses, hw_ses, false);
4567 if (status)
4568 ALOGE("%s:[%d] stop_session failed %d", __func__, st_ses->sm_handle,
4569 status);
Quinn Male80c1e0d2019-10-21 15:16:54 -07004570 STATE_TRANSITION(st_ses, loaded_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004571 }
4572
Quinn Male58749452020-03-26 17:14:56 -07004573 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
4574 status = hw_ses->fptrs->dereg_sm(hw_ses, 0);
4575 if (status) {
4576 ALOGE("%s:[%d] dereg_sm failed %d", __func__,
4577 st_ses->sm_handle, status);
4578 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004579 }
4580 /* Continue updating sound model resulting in merged model */
4581 status = update_sound_model(stc_ses, true);
4582 if (status) {
4583 ALOGE("%s:[c%d] update_sound_model add failed %d", __func__,
4584 stc_ses->sm_handle, status);
4585 goto exit;
4586 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004587
Quinn Male58749452020-03-26 17:14:56 -07004588 p_info = get_sm_info_for_model_id(st_ses, stc_ses->sm_info.model_id);
4589 if (!p_info) {
4590 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
4591 status = -EINVAL;
4592 goto exit_1;
4593 }
4594
4595 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
4596 sthw_cfg = get_sthw_cfg_for_model_id(hw_ses, 0);
4597 if (!sthw_cfg) {
4598 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
4599 status = -EINVAL;
4600 goto exit_1;
4601 }
4602
4603 sthw_cfg->conf_levels = p_info->sm_info.cf_levels;
4604 sthw_cfg->num_conf_levels = p_info->sm_info.cf_levels_size;
4605 /*
4606 * Sound model merge would have changed the order of merge conf levels,
4607 * which need to be re-updated for all current active clients, if any.
4608 */
4609 status = update_merge_conf_levels_payload_with_active_clients(st_ses);
4610 if (status)
4611 goto exit_1;
4612 } else {
4613 status = init_st_hw_config(hw_ses, stc_ses->sm_info.model_id);
4614 if (status)
4615 goto exit_1;
4616 }
4617 hw_ses->sthw_cfg_updated = true;
4618
4619 status = hw_ses->fptrs->reg_sm(hw_ses, p_info->sm_info.sm_data,
4620 p_info->sm_info.sm_size, p_info->sm_info.model_id);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004621 if (status) {
4622 ALOGE("%s:[%d] reg_sm failed %d", __func__,
4623 st_ses->sm_handle, status);
4624 goto exit_1;
4625 }
4626
Quinn Male049e47e2019-10-29 16:35:32 -07004627 if (curr_state == active_state_fn ||
4628 curr_state == detected_state_fn ||
4629 curr_state == buffering_state_fn) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004630
4631 status = start_session(st_ses, hw_ses, false);
4632 if (status)
4633 goto exit_2;
4634 STATE_TRANSITION(st_ses, active_state_fn);
4635 }
4636
4637 return 0;
4638
4639exit_2:
4640 if (!st_ses->stdev->ssr_offline_received)
Quinn Male58749452020-03-26 17:14:56 -07004641 hw_ses->fptrs->dereg_sm(hw_ses, p_info->sm_info.model_id);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004642
4643exit_1:
4644 if (!st_ses->stdev->ssr_offline_received) {
4645 update_sound_model(stc_ses, false);
Quinn Male58749452020-03-26 17:14:56 -07004646 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM)
4647 update_merge_conf_levels_payload_with_active_clients(st_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004648 }
4649
4650exit:
4651 if (st_ses->stdev->ssr_offline_received) {
Quinn Male58749452020-03-26 17:14:56 -07004652 dereg_all_sm(st_ses, hw_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004653 STATE_TRANSITION(st_ses, ssr_state_fn);
4654 status = 0;
4655 }
4656 return status;
4657}
4658
4659/* This function is called for multi-client */
4660static int handle_unload_sm(st_proxy_session_t *st_ses, st_session_t *stc_ses)
4661{
4662 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male049e47e2019-10-29 16:35:32 -07004663 st_proxy_session_state_fn_t curr_state = st_ses->current_state;
Quinn Male58749452020-03-26 17:14:56 -07004664 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
4665 struct st_hw_ses_config *sthw_cfg = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004666 int status = 0;
4667
4668 ALOGV("%s:[c%d-%d]", __func__, stc_ses->sm_handle, st_ses->sm_handle);
4669
4670 if (!is_other_client_attached(st_ses, stc_ses)) {
4671 ALOGE("%s:[c%d] Unexpected without multi-clients", __func__,
4672 stc_ses->sm_handle);
4673 return -EINVAL;
4674 }
4675
4676 if (st_ses->current_state == buffering_state_fn)
4677 hw_ses->fptrs->stop_buffering(hw_ses);
4678
4679 if (st_ses->current_state == active_state_fn ||
4680 st_ses->current_state == detected_state_fn ||
4681 st_ses->current_state == buffering_state_fn) {
4682 status = stop_session(st_ses, hw_ses, false);
4683 if (status)
4684 ALOGE("%s:[%d] stop_session failed %d", __func__,
4685 st_ses->sm_handle, status);
Quinn Male80c1e0d2019-10-21 15:16:54 -07004686 STATE_TRANSITION(st_ses, loaded_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004687 }
4688
Quinn Male58749452020-03-26 17:14:56 -07004689 status = hw_ses->fptrs->dereg_sm(hw_ses, stc_ses->sm_info.model_id);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004690 if (status)
4691 ALOGE("%s:[%d] dereg_sm failed %d", __func__, st_ses->sm_handle, status);
4692
4693 /* Continue deleting this model */
4694 status = update_sound_model(stc_ses, false);
4695 if (status)
4696 ALOGE("%s:[c%d] update_sound_model delete failed %d", __func__,
4697 stc_ses->sm_handle, status);
4698
Quinn Male58749452020-03-26 17:14:56 -07004699 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
4700 p_info = get_sm_info_for_model_id(st_ses, 0);
4701 if (!p_info) {
4702 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
4703 status = -EINVAL;
4704 goto exit;
4705 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004706
Quinn Male58749452020-03-26 17:14:56 -07004707 sthw_cfg = get_sthw_cfg_for_model_id(hw_ses, 0);
4708 if (!sthw_cfg) {
4709 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
4710 status = -EINVAL;
4711 goto exit;
4712 }
4713
4714 sthw_cfg->conf_levels = p_info->sm_info.cf_levels;
4715 sthw_cfg->num_conf_levels = p_info->sm_info.cf_levels_size;
4716 /*
4717 * Sound model merge would have changed the order of merge conf levels,
4718 * which need to be re-updated for all current active clients, if any.
4719 */
4720 update_merge_conf_levels_payload_with_active_clients(st_ses);
4721
4722 /* Load remaining merged sound model */
4723 status = hw_ses->fptrs->reg_sm(hw_ses, p_info->sm_info.sm_data,
4724 p_info->sm_info.sm_size, 0);
4725 if (status) {
4726 ALOGE("%s:[%d] reg_sm failed %d", __func__,
4727 st_ses->sm_handle, status);
4728 goto exit;
4729 }
4730 } else {
4731 status = deinit_st_hw_config(hw_ses, stc_ses->sm_handle);
4732 if (status)
4733 goto exit;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004734 }
Quinn Male58749452020-03-26 17:14:56 -07004735 hw_ses->sthw_cfg_updated = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004736
Quinn Male049e47e2019-10-29 16:35:32 -07004737 if (curr_state == active_state_fn ||
4738 curr_state == detected_state_fn ||
4739 curr_state == buffering_state_fn) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004740
4741 status = start_session(st_ses, hw_ses, false);
4742 if (status)
4743 goto exit;
4744 STATE_TRANSITION(st_ses, active_state_fn);
4745 }
4746 return 0;
4747
4748exit:
4749 if (st_ses->stdev->ssr_offline_received) {
Quinn Male58749452020-03-26 17:14:56 -07004750 if (st_ses->f_stage_version == ST_MODULE_TYPE_PDK5)
4751 dereg_all_sm(st_ses, hw_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004752 STATE_TRANSITION(st_ses, ssr_state_fn);
4753 status = 0;
4754 }
4755 return status;
4756}
4757
4758static int idle_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07004759{
4760 int status = 0;
4761 int ret = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004762 st_session_t *stc_ses = ev->stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07004763 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male58749452020-03-26 17:14:56 -07004764 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07004765
4766 /* skip parameter check as this is an internal funciton */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004767 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
4768 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07004769
4770 switch (ev->ev_id) {
4771 case ST_SES_EV_LOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004772 if (!stc_ses->phrase_sm) {
Quinn Male2e883752019-03-22 11:28:54 -07004773 ALOGE("%s: sound model data is not initialzed", __func__);
4774 status = -EINVAL;
4775 break;
4776 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004777 status = update_sound_model(stc_ses, true);
4778 if (status) {
4779 ALOGE("%s:[c%d] update sound model add failed %d", __func__,
4780 stc_ses->sm_handle, status);
4781 status = -EINVAL;
4782 break;
4783 }
Quinn Male2e883752019-03-22 11:28:54 -07004784
Quinn Male58749452020-03-26 17:14:56 -07004785 p_info = get_sm_info_for_model_id(st_ses, stc_ses->sm_info.model_id);
4786 if (!p_info) {
4787 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
4788 status = -EINVAL;
4789 break;
4790 }
4791
4792 status = init_st_hw_config(hw_ses, p_info->sm_info.model_id);
4793 if (status) {
4794 ALOGE("%s:[%d] failed to init sthw_cfg, exiting",
4795 __func__, st_ses->sm_handle);
4796 break;
4797 }
4798
Quinn Male2e883752019-03-22 11:28:54 -07004799 /*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004800 * Do retry to handle a corner case that when ADSP SSR ONLINE is
4801 * received, sometimes ADSP is still not ready to receive cmd from HLOS
4802 * and thus fails, so try more times to recover the session from SSR
4803 * state.
Quinn Male2e883752019-03-22 11:28:54 -07004804 */
4805 for (int i = 0; i < REG_SM_RETRY_CNT; i++) {
Quinn Malea15c5ff2020-06-18 18:05:20 -07004806 if (stc_ses->pending_load)
4807 status = ret = reg_all_sm(st_ses, hw_ses);
4808 else
4809 status = ret = hw_ses->fptrs->reg_sm(hw_ses, p_info->sm_info.sm_data,
4810 p_info->sm_info.sm_size, p_info->sm_info.model_id);
4811
Quinn Male2e883752019-03-22 11:28:54 -07004812 if (ret) {
4813 if (st_ses->stdev->ssr_offline_received) {
Quinn Male2e883752019-03-22 11:28:54 -07004814 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07004815 status = 0;
4816 break;
4817 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004818 ALOGE("%s:[%d] failed to reg sm, err %d, retry cnt %d",
4819 __func__, st_ses->sm_handle, status, i);
Quinn Male2e883752019-03-22 11:28:54 -07004820 usleep(REG_SM_WAIT_TIME_MS * 1000);
4821 }
4822 } else {
4823 break;
4824 }
4825 }
Quinn Male58749452020-03-26 17:14:56 -07004826
Quinn Male2e883752019-03-22 11:28:54 -07004827 if (ret)
4828 break;
4829
Quinn Male2e883752019-03-22 11:28:54 -07004830 STATE_TRANSITION(st_ses, loaded_state_fn);
4831 break;
4832
4833 case ST_SES_EV_SET_EXEC_MODE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004834 stc_ses->exec_mode = ev->payload.exec_mode;
4835 if (ev->payload.exec_mode == st_ses->exec_mode)
4836 break;
4837
Quinn Male2e883752019-03-22 11:28:54 -07004838 st_ses->exec_mode = ev->payload.exec_mode;
4839 if (ST_EXEC_MODE_CPE == st_ses->exec_mode)
4840 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
4841 else if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
4842 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
4843 /* remain in current state */
4844 break;
4845
4846 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004847 stc_ses->paused = true;
Quinn Male2e883752019-03-22 11:28:54 -07004848 break;
4849
4850 case ST_SES_EV_RESUME:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004851 stc_ses->paused = false;
Quinn Male2e883752019-03-22 11:28:54 -07004852 break;
4853
4854 case ST_SES_EV_SSR_OFFLINE:
4855 STATE_TRANSITION(st_ses, ssr_state_fn);
4856 break;
4857
4858 case ST_SES_EV_SEND_CHMIX_COEFF:
4859 status = -EIO;
4860 break;
4861
4862 case ST_SES_EV_GET_PARAM_DATA:
4863 status = -EIO;
4864 break;
4865
4866 case ST_SES_EV_REQUEST_DET:
4867 ALOGE("%s:[%d] Event not supported in this state",
4868 __func__, st_ses->sm_handle);
4869 status = -EINVAL;
4870 break;
4871
4872 default:
4873 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
4874 break;
4875 };
4876
4877 return status;
4878}
4879
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004880static int loaded_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07004881{
4882 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004883 st_session_t *stc_ses = ev->stc_ses;
4884 struct listnode *node = NULL;
4885 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07004886 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
4887 st_hw_session_t *new_hw_ses = NULL;
4888 st_exec_mode_t new_exec_mode = 0;
Quinn Male58749452020-03-26 17:14:56 -07004889 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07004890
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004891 /* skip parameter check as this is an internal function */
4892 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
4893 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07004894
4895 switch (ev->ev_id) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004896 case ST_SES_EV_LOAD_SM:
4897 /* Valid only in multi-client session usecase */
4898 status = handle_load_sm(st_ses, stc_ses);
Quinn Male2e883752019-03-22 11:28:54 -07004899 break;
4900
4901 case ST_SES_EV_UNLOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004902 if (is_other_client_attached(st_ses, stc_ses)) {
4903 status = handle_unload_sm(st_ses, stc_ses);
4904 break;
Quinn Male2e883752019-03-22 11:28:54 -07004905 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004906
Quinn Male58749452020-03-26 17:14:56 -07004907 status = hw_ses->fptrs->dereg_sm(hw_ses, stc_ses->sm_info.model_id);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004908 if (status)
4909 ALOGE("%s:[%d] dereg_sm failed %d", __func__,
4910 st_ses->sm_handle, status);
4911
4912 status = update_sound_model(stc_ses, false);
4913 if (status)
4914 ALOGE("%s:[c%d] update_sound_model failed %d", __func__,
4915 stc_ses->sm_handle, status);
4916
Quinn Male58749452020-03-26 17:14:56 -07004917 status = deinit_st_hw_config(hw_ses, stc_ses->sm_info.model_id);
4918 if (status)
4919 ALOGE("%s:[c%d] failed to deinit sthw_cfg",
4920 __func__, stc_ses->sm_handle);
4921
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004922 /* since this is a teardown scenario dont fail here */
4923 status = 0;
Quinn Male2e883752019-03-22 11:28:54 -07004924 STATE_TRANSITION(st_ses, idle_state_fn);
4925 break;
4926
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004927 case ST_SES_EV_RESUME:
4928 stc_ses->paused = false;
Quinn Male60ca2022019-08-21 17:10:25 -07004929 if (!is_any_client_in_state(st_ses, ST_STATE_ACTIVE)) {
4930 /*
4931 * When a transition is needed due to lpi mode or barge-in mode,
4932 * call dereg_sm and reg_sm to select the updated lsm_usecase.
4933 */
4934 if (hw_ses->lpi_enable != hw_ses->stdev->lpi_enable ||
4935 (hw_ses->barge_in_mode != hw_ses->stdev->barge_in_mode &&
4936 !hw_ses->stdev->support_dynamic_ec_update)) {
4937
4938 hw_ses->lpi_enable = hw_ses->stdev->lpi_enable;
4939 hw_ses->barge_in_mode = hw_ses->stdev->barge_in_mode;
4940
Quinn Male58749452020-03-26 17:14:56 -07004941 status = dereg_all_sm(st_ses, hw_ses);
Quinn Male60ca2022019-08-21 17:10:25 -07004942 if (status) {
4943 ALOGE("%s:[%d] failed to dereg_sm err %d", __func__,
4944 st_ses->sm_handle, status);
4945 break;
4946 }
4947
Quinn Male58749452020-03-26 17:14:56 -07004948 status = reg_all_sm(st_ses, hw_ses);
Quinn Male60ca2022019-08-21 17:10:25 -07004949 if (status) {
4950 ALOGE("%s:[%d] failed to reg_sm err %d", __func__,
4951 st_ses->sm_handle, status);
Quinn Male58749452020-03-26 17:14:56 -07004952 dereg_all_sm(st_ses, hw_ses);
Quinn Male60ca2022019-08-21 17:10:25 -07004953 STATE_TRANSITION(st_ses, idle_state_fn);
4954 }
4955 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004956 break;
Quinn Male60ca2022019-08-21 17:10:25 -07004957 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004958 /* Fall through */
4959 case ST_SES_EV_START:
4960 case ST_SES_EV_RESTART:
4961 if (ev->ev_id == ST_SES_EV_RESTART)
4962 update_hw_config_on_restart(st_ses, stc_ses);
4963
4964 /*
4965 * During Resume, the first active client will start the hw sesison.
4966 * During Start, check for any paused sessions to delay actual start
4967 * to Resume.
4968 */
4969 if ((ev->ev_id != ST_SES_EV_RESUME) && is_any_client_paused(st_ses))
4970 break;
4971
4972 status = start_session(st_ses, hw_ses, false);
4973 if (status) {
4974 if (st_ses->stdev->ssr_offline_received) {
Quinn Male58749452020-03-26 17:14:56 -07004975 dereg_all_sm(st_ses, hw_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004976 STATE_TRANSITION(st_ses, ssr_state_fn);
4977 status = 0;
4978 } else {
4979 ALOGE("%s:[%d] failed to start session, err %d", __func__,
4980 st_ses->sm_handle, status);
4981 }
4982 break;
4983 }
4984 STATE_TRANSITION(st_ses, active_state_fn);
4985 break;
4986
4987 case ST_SES_EV_STOP:
4988 /*
4989 * Valid in multi-client case.
4990 * Reconfig based off other active clients, if any, so that RESUME
4991 * can apply this reconfig.
4992 */
4993 update_hw_config_on_stop(st_ses, stc_ses);
4994 break;
4995
Quinn Male2e883752019-03-22 11:28:54 -07004996 case ST_SES_EV_SSR_OFFLINE:
Quinn Male2e883752019-03-22 11:28:54 -07004997 /* exec mode can be none if ssr occurs during a transition */
4998 if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
Quinn Male58749452020-03-26 17:14:56 -07004999 dereg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005000 STATE_TRANSITION(st_ses, ssr_state_fn);
5001 break;
5002
5003 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005004 stc_ses->paused = true;
Quinn Male2e883752019-03-22 11:28:54 -07005005 break;
5006
5007 case ST_SES_EV_SET_EXEC_MODE:
5008 new_exec_mode = ev->payload.exec_mode;
5009
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005010 if (new_exec_mode == st_ses->exec_mode) {
5011 stc_ses->exec_mode = st_ses->exec_mode;
5012 break;
Quinn Male2e883752019-03-22 11:28:54 -07005013 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005014
5015 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
5016 st_ses->exec_mode = ST_EXEC_MODE_NONE;
5017 list_for_each(node, &st_ses->clients_list) {
5018 c_ses = node_to_item(node, st_session_t, hw_list_node);
5019 c_ses->exec_mode = ST_EXEC_MODE_NONE;
5020 }
5021 /* unload sm for current hw session */
Quinn Male58749452020-03-26 17:14:56 -07005022 status = hw_ses->fptrs->dereg_sm(hw_ses, 0);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005023 if (status) {
5024 ALOGE("%s:[%d] dereg_sm failed with err %d", __func__,
5025 st_ses->sm_handle, status);
5026 break;
5027 }
5028 }
5029
5030 if (new_exec_mode == ST_EXEC_MODE_NONE)
5031 break;
5032
5033 /* load sm to new hw_ses */
5034 if (ST_EXEC_MODE_CPE == new_exec_mode) {
5035 new_hw_ses = st_ses->hw_ses_cpe;
5036 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
5037 new_hw_ses = st_ses->hw_ses_adsp;
5038 } else {
5039 ALOGE("%s: unknown execution mode %d", __func__,
5040 new_exec_mode);
5041 status = -EINVAL;
5042 break;
5043 }
5044
Quinn Male58749452020-03-26 17:14:56 -07005045 p_info = get_sm_info_for_model_id(st_ses, 0);
5046 if (!p_info) {
5047 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
5048 status = -EINVAL;
5049 break;
5050 }
5051
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005052 status = new_hw_ses->fptrs->reg_sm(new_hw_ses,
Quinn Male58749452020-03-26 17:14:56 -07005053 p_info->sm_info.sm_data, p_info->sm_info.sm_size, 0);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005054 if (status) {
5055 ALOGE("%s:[%d] reg_sm failed with err %d", __func__,
5056 st_ses->sm_handle, status);
5057 break;
5058 }
5059 /* switch hw sessions only if successful*/
5060 list_for_each(node, &st_ses->clients_list) {
5061 c_ses = node_to_item(node, st_session_t, hw_list_node);
5062 c_ses->exec_mode = new_exec_mode;
5063 if (c_ses->state == ST_STATE_ACTIVE) {
5064 dereg_hal_event_session(c_ses);
5065 reg_hal_event_session(c_ses, new_hw_ses);
5066 }
5067 }
5068 st_ses->exec_mode = new_exec_mode;
5069 st_ses->hw_ses_current = new_hw_ses;
5070 /* remain in current state */
Quinn Male2e883752019-03-22 11:28:54 -07005071 break;
5072
5073 case ST_SES_EV_SET_DEVICE:
5074 /*
5075 * This event handling is needed for certain graphs which
5076 * have multiple buffering modules with a single voice wakeup
5077 * module in each usecase.
5078 */
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005079 if (!ev->payload.enable) {
Quinn Male2e883752019-03-22 11:28:54 -07005080 status = hw_ses->fptrs->disable_device(hw_ses, false);
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005081 } else {
Quinn Male2e883752019-03-22 11:28:54 -07005082 status = hw_ses->fptrs->enable_device(hw_ses, false);
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005083 /*
5084 * Device switch might happen during active buffering.
5085 * If any client is active, start hw session.
5086 */
5087 if (is_any_client_in_state(st_ses, ST_STATE_ACTIVE)) {
5088 st_session_ev_t start_ev = {.ev_id = ST_SES_EV_START,
5089 .stc_ses = stc_ses};
5090 DISPATCH_EVENT(st_ses, start_ev, status);
5091 }
5092 }
Quinn Male2e883752019-03-22 11:28:54 -07005093
5094 break;
5095
5096 case ST_SES_EV_READ_PCM:
5097 /*
5098 * set status to failure this will tell AHAL to
5099 * provide zero buffers to client
5100 */
5101 status = -EIO;
5102 break;
5103
5104 case ST_SES_EV_SEND_CHMIX_COEFF:
5105 status = -EIO;
5106 break;
5107
5108 case ST_SES_EV_GET_PARAM_DATA:
5109 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005110 ev->payload.getparam.param, ev->payload.getparam.payload,
5111 ev->payload.getparam.payload_size,
5112 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07005113 break;
5114
5115 case ST_SES_EV_REQUEST_DET:
5116 ALOGE("%s:[%d] Event not supported in this state",
5117 __func__, st_ses->sm_handle);
5118 status = -EINVAL;
5119 break;
5120
5121 default:
5122 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
5123 break;
Quinn Male2e883752019-03-22 11:28:54 -07005124 };
5125
5126 return status;
Quinn Male2e883752019-03-22 11:28:54 -07005127}
5128
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005129static int active_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07005130{
5131 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005132 st_session_t *stc_ses = ev->stc_ses;
5133 struct listnode *node = NULL;
5134 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07005135 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male2e883752019-03-22 11:28:54 -07005136 st_hw_session_t *new_hw_ses = NULL;
5137 st_exec_mode_t new_exec_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005138 st_arm_second_stage_t *st_sec_stage = NULL;
5139 struct sound_trigger_recognition_event *event = NULL;
5140 recognition_callback_t callback = NULL;
5141 void *cookie = NULL;
5142 bool lab_enabled = false, enable_second_stage = false, active = false;
Quinn Male2e883752019-03-22 11:28:54 -07005143
5144 /* skip parameter check as this is an internal funciton */
5145 ALOGD("%s:[%d] handle event id %d", __func__, st_ses->sm_handle, ev->ev_id);
5146
5147 switch (ev->ev_id) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005148 case ST_SES_EV_LOAD_SM:
5149 /* Valid in multi-client usecase */
5150 status = handle_load_sm(st_ses, stc_ses);
5151 break;
5152
5153 case ST_SES_EV_UNLOAD_SM:
5154 /* Valid in multi-client usecase */
5155 status = handle_unload_sm(st_ses, stc_ses);
5156 break;
5157
5158 case ST_SES_EV_RESTART:
5159 /* Valid in multi-client usecase */
5160 update_hw_config_on_restart(st_ses, stc_ses);
5161 /* Fall through */
5162 case ST_SES_EV_START:
5163 /* Valid in multi-client usecase */
5164 status = stop_session(st_ses, hw_ses, false);
5165 if (!status) {
5166 status = start_session(st_ses, hw_ses, false);
5167 if (status)
5168 ALOGE("%s:[%d] start_session failed %d", __func__,
5169 st_ses->sm_handle, status);
5170 } else {
5171 ALOGE("%s:[%d] stop_session failed %d", __func__,
5172 st_ses->sm_handle, status);
5173 }
5174 if (status & st_ses->stdev->ssr_offline_received) {
Quinn Male58749452020-03-26 17:14:56 -07005175 dereg_all_sm(st_ses, hw_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005176 STATE_TRANSITION(st_ses, ssr_state_fn);
5177 status = 0;
5178 }
5179 break;
5180
Quinn Male2e883752019-03-22 11:28:54 -07005181 case ST_SES_EV_SET_EXEC_MODE:
5182 new_exec_mode = ev->payload.exec_mode;
5183
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005184 if (new_exec_mode == st_ses->exec_mode) {
5185 stc_ses->exec_mode = st_ses->exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07005186 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005187 }
Quinn Male2e883752019-03-22 11:28:54 -07005188
5189 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
5190 ALOGV("%s: disable current session", __func__);
5191 st_ses->exec_mode = ST_EXEC_MODE_NONE;
5192 status = stop_session(st_ses, hw_ses, true);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005193 list_for_each(node, &st_ses->clients_list) {
5194 c_ses = node_to_item(node, st_session_t, hw_list_node);
5195 c_ses->exec_mode = ST_EXEC_MODE_NONE;
5196 }
Quinn Male2e883752019-03-22 11:28:54 -07005197 if (status)
5198 break;
5199 }
5200
5201 if (new_exec_mode == ST_EXEC_MODE_NONE)
5202 break;
5203
5204 if (ST_EXEC_MODE_CPE == new_exec_mode) {
5205 new_hw_ses = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07005206 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
5207 new_hw_ses = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07005208 } else {
5209 ALOGE("%s: unknown execution mode %d", __func__,
5210 new_exec_mode);
5211 status = -EINVAL;
5212 break;
5213 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005214 /*
5215 * hw session changed to/from WDSP/ADSP, hence update the
5216 * related config.
5217 * Not applicable for LPI<->non-LPI transtions as hw session
5218 * doesn't change.
5219 */
5220 status = update_hw_config_on_start(stc_ses, new_hw_ses);
5221 if (status) {
5222 ALOGE("%s: Update_hw_config_on_start failed %d",
5223 __func__, status);
5224 break;
5225 }
Quinn Male2e883752019-03-22 11:28:54 -07005226
5227 ALOGV("%s: enable current session", __func__);
5228 status = start_session(st_ses, new_hw_ses, true);
5229 if (status)
5230 break;
5231
5232 /* set new exec mode and current session */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005233 list_for_each(node, &st_ses->clients_list) {
5234 c_ses = node_to_item(node, st_session_t, hw_list_node);
5235 c_ses->exec_mode = new_exec_mode;
5236 if (c_ses->state == ST_STATE_ACTIVE) {
5237 dereg_hal_event_session(c_ses);
5238 reg_hal_event_session(c_ses, new_hw_ses);
5239 }
5240 }
Quinn Male2e883752019-03-22 11:28:54 -07005241 st_ses->exec_mode = new_exec_mode;
5242 st_ses->hw_ses_current = new_hw_ses;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005243
Quinn Male2e883752019-03-22 11:28:54 -07005244 ALOGV("%s: end transition", __func__);
5245 break;
5246
5247 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005248 /*
5249 * For multi-client, the first active pausing client stops the hw
5250 * session and moves to loaded state.
5251 */
5252 stc_ses->paused = true;
5253 if (stc_ses->state != ST_STATE_ACTIVE)
5254 break;
5255
Quinn Male2e883752019-03-22 11:28:54 -07005256 status = stop_session(st_ses, hw_ses, false);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005257
Quinn Male2e883752019-03-22 11:28:54 -07005258 if (status) {
5259 if (st_ses->stdev->ssr_offline_received) {
5260 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male58749452020-03-26 17:14:56 -07005261 dereg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005262 status = 0;
5263 } else {
5264 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
5265 st_ses->sm_handle, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005266 /* Move anyway to loaded state */
5267 STATE_TRANSITION(st_ses, loaded_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07005268 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005269 break;
Quinn Male2e883752019-03-22 11:28:54 -07005270 }
Quinn Male2e883752019-03-22 11:28:54 -07005271 STATE_TRANSITION(st_ses, loaded_state_fn);
5272 break;
5273
Zhou Song5d413d72019-11-13 17:47:24 +08005274 case ST_SES_EV_RESUME:
5275 if (stc_ses->paused == true)
5276 stc_ses->paused = false;
5277 break;
5278
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005279 case ST_SES_EV_STOP:
5280 status = stop_session(st_ses, hw_ses, false);
5281 if (status)
5282 ALOGE("%s:[%d] start_session failed %d", __func__,
5283 st_ses->sm_handle, status);
Quinn Male2e883752019-03-22 11:28:54 -07005284
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005285 /* Continue to reconfig based off other active clients, if any */
5286 active = update_hw_config_on_stop(st_ses, stc_ses);
5287
5288 if (!status) {
5289 if (active) {
5290 ALOGD("%s: client c%d stopped, start %d due to reconfig",
5291 __func__, stc_ses->sm_handle, st_ses->sm_handle);
5292 status = start_session(st_ses, hw_ses, false);
5293 if (status)
5294 ALOGE("%s:[%d] start_session failed %d", __func__,
Quinn Male2e883752019-03-22 11:28:54 -07005295 st_ses->sm_handle, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005296 /* Stay in active state */
Quinn Male2e883752019-03-22 11:28:54 -07005297 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005298 STATE_TRANSITION(st_ses, loaded_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07005299 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005300 }
Quinn Male2e883752019-03-22 11:28:54 -07005301
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005302 if (status) {
5303 if (st_ses->stdev->ssr_offline_received) {
Quinn Male58749452020-03-26 17:14:56 -07005304 dereg_all_sm(st_ses, hw_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005305 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07005306 status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005307 } else {
5308 STATE_TRANSITION(st_ses, loaded_state_fn);
5309 }
5310 }
5311
5312 break;
5313
5314 case ST_SES_EV_DETECTED:
Quinn Maled0814de2019-05-29 17:33:22 -07005315
5316 st_ses->detection_event_time = get_current_time_ns();
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005317 /*
5318 * Find which client is this detection for.
5319 * Note that only one keyword detection can happen at a time.
5320 */
5321 stc_ses = get_detected_client(st_ses,
5322 ev->payload.detected.detect_payload,
5323 ev->payload.detected.payload_size);
5324
5325 if (!stc_ses) {
5326 ALOGW("%s:[%d] Couldn't find a matching client for detection",
5327 __func__, st_ses->sm_handle);
5328 /*
5329 * Though we set higest conf level 100 for inactive client in merged
5330 * sound model, it may be possible it still detects. In case the lab
5331 * is enabled due to other active client, stop hw buffering.
5332 */
5333 if (st_ses->lab_enabled)
5334 hw_ses->fptrs->stop_buffering(hw_ses);
Quinn Male48490df2020-03-25 10:25:42 -07005335 pthread_mutex_unlock(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005336 break;
5337 }
5338 st_ses->det_stc_ses = stc_ses;
5339 st_ses->hw_ses_current->enable_second_stage = false; /* Initialize */
Venkatesh Mangalappalib4243f42019-08-19 15:25:39 -07005340 stc_ses->detection_sent = false;
Quinn Male58749452020-03-26 17:14:56 -07005341 hw_ses->detected_preroll = stc_ses->preroll_duration;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005342
5343 if (list_empty(&stc_ses->second_stage_list) ||
5344 st_ses->detection_requested) {
5345 st_ses->detection_requested = false;
5346 status = process_detection_event(st_ses,
5347 ev->payload.detected.timestamp,
5348 ev->payload.detected.detect_status,
5349 ev->payload.detected.detect_payload,
5350 ev->payload.detected.payload_size,
5351 &event);
5352 if (status || !event) {
5353 ALOGE("%s:[%d] process_detection_event failed err %d", __func__,
5354 st_ses->sm_handle, status);
5355 /*
5356 * Stop buffering if this is not a successful detection and
5357 * LAB is triggered in hw automatically
5358 */
5359 hw_ses->fptrs->stop_buffering(hw_ses);
5360 if (event)
5361 free(event);
Quinn Male48490df2020-03-25 10:25:42 -07005362 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07005363 break;
5364 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005365 } else {
5366 ALOGV("%s:[c%d] second stage enabled, list_empty %d,"
5367 "det_requested %d", __func__, stc_ses->sm_handle,
5368 list_empty(&stc_ses->second_stage_list),
5369 st_ses->detection_requested);
Quinn Male2e883752019-03-22 11:28:54 -07005370
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005371 enable_second_stage = true;
Quinn Male2e883752019-03-22 11:28:54 -07005372 /*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005373 * Before first stage starts buffering, update the second stage info
5374 * to first stage layer for further communication between first and
5375 * second stage layers.
Quinn Male2e883752019-03-22 11:28:54 -07005376 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005377 st_ses->hw_ses_current->enable_second_stage = true;
5378 st_ses->hw_ses_current->second_stage_list =
5379 &(stc_ses->second_stage_list);
Quinn Male2e883752019-03-22 11:28:54 -07005380
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005381 list_for_each(node, &stc_ses->second_stage_list) {
5382 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
5383 list_node);
5384 st_sec_stage->ss_session->st_ses = st_ses;
5385 }
5386 get_first_stage_detection_params(st_ses,
5387 ev->payload.detected.detect_payload,
5388 ev->payload.detected.payload_size);
5389 memcpy(st_ses->det_session_ev, ev, sizeof(st_session_ev_t));
5390 }
5391 /*
5392 * change to new state before invoking user callback, this will
5393 * ensure that if user calls start_recognition immediately from the
5394 * callback it will be handled by one of the two states below
5395 */
5396 if (!status && st_ses->lab_enabled) {
5397 if (stc_ses->rc_config->capture_requested ||
5398 !list_empty(&stc_ses->second_stage_list)) {
Quinn Maleaba13db2019-07-11 15:52:14 -07005399 if (st_ses->stdev->enable_debug_dumps) {
5400 ST_DBG_FILE_OPEN_WR(st_ses->lab_fp, ST_DEBUG_DUMP_LOCATION,
5401 "lab_capture", "bin", file_cnt++);
5402 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005403 STATE_TRANSITION(st_ses, buffering_state_fn);
5404 lab_enabled = true;
5405 } else {
5406 /*
5407 * for merged model case the client detected may not have
5408 * requested the capture nor enabled the second stage, but the
5409 * hw lab could be enabled due to other client requested capture
5410 * or enabled second stage.
5411 */
5412 ALOGV("%s: stop buffering as c%d doesn't need", __func__,
5413 stc_ses->sm_handle);
5414 hw_ses->fptrs->stop_buffering(hw_ses);
5415 STATE_TRANSITION(st_ses, detected_state_fn);
5416 lab_enabled = false;
5417 }
5418 } else {
5419 STATE_TRANSITION(st_ses, detected_state_fn);
5420 }
5421
5422 if (!stc_ses->callback) {
5423 ALOGE("%s:[c%d] received detection event but no callback",
5424 __func__, stc_ses->sm_handle);
5425 status = -EINVAL;
5426 if (event)
Quinn Male2e883752019-03-22 11:28:54 -07005427 free(event);
Quinn Male48490df2020-03-25 10:25:42 -07005428 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07005429 break;
5430 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005431 /*
5432 * callback to user, assumption is that client does not
5433 * block in the callback waiting for data otherwise will be a deadlock.
5434 * If second stage is enabled, the detection will be sent later when
5435 * second stage successfully detects.
5436 */
5437 if (!enable_second_stage) {
Venkatesh Mangalappalib4243f42019-08-19 15:25:39 -07005438 stc_ses->detection_sent = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005439 callback = stc_ses->callback;
5440 cookie = stc_ses->cookie;
5441 ALOGD("%s:[c%d] invoking the client callback",
5442 __func__, stc_ses->sm_handle);
5443 ATRACE_ASYNC_END("sthal: detection success",
5444 st_ses->sm_handle);
Quinn Male48490df2020-03-25 10:25:42 -07005445 if (!lab_enabled) {
5446 st_session_ev_t deferred_ev = {
5447 .ev_id = ST_SES_EV_DEFERRED_STOP,
5448 .stc_ses = stc_ses
5449 };
5450 DISPATCH_EVENT(st_ses, deferred_ev, status);
5451 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005452 pthread_mutex_unlock(&st_ses->lock);
5453 ATRACE_BEGIN("sthal: client detection callback");
5454 callback(event, cookie);
5455 ATRACE_END();
Quinn Male48490df2020-03-25 10:25:42 -07005456 if (event)
5457 free(event);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005458 } else {
5459 pthread_mutex_unlock(&st_ses->lock);
5460 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005461
5462 /*
5463 * TODO: Add RECOGNITION_STATUS_GET_STATE_RESPONSE to
5464 * the SoundTrigger API header.
5465 */
5466 if (lab_enabled &&
5467 ((ev->payload.detected.detect_status ==
5468 RECOGNITION_STATUS_SUCCESS) ||
5469 (ev->payload.detected.detect_status == 3))) {
5470 /* Cache lab data to internal buffers (blocking call) */
5471 hw_ses->fptrs->process_lab_capture(hw_ses);
5472 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005473 break;
Quinn Male2e883752019-03-22 11:28:54 -07005474
5475 case ST_SES_EV_SSR_OFFLINE:
Quinn Male2e883752019-03-22 11:28:54 -07005476 /* exec mode can be none if ssr occurs during a transition */
5477 if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005478 stop_session(st_ses, hw_ses, true);
5479 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07005480 break;
5481
5482 case ST_SES_EV_SEND_CHMIX_COEFF:
5483 status = hw_ses->fptrs->send_custom_chmix_coeff(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005484 ev->payload.chmix_coeff_str);
Quinn Male2e883752019-03-22 11:28:54 -07005485 break;
5486
5487 case ST_SES_EV_SET_DEVICE:
5488 if (!ev->payload.enable)
5489 status = hw_ses->fptrs->disable_device(hw_ses, true);
5490 else
5491 status = hw_ses->fptrs->enable_device(hw_ses, true);
5492
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005493 if (status && st_ses->stdev->ssr_offline_received) {
5494 STATE_TRANSITION(st_ses, ssr_state_fn);
5495 status = 0;
5496 }
Quinn Male2e883752019-03-22 11:28:54 -07005497 break;
5498
5499 case ST_SES_EV_READ_PCM:
5500 /*
5501 * buffering could have been stopped internally
5502 * and switched to active state ex: transitions.
5503 * set status to failure this will tell AHAL to
5504 * provide zero buffers to client
5505 */
5506 status = -EIO;
5507 break;
5508
5509 case ST_SES_EV_GET_PARAM_DATA:
5510 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005511 ev->payload.getparam.param, ev->payload.getparam.payload,
5512 ev->payload.getparam.payload_size,
5513 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07005514 break;
5515
5516 case ST_SES_EV_REQUEST_DET:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005517 if (!list_empty(&stc_ses->second_stage_list)) {
5518 ALOGE("%s:[%d] Event not supported with second stage enabled",
5519 __func__, st_ses->sm_handle);
5520 status = -EINVAL;
5521 break;
Quinn Male2e883752019-03-22 11:28:54 -07005522 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005523 status = hw_ses->fptrs->send_detection_request(hw_ses);
5524 if (!status)
5525 st_ses->detection_requested = true;
Quinn Male2e883752019-03-22 11:28:54 -07005526 break;
5527
5528 default:
5529 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
5530 break;
Quinn Male2e883752019-03-22 11:28:54 -07005531 };
5532
5533 return status;
5534}
5535
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005536static int detected_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07005537{
5538 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005539 st_exec_mode_t new_exec_mode = ST_EXEC_MODE_NONE;
5540 st_session_t *stc_ses = ev->stc_ses;
5541 struct listnode *node = NULL;
5542 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07005543 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
5544 st_hw_session_t *new_hw_ses = NULL;
5545
5546 /* skip parameter check as this is an internal funciton */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005547 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5548 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005549
5550 switch (ev->ev_id) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005551 case ST_SES_EV_LOAD_SM:
5552 /* Valid event only in multi-client usecase */
5553 /*
5554 * If a detected client deffered stop event is not handled yet,
5555 * handle here before moving out of detected state
5556 */
5557 if (st_ses->det_stc_ses && !st_ses->det_stc_ses->pending_stop) {
5558 ALOGD("%s:[%d] post deferred stop for c%d", __func__,
5559 st_ses->sm_handle, st_ses->det_stc_ses->sm_handle);
5560 status = hw_session_notifier_enqueue(
5561 st_ses->det_stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP,
5562 ST_SES_DEFERRED_STOP_DELAY_MS);
5563 if (!status)
5564 st_ses->det_stc_ses->pending_stop = true;
5565 }
5566 status = handle_load_sm(st_ses, stc_ses);
5567 break;
5568
5569 case ST_SES_EV_UNLOAD_SM:
5570 /* Valid event only in multi-client usecase */
5571 /*
5572 * If a detected client deffered stop event is not handled yet,
5573 * handle here before moving out of detected state
5574 */
5575 if (st_ses->det_stc_ses && !st_ses->det_stc_ses->pending_stop) {
5576 ALOGD("%s:[%d] post deferred stop for client c%d", __func__,
5577 st_ses->sm_handle, st_ses->det_stc_ses->sm_handle);
5578 status = hw_session_notifier_enqueue(
5579 st_ses->det_stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP,
5580 ST_SES_DEFERRED_STOP_DELAY_MS);
5581 if (!status)
5582 st_ses->det_stc_ses->pending_stop = true;
5583 }
5584 status = handle_unload_sm(st_ses, stc_ses);
5585 break;
5586
Quinn Male2e883752019-03-22 11:28:54 -07005587 case ST_SES_EV_START:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005588 /* For multi-client, other loaded client may start */
Quinn Male2e883752019-03-22 11:28:54 -07005589 STATE_TRANSITION(st_ses, active_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005590 DISPATCH_EVENT(st_ses, *ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07005591 break;
5592
5593 case ST_SES_EV_RESTART:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005594 status = restart_session(st_ses, hw_ses);
5595 if (status && !st_ses->stdev->ssr_offline_received)
5596 ALOGE("%s:[%d] failed to start session, err %d", __func__,
5597 st_ses->sm_handle, status);
5598
5599 if (st_ses->stdev->ssr_offline_received) {
5600 stop_session(st_ses, hw_ses, true);
5601 STATE_TRANSITION(st_ses, ssr_state_fn);
5602 status = 0;
5603 } else {
5604 /* Move anyways to allow client unload */
5605 STATE_TRANSITION(st_ses, active_state_fn);
5606 }
Quinn Male2e883752019-03-22 11:28:54 -07005607 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005608
Quinn Male2e883752019-03-22 11:28:54 -07005609 case ST_SES_EV_PAUSE:
Quinn Male2e883752019-03-22 11:28:54 -07005610 case ST_SES_EV_STOP:
5611 /*
5612 * It is possible that the client can issue stop after detection
5613 * callback. This even can be issued internally as part of
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005614 * deferred stop as well. For multi-client, it could be current
5615 * detected client stop or other client stop.
Quinn Male2e883752019-03-22 11:28:54 -07005616 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005617 STATE_TRANSITION(st_ses, active_state_fn);
5618 DISPATCH_EVENT(st_ses, *ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07005619 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005620
Quinn Male2e883752019-03-22 11:28:54 -07005621 case ST_SES_EV_SSR_OFFLINE:
Quinn Male2e883752019-03-22 11:28:54 -07005622 /*
5623 * Ignore return status during SSR handling
5624 * as the ADSP or CPE might be down so these
5625 * calls would fail. Exec mode can be none if
5626 * ssr occurs during a transition.
5627 */
5628 if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005629 stop_session(st_ses, hw_ses, true);
Quinn Male2e883752019-03-22 11:28:54 -07005630 STATE_TRANSITION(st_ses, ssr_state_fn);
5631 break;
5632
5633 case ST_SES_EV_SET_EXEC_MODE:
5634 new_exec_mode = ev->payload.exec_mode;
5635
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005636 if (new_exec_mode == st_ses->exec_mode) {
5637 stc_ses->exec_mode = st_ses->exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07005638 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005639 }
Quinn Male2e883752019-03-22 11:28:54 -07005640
5641 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
5642 st_ses->exec_mode = ST_EXEC_MODE_NONE;
5643 status = stop_session(st_ses, hw_ses, true);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005644 list_for_each(node, &st_ses->clients_list) {
5645 c_ses = node_to_item(node, st_session_t, hw_list_node);
5646 c_ses->exec_mode = new_exec_mode;
5647 }
Quinn Male2e883752019-03-22 11:28:54 -07005648 if (status)
5649 break;
5650 }
5651
5652 if (new_exec_mode == ST_EXEC_MODE_NONE)
5653 break;
5654
5655 /* switch to new hw session */
5656 if (ST_EXEC_MODE_CPE == new_exec_mode) {
5657 new_hw_ses = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07005658 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
5659 new_hw_ses = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07005660 } else {
5661 ALOGE("%s: unknown execution mode %d", __func__,
5662 new_exec_mode);
5663 status = -EINVAL;
5664 break;
5665 }
5666
5667 /*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005668 * hw session changed to/from WDSP/ADSP, hence update the
5669 * related config.
5670 * Not applicable for LPI<->non-LPI transtions as hw session
5671 * doesn't change.
5672 */
5673 status = update_hw_config_on_start(stc_ses, new_hw_ses);
5674 if (status) {
5675 ALOGE("%s: Update_hw_config_on_start failed %d",
5676 __func__, status);
5677 break;
5678 }
5679 /*
Quinn Male2e883752019-03-22 11:28:54 -07005680 * start new hw session and stay in detected state as
5681 * client restart and stop concurrency scenarios are handled
5682 * in this state
5683 */
5684 status = start_session(st_ses, new_hw_ses, true);
5685 if (status)
5686 break;
5687
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005688 list_for_each(node, &st_ses->clients_list) {
5689 c_ses = node_to_item(node, st_session_t, hw_list_node);
5690 c_ses->exec_mode = new_exec_mode;
5691 if (c_ses->state == ST_STATE_ACTIVE) {
5692 dereg_hal_event_session(c_ses);
5693 reg_hal_event_session(c_ses, new_hw_ses);
5694 }
5695 }
Quinn Male2e883752019-03-22 11:28:54 -07005696 st_ses->exec_mode = new_exec_mode;
5697 st_ses->hw_ses_current = new_hw_ses;
5698 break;
5699
5700 case ST_SES_EV_SEND_CHMIX_COEFF:
5701 status = -EINVAL;
5702 break;
5703
5704 case ST_SES_EV_SET_DEVICE:
5705 /*
5706 * set device is a no-op in detected state due to the following reasons
5707 * A set device is a sequence of disable and enable device commands.
5708 * set device sequence is triggered with dev lock held. Therefore there
5709 * cannot be a concurrency with other client issued events.
5710 * As a deferred stop is posted prior to entering detected state,
5711 * one of the two events are possible
5712 * 1) timer expires and stop is issued : this implies stop_session
5713 * 2) timer is cancelled and start is issued by client: this implies
5714 * new device is set as part of start_session
5715 */
5716 break;
5717
5718 case ST_SES_EV_GET_PARAM_DATA:
5719 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005720 ev->payload.getparam.param, ev->payload.getparam.payload,
5721 ev->payload.getparam.payload_size,
5722 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07005723 break;
5724 case ST_SES_EV_DEFERRED_STOP:
5725 ALOGD("%s:[%d] post deferred stop from detected state", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005726 st_ses->sm_handle);
5727 status = hw_session_notifier_enqueue(stc_ses->sm_handle,
5728 ST_SES_EV_DEFERRED_STOP, ST_SES_DEFERRED_STOP_DELAY_MS);
Quinn Male2e883752019-03-22 11:28:54 -07005729 if (!status)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005730 stc_ses->pending_stop = true;
Quinn Male2e883752019-03-22 11:28:54 -07005731 break;
5732 case ST_SES_EV_REQUEST_DET:
5733 ALOGE("%s:[%d] Event not supported in this state",
5734 __func__, st_ses->sm_handle);
5735 status = -EINVAL;
5736 break;
5737 default:
5738 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
5739 break;
Quinn Male2e883752019-03-22 11:28:54 -07005740 };
Quinn Male2e883752019-03-22 11:28:54 -07005741 return status;
5742}
5743
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005744static int buffering_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07005745{
5746 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005747 st_session_t *stc_ses = ev->stc_ses;
5748 struct listnode *node = NULL;
5749 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07005750 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005751 st_exec_mode_t new_exec_mode = ST_EXEC_MODE_NONE;
Quinn Male2e883752019-03-22 11:28:54 -07005752 st_hw_session_t *new_hw_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07005753
5754 /* skip parameter check as this is an internal function */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005755 ALOGVV("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5756 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005757
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005758 switch (ev->ev_id) {
5759 case ST_SES_EV_LOAD_SM:
5760 /* Valid in multi-client usecase */
5761 ALOGD("%s:[c%d-%d] load sm", __func__, stc_ses->sm_handle,
5762 st_ses->sm_handle);
5763
5764 status = handle_load_sm(st_ses, stc_ses);
5765 break;
5766
5767 case ST_SES_EV_UNLOAD_SM:
5768 ALOGD("%s:[c%d-%d] unload sm", __func__, stc_ses->sm_handle,
5769 st_ses->sm_handle);
5770
5771 status = handle_unload_sm(st_ses, stc_ses);
5772 break;
5773
5774 case ST_SES_EV_READ_PCM:
Quinn Male2e883752019-03-22 11:28:54 -07005775 /* Note: this function may block if there is no PCM data ready*/
5776 hw_ses->fptrs->read_pcm(hw_ses, ev->payload.readpcm.out_buff,
5777 ev->payload.readpcm.out_buff_size);
Quinn Maleaba13db2019-07-11 15:52:14 -07005778 if (st_ses->stdev->enable_debug_dumps) {
5779 ST_DBG_FILE_WRITE(st_ses->lab_fp, ev->payload.readpcm.out_buff,
5780 ev->payload.readpcm.out_buff_size);
5781 }
Quinn Male2e883752019-03-22 11:28:54 -07005782 break;
5783 case ST_SES_EV_END_BUFFERING:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005784 if (stc_ses == st_ses->det_stc_ses) {
5785 hw_ses->fptrs->stop_buffering(hw_ses);
5786 if (!stc_ses->pending_stop) {
5787 ALOGD("%s:[c%d] post deferred stop on buffering end", __func__,
5788 stc_ses->sm_handle);
5789 status = hw_session_notifier_enqueue(stc_ses->sm_handle,
5790 ST_SES_EV_DEFERRED_STOP, ST_SES_DEFERRED_STOP_DELAY_MS);
5791 if (!status)
5792 stc_ses->pending_stop = true;
5793 } else {
5794 ALOGD("%s:[c%d] skip deferred stop on buffering as already set",
5795 __func__, stc_ses->sm_handle);
5796 }
Quinn Male2e883752019-03-22 11:28:54 -07005797 }
5798 break;
Quinn Male2e883752019-03-22 11:28:54 -07005799
Quinn Male48490df2020-03-25 10:25:42 -07005800 case ST_SES_EV_DEFERRED_STOP:
5801 ALOGD("%s:[%d] post internal deferred stop from buffering state",
5802 __func__, st_ses->sm_handle);
5803 status = hw_session_notifier_enqueue(stc_ses->sm_handle,
5804 ST_SES_EV_DEFERRED_STOP, ST_SES_DEFERRED_STOP_DELAY_MS);
5805 if (!status)
5806 stc_ses->pending_stop = true;
5807 break;
5808
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005809 case ST_SES_EV_STOP:
5810 ALOGD("%s:[c%d-%d] handle event STOP", __func__, stc_ses->sm_handle,
5811 st_ses->sm_handle);
5812 if (stc_ses != st_ses->det_stc_ses) {
5813 ALOGD("%s: c%d buffering, delay c%d stop", __func__,
5814 st_ses->det_stc_ses->sm_handle, stc_ses->sm_handle);
5815 update_hw_config_on_stop(st_ses, stc_ses);
5816 break;
5817 }
5818 /* Fall through */
5819 case ST_SES_EV_PAUSE:
5820 hw_ses->fptrs->stop_buffering(hw_ses);
5821 STATE_TRANSITION(st_ses, active_state_fn);
5822 DISPATCH_EVENT(st_ses, *ev, status);
Quinn Maleaba13db2019-07-11 15:52:14 -07005823 if (st_ses->stdev->enable_debug_dumps)
5824 ST_DBG_FILE_CLOSE(st_ses->lab_fp);
Quinn Male2e883752019-03-22 11:28:54 -07005825 break;
5826
5827 case ST_SES_EV_SET_DEVICE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005828 ALOGD("%s:[c%d-%d] handle SET_DEVICE", __func__, stc_ses->sm_handle,
5829 st_ses->sm_handle);
Quinn Male2e883752019-03-22 11:28:54 -07005830 /*
5831 * Device switch will not wait for buffering to finish. It will instead
Zhou Song271fdfe2020-04-24 16:06:04 +08005832 * interrupt and stop the buffering and transition to the active state.
Quinn Male2e883752019-03-22 11:28:54 -07005833 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005834 hw_ses->fptrs->stop_buffering(hw_ses);
Zhou Song271fdfe2020-04-24 16:06:04 +08005835 STATE_TRANSITION(st_ses, active_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005836 DISPATCH_EVENT(st_ses, *ev, status);
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005837
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005838 /*
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005839 * set_device event can be dispatched with any one of attached
5840 * multi-clients. For current detected client, the App may or may
5841 * not start next detection, so handle the state accordingly.
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005842 */
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005843 if (st_ses->det_stc_ses->pending_stop) {
5844 ALOGD("%s:[c%d] cancel ST_SES_EV_DEFERRED_STOP", __func__,
5845 st_ses->det_stc_ses->sm_handle);
5846 hw_session_notifier_cancel(stc_ses->sm_handle,
5847 ST_SES_EV_DEFERRED_STOP);
5848 stc_ses->pending_stop = false;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005849 }
Zhou Song271fdfe2020-04-24 16:06:04 +08005850 st_ses->det_stc_ses->state = ST_STATE_ACTIVE;
Quinn Male2e883752019-03-22 11:28:54 -07005851 break;
5852
5853 case ST_SES_EV_START:
5854 case ST_SES_EV_RESTART:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005855 ALOGD("%s:[c%d-%d] handle event START/RESTART", __func__,
5856 stc_ses->sm_handle, st_ses->sm_handle);
5857
5858 if (stc_ses != st_ses->det_stc_ses) {
5859 ALOGD("%s: c%d buffering, delay c%d start", __func__,
5860 st_ses->det_stc_ses->sm_handle, stc_ses->sm_handle);
5861 break;
5862 }
Quinn Male2e883752019-03-22 11:28:54 -07005863 /*
5864 * Client starts detection again.
5865 * This implies a previous deferred stop hasn't completed yet as
5866 * stop would have changed state to loaded.
5867 * For a restart event, issue stop buffering and restart the session
5868 * For a start event, stop buffering then stop and start the session
5869 * so that any new parameters take effect.
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005870 * For multi-client case while the detected is buffering,
5871 * the other client stop/start would have been deferred by updating
5872 * the config, and later when current detected client restarts after
5873 * buffreing is completed, check if hw config is updated due to other
5874 * client and stop->start the hw session to apply updated config.
Quinn Male2e883752019-03-22 11:28:54 -07005875 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005876 hw_ses->fptrs->stop_buffering(hw_ses);
5877 if (hw_ses->sthw_cfg_updated || ev->ev_id == ST_SES_EV_START) {
Quinn Male2e883752019-03-22 11:28:54 -07005878 status = stop_session(st_ses, hw_ses, false);
Zhou Songfe0a2a52019-11-12 15:17:59 +08005879 STATE_TRANSITION(st_ses, loaded_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005880 if (status) {
Quinn Male2e883752019-03-22 11:28:54 -07005881 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005882 st_ses->sm_handle, status);
5883 } else {
5884 status = start_session(st_ses, hw_ses, false);
5885 if (status) {
5886 ALOGE("%s:[%d] failed to start session, err %d", __func__,
5887 st_ses->sm_handle, status);
5888 }
Quinn Male2e883752019-03-22 11:28:54 -07005889 }
Quinn Male2e883752019-03-22 11:28:54 -07005890 } else {
5891 status = restart_session(st_ses, hw_ses);
5892 }
5893
5894 if (status) {
5895 if (st_ses->stdev->ssr_offline_received) {
Quinn Male58749452020-03-26 17:14:56 -07005896 dereg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005897 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07005898 status = 0;
5899 } else {
Quinn Male2e883752019-03-22 11:28:54 -07005900 /* move to active anyways to allow unload sm */
5901 STATE_TRANSITION(st_ses, active_state_fn);
5902 }
5903 } else {
Quinn Male2e883752019-03-22 11:28:54 -07005904 STATE_TRANSITION(st_ses, active_state_fn);
5905 }
5906 break;
5907
5908 case ST_SES_EV_SSR_OFFLINE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005909 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5910 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005911 /*
5912 * Ignore return status during SSR handling
5913 * as the ADSP or CPE might be down so these
5914 * calls would fail. Exec mode can be none if
5915 * ssr occurs during a transition.
5916 */
5917 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005918 hw_ses->fptrs->stop_buffering(hw_ses);
5919 stop_session(st_ses, hw_ses, true);
Quinn Male2e883752019-03-22 11:28:54 -07005920 }
5921 STATE_TRANSITION(st_ses, ssr_state_fn);
5922 break;
5923
5924 case ST_SES_EV_SET_EXEC_MODE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005925 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5926 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005927
5928 new_exec_mode = ev->payload.exec_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005929 if (new_exec_mode == st_ses->exec_mode) {
5930 stc_ses->exec_mode = st_ses->exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07005931 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005932 }
Quinn Male2e883752019-03-22 11:28:54 -07005933
5934 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
5935 st_ses->exec_mode = ST_EXEC_MODE_NONE;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005936 status = hw_ses->fptrs->stop_buffering(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005937 if (status) {
5938 ALOGE("%s:[%d] failed to stop_buffering err %d", __func__,
5939 st_ses->sm_handle, status);
5940 break;
5941 }
Quinn Male2e883752019-03-22 11:28:54 -07005942 status = stop_session(st_ses, hw_ses, true);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005943 list_for_each(node, &st_ses->clients_list) {
5944 c_ses = node_to_item(node, st_session_t, hw_list_node);
5945 c_ses->exec_mode = new_exec_mode;
5946 }
Quinn Male2e883752019-03-22 11:28:54 -07005947 if (status) {
5948 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
5949 st_ses->sm_handle, status);
5950 break;
5951 }
5952 }
5953
5954 if (new_exec_mode == ST_EXEC_MODE_NONE)
5955 break;
5956
5957 /* switch to new hw session */
5958 if (ST_EXEC_MODE_CPE == new_exec_mode) {
5959 new_hw_ses = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07005960 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
5961 new_hw_ses = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07005962 } else {
5963 ALOGE("%s: unknown execution mode %d", __func__,
5964 new_exec_mode);
5965 status = -EINVAL;
5966 break;
5967 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005968 /*
5969 * hw session changed to/from WDSP/ADSP, hence update the
5970 * related config.
5971 * Not applicable for LPI<->non-LPI transtions as hw session
5972 * doesn't change.
5973 */
5974 status = update_hw_config_on_start(stc_ses, new_hw_ses);
5975 if (status) {
5976 ALOGE("%s: Update_hw_config_on_start failed %d",
5977 __func__, status);
5978 break;
5979 }
Quinn Male2e883752019-03-22 11:28:54 -07005980 status = start_session(st_ses, new_hw_ses, true);
5981 if (status) {
5982 ALOGE("%s:[%d] failed to start hw ses, err %d", __func__,
5983 st_ses->sm_handle, status);
5984 break;
5985 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005986 list_for_each(node, &st_ses->clients_list) {
5987 c_ses = node_to_item(node, st_session_t, hw_list_node);
5988 c_ses->exec_mode = new_exec_mode;
5989 if (c_ses->state == ST_STATE_ACTIVE) {
5990 dereg_hal_event_session(c_ses);
5991 reg_hal_event_session(c_ses, new_hw_ses);
5992 }
5993 }
Quinn Male2e883752019-03-22 11:28:54 -07005994 st_ses->exec_mode = new_exec_mode;
5995 st_ses->hw_ses_current = new_hw_ses;
5996 STATE_TRANSITION(st_ses, active_state_fn);
5997 break;
5998
5999 case ST_SES_EV_SEND_CHMIX_COEFF:
6000 status = hw_ses->fptrs->send_custom_chmix_coeff(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006001 ev->payload.chmix_coeff_str);
Quinn Male2e883752019-03-22 11:28:54 -07006002 break;
6003
6004 case ST_SES_EV_GET_PARAM_DATA:
6005 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006006 ev->payload.getparam.param, ev->payload.getparam.payload,
6007 ev->payload.getparam.payload_size,
6008 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07006009 break;
6010
6011 case ST_SES_EV_REQUEST_DET:
6012 ALOGE("%s:[%d] Event %d not supported in this state",
6013 __func__, st_ses->sm_handle, ev->ev_id);
6014 status = -EINVAL;
6015 break;
6016
6017 default:
6018 ALOGD("%s:[%d] unhandled event, id %d", __func__, st_ses->sm_handle,
6019 ev->ev_id);
6020 break;
Quinn Male2e883752019-03-22 11:28:54 -07006021 };
6022
6023 return status;
6024}
6025
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006026static int ssr_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07006027{
6028 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006029 st_session_t *stc_ses = ev->stc_ses;
6030 st_session_ev_t load_ev = {.ev_id = ST_SES_EV_LOAD_SM};
6031 st_session_ev_t start_ev = {.ev_id = ST_SES_EV_START};
6032 st_session_ev_t exec_mode_ev = {.ev_id = ST_SES_EV_SET_EXEC_MODE};
6033 bool active = false;
Quinn Male2e883752019-03-22 11:28:54 -07006034
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006035 /* skip parameter check as this is an internal function */
6036 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
6037 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07006038
6039 switch (ev->ev_id) {
6040 case ST_SES_EV_SSR_ONLINE:
6041 ALOGV("%s:[%d] SSR ONLINE received", __func__, st_ses->sm_handle);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006042 /*
6043 * Load and start all clients at once instead of unload/loading
6044 * due to each subsequent client dispatch. It is expected the
6045 * upper layer calls SSR_ONLINE for all clients.
6046 */
6047 stc_ses->pending_load = true;
6048 if (is_any_client_not_pending_load(st_ses))
6049 break;
6050
Quinn Male2e883752019-03-22 11:28:54 -07006051 STATE_TRANSITION(st_ses, idle_state_fn);
6052
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006053 if ((stc_ses->ssr_transit_exec_mode == ST_EXEC_MODE_CPE) ||
6054 (stc_ses->ssr_transit_exec_mode == ST_EXEC_MODE_ADSP)) {
6055 exec_mode_ev.stc_ses = stc_ses;
6056 exec_mode_ev.payload.exec_mode = stc_ses->ssr_transit_exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07006057 DISPATCH_EVENT(st_ses, exec_mode_ev, status);
Quinn Malea15c5ff2020-06-18 18:05:20 -07006058 if (status) {
6059 reset_clients_pending_load(st_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006060 break;
Quinn Malea15c5ff2020-06-18 18:05:20 -07006061 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006062 stc_ses->ssr_transit_exec_mode = ST_EXEC_MODE_NONE;
Quinn Male2e883752019-03-22 11:28:54 -07006063 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006064 active = is_any_client_in_state(st_ses, ST_STATE_ACTIVE);
6065 if (active || is_any_client_in_state(st_ses, ST_STATE_LOADED)) {
6066 load_ev.stc_ses = stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006067 DISPATCH_EVENT(st_ses, load_ev, status);
Quinn Malea15c5ff2020-06-18 18:05:20 -07006068 if (status) {
6069 reset_clients_pending_load(st_ses);
Quinn Male2e883752019-03-22 11:28:54 -07006070 break;
Quinn Malea15c5ff2020-06-18 18:05:20 -07006071 }
Quinn Male2e883752019-03-22 11:28:54 -07006072 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006073 if (active) {
6074 start_ev.stc_ses = stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006075 DISPATCH_EVENT(st_ses, start_ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07006076 }
6077
Quinn Malea15c5ff2020-06-18 18:05:20 -07006078 reset_clients_pending_load(st_ses);
Quinn Male2e883752019-03-22 11:28:54 -07006079 break;
6080
6081 case ST_SES_EV_LOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006082 if (ST_STATE_IDLE == stc_ses->state) {
6083 status = update_sound_model(stc_ses, true);
6084 if (status) {
6085 ALOGE("%s:[c%d] update sound model add failed %d", __func__,
6086 stc_ses->sm_handle, status);
6087 status = -EINVAL;
6088 break;
6089 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006090 stc_ses->state = ST_STATE_LOADED;
Quinn Male2e883752019-03-22 11:28:54 -07006091 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006092 ALOGE("%s: received unexpected event, client state = %d",
6093 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07006094 }
6095 break;
6096
6097 case ST_SES_EV_UNLOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006098 if (ST_STATE_LOADED == stc_ses->state) {
6099 status = update_sound_model(stc_ses, false);
6100 if (status)
6101 ALOGE("%s:[c%d] update sound_model failed %d", __func__,
6102 stc_ses->sm_handle, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006103 stc_ses->state = ST_STATE_IDLE;
Quinn Male2e883752019-03-22 11:28:54 -07006104 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006105 ALOGE("%s: received unexpected event, client state = %d",
6106 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07006107 }
6108 break;
6109
6110 case ST_SES_EV_START:
6111 case ST_SES_EV_RESTART:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006112 if (ST_STATE_LOADED == stc_ses->state) {
6113 if (ev->ev_id == ST_SES_EV_RESTART)
6114 update_hw_config_on_restart(st_ses, stc_ses);
6115 stc_ses->state = ST_STATE_ACTIVE;
Quinn Male2e883752019-03-22 11:28:54 -07006116 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006117 ALOGE("%s: received unexpected event, client state = %d",
6118 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07006119 }
6120 break;
6121
6122 case ST_SES_EV_STOP:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006123 if (ST_STATE_ACTIVE == stc_ses->state) {
6124 update_hw_config_on_stop(st_ses, stc_ses);
6125 stc_ses->state = ST_STATE_LOADED;
Quinn Male2e883752019-03-22 11:28:54 -07006126 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006127 ALOGE("%s: received unexpected event, client state = %d",
6128 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07006129 }
6130 break;
6131
6132 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006133 stc_ses->paused = true;
Quinn Male2e883752019-03-22 11:28:54 -07006134 break;
6135
6136 case ST_SES_EV_RESUME:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006137 stc_ses->paused = false;
Quinn Male2e883752019-03-22 11:28:54 -07006138 break;
6139
6140 case ST_SES_EV_READ_PCM:
6141 status = -EIO;
6142 break;
6143
6144 case ST_SES_EV_SEND_CHMIX_COEFF:
6145 status = -EIO;
6146 break;
6147
6148 case ST_SES_EV_GET_PARAM_DATA:
6149 status = -EIO;
6150 break;
6151
6152 case ST_SES_EV_SET_EXEC_MODE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006153 stc_ses->exec_mode = ev->payload.exec_mode;
6154 if (ev->payload.exec_mode == st_ses->exec_mode)
6155 break;
6156
Quinn Male2e883752019-03-22 11:28:54 -07006157 st_ses->exec_mode = ev->payload.exec_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006158
Quinn Male2e883752019-03-22 11:28:54 -07006159 if (ST_EXEC_MODE_CPE == st_ses->exec_mode)
6160 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
6161 else if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
6162 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
6163 /* remain in current state */
6164 break;
6165
6166 case ST_SES_EV_REQUEST_DET:
6167 ALOGE("%s:[%d] Event not supported in this state",
6168 __func__, st_ses->sm_handle);
6169 status = -EINVAL;
6170 break;
6171
6172 default:
6173 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
6174 break;
6175 };
6176
6177 return status;
6178}
6179
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006180int st_session_load_sm(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006181{
6182 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006183
6184 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006185 return -EINVAL;
6186
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006187 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6188 st_session_loadsm_payload_t payload = { .phrase_sm = stc_ses->phrase_sm };
Quinn Male2e883752019-03-22 11:28:54 -07006189 st_session_ev_t ev = { .ev_id = ST_SES_EV_LOAD_SM,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006190 .payload.loadsm = payload, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006191
6192 pthread_mutex_lock(&st_ses->lock);
6193 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006194 if (!status) {
Quinn Male12f5c6f2019-11-14 17:34:10 -08006195 prepare_second_stage_for_client(stc_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006196 stc_ses->state = ST_STATE_LOADED;
6197 }
Quinn Male2e883752019-03-22 11:28:54 -07006198 pthread_mutex_unlock(&st_ses->lock);
6199
6200 return status;
6201}
6202
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006203int st_session_unload_sm(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006204{
6205 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006206
6207 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006208 return -EINVAL;
6209
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006210 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6211 st_session_ev_t ev = { .ev_id = ST_SES_EV_UNLOAD_SM, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006212
6213 pthread_mutex_lock(&st_ses->lock);
6214 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006215 stop_second_stage_for_client(stc_ses);
6216 stc_ses->state = ST_STATE_IDLE;
Quinn Male2e883752019-03-22 11:28:54 -07006217 pthread_mutex_unlock(&st_ses->lock);
6218
6219 return status;
6220}
6221
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006222int st_session_start(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006223{
6224 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006225
6226 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006227 return -EINVAL;
6228
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006229 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6230 st_session_ev_t ev = { .ev_id = ST_SES_EV_START, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006231
Quinn Male2e883752019-03-22 11:28:54 -07006232 pthread_mutex_lock(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006233 if (stc_ses->pending_stop) {
6234 ALOGV("%s:[c%d] cancel ST_SES_EV_DEFERRED_STOP", __func__,
6235 stc_ses->sm_handle);
6236 hw_session_notifier_cancel(stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP);
6237 stc_ses->pending_stop = false;
6238 }
6239
Quinn Male2e883752019-03-22 11:28:54 -07006240 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006241 if (!status) {
6242 reg_hal_event_session(stc_ses, st_ses->hw_ses_current);
6243 start_second_stage_for_client(stc_ses);
6244 stc_ses->state = ST_STATE_ACTIVE;
6245 }
Quinn Male2e883752019-03-22 11:28:54 -07006246 pthread_mutex_unlock(&st_ses->lock);
6247 return status;
6248}
6249
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006250int st_session_stop(st_session_t *stc_ses)
6251{
6252 int status = 0;
6253
6254 if (!stc_ses || !stc_ses->hw_proxy_ses)
6255 return -EINVAL;
6256
6257 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6258 st_session_ev_t ev = { .ev_id = ST_SES_EV_STOP, .stc_ses = stc_ses };
6259
6260 pthread_mutex_lock(&st_ses->lock);
6261 DISPATCH_EVENT(st_ses, ev, status);
6262 dereg_hal_event_session(stc_ses);
6263 stc_ses->pending_stop = false;
6264 stc_ses->state = ST_STATE_LOADED;
6265 pthread_mutex_unlock(&st_ses->lock);
6266
6267 return status;
6268}
6269
6270int st_session_restart(st_session_t *stc_ses)
6271{
6272 int status = 0;
6273
6274 if (!stc_ses || !stc_ses->hw_proxy_ses)
6275 return -EINVAL;
6276
6277 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6278 st_session_ev_t ev = { .ev_id = ST_SES_EV_RESTART, .stc_ses = stc_ses };
6279
6280 pthread_mutex_lock(&st_ses->lock);
6281 if (stc_ses->pending_stop) {
6282 ALOGV("%s:[c%d] cancel ST_SES_EV_DEFERRED_STOP", __func__,
6283 stc_ses->sm_handle);
6284 hw_session_notifier_cancel(stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP);
6285 stc_ses->pending_stop = false;
6286 }
6287
6288 DISPATCH_EVENT(st_ses, ev, status);
6289 if (!status) {
6290 start_second_stage_for_client(stc_ses);
6291 stc_ses->state = ST_STATE_ACTIVE;
6292 } else {
6293 dereg_hal_event_session(stc_ses);
6294 stc_ses->state = ST_STATE_LOADED;
6295 }
6296 pthread_mutex_unlock(&st_ses->lock);
6297
6298 return status;
6299}
6300
6301int st_session_ssr_offline(st_session_t *stc_ses,
Quinn Male2e883752019-03-22 11:28:54 -07006302 enum ssr_event_status ssr_type)
6303{
6304 int status = 0;
6305
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006306 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006307 return -EINVAL;
6308
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006309 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006310 st_session_ev_t ev = { .ev_id = ST_SES_EV_SSR_OFFLINE,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006311 .payload.ssr = ssr_type, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006312
6313 pthread_mutex_lock(&st_ses->lock);
6314 /*
6315 * In typical usecases, handle SSR only if it occured on the core we are
6316 * currently using. In cases that have an SSR event during transitions,
6317 * the exec_mode can be NONE. For these cases, handle SSR on the core
6318 * which was in use prior to the transition. For example, if the
6319 * ssr_transit_exec_mode is ADSP, then the core prior to the transition
6320 * is CPE, so we handle the CPE SSR event.
6321 *
6322 * On 8909w BG uses CPE mode for detection. So add BG specific
6323 * conditon check to handle SSR event.
6324 */
6325 if (((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
6326 (CPE_STATUS_OFFLINE == ssr_type)) ||
6327 ((ST_EXEC_MODE_ADSP == st_ses->exec_mode) &&
6328 (SND_CARD_STATUS_OFFLINE == ssr_type)) ||
6329 ((ST_EXEC_MODE_NONE == st_ses->exec_mode) &&
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006330 (((ST_EXEC_MODE_CPE == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07006331 (SND_CARD_STATUS_OFFLINE == ssr_type)) ||
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006332 ((ST_EXEC_MODE_ADSP == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07006333 (CPE_STATUS_OFFLINE == ssr_type)))) ||
6334 ((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
6335 (SND_CARD_STATUS_OFFLINE == ssr_type) &&
6336 (st_ses->stdev->bg_kwd)))
6337 DISPATCH_EVENT(st_ses, ev, status);
6338 pthread_mutex_unlock(&st_ses->lock);
6339
6340 return status;
6341}
6342
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006343int st_session_ssr_online(st_session_t *stc_ses,
Quinn Male2e883752019-03-22 11:28:54 -07006344 enum ssr_event_status ssr_type)
6345{
6346 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006347
6348 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006349 return -EINVAL;
6350
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006351 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006352 st_session_ev_t ev = { .ev_id = ST_SES_EV_SSR_ONLINE,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006353 .payload.ssr = ssr_type, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006354
6355 pthread_mutex_lock(&st_ses->lock);
6356 /*
6357 * In typical usecases, handle SSR only if it occured on the core we are
6358 * currently using. In cases that have an SSR event during transitions,
6359 * the exec_mode can be NONE. For these cases, handle SSR on the core
6360 * which was in use prior to the transition. For example, if the
6361 * ssr_transit_exec_mode is ADSP, then the core prior to the transition
6362 * is CPE, so we handle the CPE SSR event.
6363 *
6364 * On 8909w BG uses CPE mode for detection. So add BG specific
6365 * conditon check to handle SSR event.
6366 */
6367 if (((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
6368 (CPE_STATUS_ONLINE == ssr_type)) ||
6369 ((ST_EXEC_MODE_ADSP == st_ses->exec_mode) &&
6370 (SND_CARD_STATUS_ONLINE == ssr_type)) ||
6371 ((ST_EXEC_MODE_NONE == st_ses->exec_mode) &&
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006372 (((ST_EXEC_MODE_CPE == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07006373 (SND_CARD_STATUS_ONLINE == ssr_type)) ||
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006374 ((ST_EXEC_MODE_ADSP == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07006375 (CPE_STATUS_ONLINE == ssr_type)))) ||
6376 ((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
6377 (SND_CARD_STATUS_ONLINE == ssr_type) &&
6378 (st_ses->stdev->bg_kwd)))
6379 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006380
Quinn Male2e883752019-03-22 11:28:54 -07006381 pthread_mutex_unlock(&st_ses->lock);
6382
6383 return status;
6384}
6385
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006386int st_session_pause(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006387{
6388 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006389
6390 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006391 return -EINVAL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006392
6393 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6394 st_session_ev_t ev = { .ev_id = ST_SES_EV_PAUSE, .stc_ses = stc_ses };
6395
Venkatesh Mangalappali47118dc2019-07-29 11:51:52 -07006396 pthread_mutex_lock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006397 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappali47118dc2019-07-29 11:51:52 -07006398 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006399 return status;
6400}
6401
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006402int st_session_resume(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006403{
6404 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006405
6406 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006407 return -EINVAL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006408
6409 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6410 st_session_ev_t ev = { .ev_id = ST_SES_EV_RESUME, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006411
6412 pthread_mutex_lock(&st_ses->lock);
6413 DISPATCH_EVENT(st_ses, ev, status);
6414 pthread_mutex_unlock(&st_ses->lock);
6415 return status;
6416}
6417
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006418int st_session_disable_device(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006419{
6420 int status = 0;
Zhou Songcd3c8e62019-07-16 13:30:19 +08006421 st_session_event_id_t ev_id = ST_SES_EV_SET_DEVICE;
Quinn Male2e883752019-03-22 11:28:54 -07006422
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006423 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006424 return -EINVAL;
6425
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006426 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Zhou Songcd3c8e62019-07-16 13:30:19 +08006427 pthread_mutex_lock(&st_ses->lock);
6428 if (check_gcs_usecase_switch(stc_ses->hw_proxy_ses))
6429 ev_id = ST_SES_EV_PAUSE;
6430
6431 st_session_ev_t ev = {.ev_id = ev_id,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006432 .payload.enable = false, .stc_ses = stc_ses};
6433
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006434 /*
6435 * Avoid dispatching for each attached multi-client, instead
6436 * defer it until last client
6437 */
6438 stc_ses->pending_set_device = true;
6439 if (is_any_client_not_pending_set_device(st_ses)) {
6440 pthread_mutex_unlock(&st_ses->lock);
6441 return status;
6442 }
6443 reset_clients_pending_set_device(st_ses);
6444
6445 DISPATCH_EVENT(st_ses, ev, status);
6446 pthread_mutex_unlock(&st_ses->lock);
6447 return status;
6448}
6449
6450int st_session_enable_device(st_session_t *stc_ses)
6451{
6452 int status = 0;
Zhou Songcd3c8e62019-07-16 13:30:19 +08006453 st_session_event_id_t ev_id = ST_SES_EV_SET_DEVICE;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006454
6455 if (!stc_ses || !stc_ses->hw_proxy_ses)
6456 return -EINVAL;
6457
6458 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Zhou Songcd3c8e62019-07-16 13:30:19 +08006459 pthread_mutex_lock(&st_ses->lock);
6460 if (check_gcs_usecase_switch(stc_ses->hw_proxy_ses))
6461 ev_id = ST_SES_EV_RESUME;
6462
6463 st_session_ev_t ev = { .ev_id = ev_id,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006464 .payload.enable = true, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006465
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006466 /*
6467 * Avoid dispatching for each attached multi-client, instead
6468 * defer it until last client
6469 */
6470 stc_ses->pending_set_device = true;
6471 if (is_any_client_not_pending_set_device(st_ses)) {
6472 pthread_mutex_unlock(&st_ses->lock);
6473 return status;
6474 }
6475 reset_clients_pending_set_device(st_ses);
6476
Quinn Male2e883752019-03-22 11:28:54 -07006477 DISPATCH_EVENT(st_ses, ev, status);
6478 pthread_mutex_unlock(&st_ses->lock);
6479 return status;
6480}
6481
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006482bool st_session_is_detected(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006483{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006484 bool ret = false;
Quinn Male2e883752019-03-22 11:28:54 -07006485
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006486 if (!stc_ses || !stc_ses->hw_proxy_ses)
6487 return ret;
Quinn Male2e883752019-03-22 11:28:54 -07006488
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006489 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006490
6491 pthread_mutex_lock(&st_ses->lock);
6492 ret = (st_ses->current_state == detected_state_fn) ? true : false;
6493 pthread_mutex_unlock(&st_ses->lock);
6494
6495 return ret;
6496}
6497
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006498bool st_session_is_active(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006499{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006500 bool ret = false;
6501
6502 if (!stc_ses || !stc_ses->hw_proxy_ses)
6503 return ret;
6504
6505 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006506
6507 pthread_mutex_lock(&st_ses->lock);
6508 ret = (st_ses->current_state == active_state_fn) ? true : false;
6509 pthread_mutex_unlock(&st_ses->lock);
6510
6511 return ret;
6512}
6513
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006514bool st_session_is_buffering(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006515{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006516 bool ret = false;
6517
6518 if (!stc_ses || !stc_ses->hw_proxy_ses)
6519 return ret;
6520
6521 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006522
6523 pthread_mutex_lock(&st_ses->lock);
6524 ret = (st_ses->current_state == buffering_state_fn) ? true : false;
6525 pthread_mutex_unlock(&st_ses->lock);
6526
6527 return ret;
6528}
6529
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006530bool st_session_is_ssr_state(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006531{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006532 bool ret = false;
6533
6534 if (!stc_ses || !stc_ses->hw_proxy_ses)
6535 return ret;
6536
6537 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006538
6539 pthread_mutex_lock(&st_ses->lock);
6540 ret = (st_ses->current_state == ssr_state_fn) ? true : false;
6541 pthread_mutex_unlock(&st_ses->lock);
6542
6543 return ret;
6544}
6545
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006546int st_session_read_pcm(st_session_t *stc_ses, uint8_t *buff,
Quinn Male2e883752019-03-22 11:28:54 -07006547 size_t buff_size, size_t *read_size)
6548{
6549 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006550
6551 if (!stc_ses || !stc_ses->hw_proxy_ses || !buff || buff_size == 0 ||
6552 read_size == 0)
Quinn Male2e883752019-03-22 11:28:54 -07006553 return -EINVAL;
6554
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006555 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6556 st_session_readpcm_payload_t payload = {.out_buff = buff,
6557 .out_buff_size = buff_size, .actual_read_size = read_size};
Quinn Male2e883752019-03-22 11:28:54 -07006558
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006559 st_session_ev_t ev = {.ev_id = ST_SES_EV_READ_PCM,
6560 .payload.readpcm = payload, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006561
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006562 /*
6563 * Do not lock when handling this event, this event
6564 * can go in parallel with other events as multiple
6565 * sessions can buffer in parallel.
6566 */
Quinn Male2e883752019-03-22 11:28:54 -07006567 DISPATCH_EVENT(st_ses, ev, status);
6568 return status;
6569}
6570
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006571int st_session_stop_lab(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006572{
6573 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006574
6575 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006576 return -EINVAL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006577
6578 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6579 st_session_ev_t ev = {.ev_id = ST_SES_EV_END_BUFFERING, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006580
6581 pthread_mutex_lock(&st_ses->lock);
6582 DISPATCH_EVENT(st_ses, ev, status);
6583 pthread_mutex_unlock(&st_ses->lock);
6584 return status;
6585}
6586
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006587int st_session_set_exec_mode(st_session_t *stc_ses, st_exec_mode_t exec)
Quinn Male2e883752019-03-22 11:28:54 -07006588{
6589 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006590
6591 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006592 return -EINVAL;
6593
6594 ALOGV("%s: exec mode %d", __func__, exec);
6595
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006596 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6597 st_session_ev_t ev = {.ev_id = ST_SES_EV_SET_EXEC_MODE,
6598 .payload.exec_mode = exec, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006599
6600 pthread_mutex_lock(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006601 if (st_ses->enable_trans)
6602 DISPATCH_EVENT(st_ses, ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07006603 pthread_mutex_unlock(&st_ses->lock);
6604 return status;
6605}
6606
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006607int st_session_update_recongition_config(st_session_t *stc_ses)
6608{
6609
6610 int status = 0;
6611
6612 if (!stc_ses || !stc_ses->hw_proxy_ses)
6613 return -EINVAL;
6614
6615 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6616
6617 pthread_mutex_lock(&st_ses->lock);
6618 status = update_hw_config_on_start(stc_ses, st_ses->hw_ses_current);
6619 pthread_mutex_unlock(&st_ses->lock);
6620 return status;
6621
6622}
6623
6624int st_session_get_preroll(st_session_t *stc_ses)
6625{
6626 int val = 0;
6627
6628 if (!stc_ses || !stc_ses->hw_proxy_ses)
6629 return 0;
6630
6631 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6632
6633 pthread_mutex_lock(&st_ses->lock);
Quinn Male58749452020-03-26 17:14:56 -07006634 val = st_ses->hw_ses_current->max_preroll;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006635 pthread_mutex_unlock(&st_ses->lock);
6636
6637 return val;
6638}
6639
6640int st_session_send_custom_chmix_coeff(st_session_t *stc_ses, char *str)
Quinn Male2e883752019-03-22 11:28:54 -07006641{
6642 int status = 0;
6643
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006644 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006645 return -EINVAL;
6646
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006647 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006648 st_session_ev_t ev = { .ev_id = ST_SES_EV_SEND_CHMIX_COEFF,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006649 .payload.chmix_coeff_str = str, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006650
6651 pthread_mutex_lock(&st_ses->lock);
6652 if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
6653 DISPATCH_EVENT(st_ses, ev, status);
6654 pthread_mutex_unlock(&st_ses->lock);
6655 return status;
6656}
6657
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006658int st_session_get_config(st_session_t *stc_ses, struct pcm_config *config)
Quinn Male2e883752019-03-22 11:28:54 -07006659{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006660 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006661 return -EINVAL;
6662
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006663 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6664
6665 pthread_mutex_lock(&st_ses->lock);
6666 memcpy(config, &st_ses->hw_ses_current->config, sizeof(struct pcm_config));
6667 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006668
6669 return 0;
6670}
6671
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006672int st_session_get_param_data(st_session_t *stc_ses, const char *param,
6673 void *payload, size_t payload_size, size_t *param_data_size)
Quinn Male2e883752019-03-22 11:28:54 -07006674{
6675 int status = 0;
6676
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006677 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006678 return -EINVAL;
6679
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006680 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006681 st_session_getparam_payload_t getparam_payload = { .param = param,
6682 .payload = payload,
6683 .payload_size = payload_size,
6684 .param_data_size = param_data_size};
6685 st_session_ev_t ev = { .ev_id = ST_SES_EV_GET_PARAM_DATA,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006686 .payload.getparam = getparam_payload, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006687
6688 pthread_mutex_lock(&st_ses->lock);
6689 /* Currently get param data supported for ARM & ADSP mode */
6690 if ((ST_EXEC_MODE_ARM == st_ses->exec_mode) ||
6691 (ST_EXEC_MODE_ADSP == st_ses->exec_mode))
6692 DISPATCH_EVENT(st_ses, ev, status);
6693 pthread_mutex_unlock(&st_ses->lock);
6694
6695 return status;
6696}
6697
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006698int st_session_ss_init(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006699{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006700 int status = 0;
6701 struct listnode *node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07006702 st_arm_second_stage_t *st_sec_stage = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006703 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006704
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006705 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07006706 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
6707 status = st_second_stage_module_init(st_sec_stage,
6708 (void *)st_sec_stage->ss_info->lib_name);
6709 if (status) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006710 ALOGE("%s:[c%d] initializing second stage session failed %d",
6711 __func__, stc_ses->sm_handle, status);
Quinn Male2e883752019-03-22 11:28:54 -07006712 goto ss_cleanup;
6713 }
6714 }
6715
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006716 pthread_mutex_lock(&st_ses->lock);
6717 if (st_ses->aggregator_thread_created) {
6718 pthread_mutex_unlock(&st_ses->lock);
6719 return 0;
6720 }
6721 /*
6722 * Aggregator is not maintatined per client as there is only one
6723 * client keyword detection happens at a time in multi-client scenario.
6724 * Instead use single aggregator thread at proxy level, processing the
6725 * second stage for detected client at run time.
6726 */
6727 init_det_event_aggregator(st_ses);
6728
Quinn Male2e883752019-03-22 11:28:54 -07006729 st_ses->det_session_ev = calloc(1, sizeof(st_session_ev_t));
6730 if (!st_ses->det_session_ev) {
6731 ALOGE("%s: Failed to allocate st_session_ev_t, exiting", __func__);
6732 status = -ENOMEM;
6733 goto ss_cleanup;
6734 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006735 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006736 return 0;
6737
6738ss_cleanup:
6739 destroy_det_event_aggregator(st_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006740 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07006741 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
6742 st_second_stage_module_deinit(st_sec_stage);
6743 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006744 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006745 return status;
6746}
6747
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006748int st_session_ss_deinit(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006749{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006750 struct listnode *node = NULL;
6751 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006752 st_arm_second_stage_t *st_sec_stage = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006753 st_session_t *c_ses = NULL;
6754 bool aggregator_needed = false;
Quinn Male2e883752019-03-22 11:28:54 -07006755
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006756 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07006757 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
6758 st_second_stage_module_deinit(st_sec_stage);
6759 }
6760
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006761 pthread_mutex_lock(&st_ses->lock);
6762 if (!st_ses->aggregator_thread_created) {
6763 pthread_mutex_unlock(&st_ses->lock);
6764 return 0;
6765 }
6766 /* If other client has second stage enabled, keep the aggregator */
6767 list_for_each(node, &st_ses->clients_list) {
6768 c_ses = node_to_item(node, st_session_t, hw_list_node);
6769 if (c_ses != stc_ses && !list_empty(&c_ses->second_stage_list)) {
6770 aggregator_needed = true;
6771 break;
6772 }
6773 }
6774 if (aggregator_needed) {
6775 pthread_mutex_unlock(&st_ses->lock);
6776 return 0;
6777 }
6778
6779 destroy_det_event_aggregator(st_ses);
6780
Quinn Male2e883752019-03-22 11:28:54 -07006781 if (st_ses->det_session_ev)
6782 free(st_ses->det_session_ev);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006783 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006784
6785 return 0;
6786}
6787
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006788int st_session_request_detection(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006789{
6790 int status = 0;
6791
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006792 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006793 return -EINVAL;
6794
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006795 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6796 st_session_ev_t ev = {.ev_id = ST_SES_EV_REQUEST_DET, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006797
6798 /* lock to serialize event handling */
6799 pthread_mutex_lock(&st_ses->lock);
6800 DISPATCH_EVENT(st_ses, ev, status);
6801 pthread_mutex_unlock(&st_ses->lock);
6802 return status;
6803}
6804
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006805int st_session_init(st_session_t *stc_ses, struct sound_trigger_device *stdev,
Quinn Male2e883752019-03-22 11:28:54 -07006806 st_exec_mode_t exec_mode, sound_model_handle_t sm_handle)
6807{
6808 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006809 struct st_vendor_info *v_info = NULL;
6810 st_proxy_session_t *st_ses = NULL;
6811 struct listnode *node = NULL;
6812 struct st_session *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07006813 pthread_mutexattr_t attr;
6814
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006815 if (!stc_ses || !stdev)
6816 return -EINVAL;
Quinn Male2e883752019-03-22 11:28:54 -07006817
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006818 st_ses = calloc(1, sizeof(st_proxy_session_t));
6819 if (!st_ses) {
6820 ALOGE("%s: hw_proxy_ses allocation failed", __func__);
6821 return -ENOMEM;
6822 }
6823 st_ses->stdev = stc_ses->stdev = stdev;
6824 v_info = stc_ses->vendor_uuid_info;
Quinn Male2e883752019-03-22 11:28:54 -07006825
6826 if (v_info && (EXEC_MODE_CFG_DYNAMIC == v_info->exec_mode_cfg)) {
6827 st_ses->enable_trans = true;
Quinn Male2e883752019-03-22 11:28:54 -07006828 /* alloc and init cpe session*/
Quinn Male9a345522020-03-12 17:49:25 -07006829 st_ses->hw_ses_cpe =
6830 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
6831 if (!st_ses->hw_ses_cpe) {
6832 status = -ENOMEM;
6833 goto cleanup;
Quinn Male2e883752019-03-22 11:28:54 -07006834 }
Quinn Male9a345522020-03-12 17:49:25 -07006835 status = st_hw_sess_gcs_init(st_ses->hw_ses_cpe, hw_sess_cb,
6836 (void *)st_ses, ST_EXEC_MODE_CPE, v_info, sm_handle, stdev);
6837 if (status) {
6838 ALOGE("%s: initializing gcs hw session failed %d", __func__,
6839 status);
6840 goto cleanup;
6841 }
6842
6843 /* alloc and init adsp session*/
6844 st_ses->hw_ses_adsp =
6845 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
6846 if (!st_ses->hw_ses_adsp) {
6847 st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
6848 status = -ENOMEM;
6849 goto cleanup;
6850 }
6851
6852 status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
6853 (void *)st_ses, ST_EXEC_MODE_ADSP, v_info, sm_handle, stdev);
6854 if (status) {
6855 ALOGE("%s: initializing lsm session failed", __func__);
6856 st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
6857 goto cleanup;
6858 }
6859
Quinn Male2e883752019-03-22 11:28:54 -07006860 /* set current hw_session */
6861 if (exec_mode == ST_EXEC_MODE_CPE)
6862 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
6863 else if (exec_mode == ST_EXEC_MODE_ADSP)
6864 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07006865 } else if (v_info && (EXEC_MODE_CFG_CPE == v_info->exec_mode_cfg)) {
6866 st_ses->enable_trans = false;
Quinn Male9a345522020-03-12 17:49:25 -07006867
6868 ALOGD("%s: initializing gcs hw session", __func__);
6869 st_ses->hw_ses_cpe =
6870 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
6871 if (!st_ses->hw_ses_cpe) {
6872 status = -ENOMEM;
6873 goto cleanup;
Quinn Male2e883752019-03-22 11:28:54 -07006874 }
Quinn Male9a345522020-03-12 17:49:25 -07006875 status = st_hw_sess_gcs_init(st_ses->hw_ses_cpe, hw_sess_cb,
6876 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6877 if (status) {
6878 ALOGE("%s: initializing gcs hw session failed %d",
6879 __func__, status);
6880 goto cleanup;
6881 }
6882
Quinn Male2e883752019-03-22 11:28:54 -07006883 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07006884 } else if (v_info && (EXEC_MODE_CFG_APE == v_info->exec_mode_cfg)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006885 /*
6886 * Check for merge sound model support and return the existing hw
6887 * session. If any other clients have already created it.
6888 */
Quinn Male58749452020-03-26 17:14:56 -07006889 if (v_info->merge_fs_soundmodels &&
6890 stc_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006891 if (!v_info->is_qcva_uuid) {
Quinn Male58749452020-03-26 17:14:56 -07006892 ALOGE("%s: merge sound model not supported for non SVA engines",
6893 __func__);
6894 status = -ENOSYS;
6895 goto cleanup;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006896 }
6897 list_for_each(node, &stdev->sound_model_list) {
6898 c_ses = node_to_item(node, st_session_t, list_node);
6899 if ((c_ses != stc_ses) &&
6900 c_ses->vendor_uuid_info->is_qcva_uuid &&
Quinn Male58749452020-03-26 17:14:56 -07006901 c_ses->vendor_uuid_info->merge_fs_soundmodels &&
6902 c_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006903 stc_ses->hw_proxy_ses = c_ses->hw_proxy_ses;
6904 list_add_tail(&stc_ses->hw_proxy_ses->clients_list,
6905 &stc_ses->hw_list_node);
Quinn Male58749452020-03-26 17:14:56 -07006906 ALOGD("%s: another client attached, merge SM: h%d <-- c%d",
6907 __func__, stc_ses->hw_proxy_ses->sm_handle, sm_handle);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006908 free(st_ses);
6909 st_ses = NULL;
6910 break;
6911 }
6912 }
Quinn Male58749452020-03-26 17:14:56 -07006913 } else if (stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
6914 if (!v_info->is_qcva_uuid) {
6915 ALOGE("%s: multi sound model not supported for non SVA engines",
6916 __func__);
6917 status = -ENOSYS;
6918 goto cleanup;
6919 }
6920 list_for_each(node, &stdev->sound_model_list) {
6921 c_ses = node_to_item(node, st_session_t, list_node);
6922 if ((c_ses != stc_ses) &&
6923 c_ses->vendor_uuid_info->is_qcva_uuid &&
6924 c_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
6925 stc_ses->hw_proxy_ses = c_ses->hw_proxy_ses;
6926 list_add_tail(&stc_ses->hw_proxy_ses->clients_list,
6927 &stc_ses->hw_list_node);
6928 ALOGD("%s: another client attached, multi SM: h%d <-- c%d",
6929 __func__, stc_ses->hw_proxy_ses->sm_handle, sm_handle);
6930 free(st_ses);
6931 st_ses = NULL;
6932 break;
6933 }
6934 }
6935 }
6936 if (st_ses) { /* If no other client exist */
6937 st_ses->hw_ses_adsp =
6938 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
6939 if (!st_ses->hw_ses_adsp) {
6940 status = -ENOMEM;
6941 goto cleanup;
6942 }
6943 status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
6944 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6945 if (status) {
6946 ALOGE("%s: initializing lsm hw session failed %d",
6947 __func__, status);
6948 goto cleanup;
6949 }
6950 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
6951 st_ses->f_stage_version = stc_ses->f_stage_version;
6952 st_ses->hw_ses_current->f_stage_version = stc_ses->f_stage_version;
6953 }
Quinn Male2e883752019-03-22 11:28:54 -07006954 } else if (v_info && (EXEC_MODE_CFG_ARM == v_info->exec_mode_cfg)) {
6955 st_ses->enable_trans = false;
6956 st_ses->hw_ses_arm = calloc(1, sizeof(st_hw_session_pcm_t));
6957 if (!st_ses->hw_ses_arm) {
6958 status = -ENOMEM;
6959 goto cleanup;
6960 }
6961 status = st_hw_sess_pcm_init(st_ses->hw_ses_arm, hw_sess_cb,
6962 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6963 if (status) {
6964 ALOGE("%s: initializing pcm hw session failed %d",
6965 __func__, status);
6966 goto cleanup;
6967 }
6968 st_ses->hw_ses_current = st_ses->hw_ses_arm;
6969 } else if (!v_info) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006970 st_ses->hw_ses_cpe =
6971 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
Quinn Male2e883752019-03-22 11:28:54 -07006972 if (!st_ses->hw_ses_cpe) {
6973 status = -ENOMEM;
6974 goto cleanup;
6975 }
6976 status = st_hw_sess_lsm_init(st_ses->hw_ses_cpe, hw_sess_cb,
6977 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6978 if (status) {
6979 ALOGE("%s: initializing lsm hw session failed %d",
6980 __func__, status);
6981 goto cleanup;
6982 }
6983 }
6984
6985 pthread_mutexattr_init(&attr);
6986 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006987 pthread_mutex_init(&stc_ses->lock, (const pthread_mutexattr_t *)&attr);
Quinn Male2e883752019-03-22 11:28:54 -07006988
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006989 stc_ses->exec_mode = exec_mode;
6990 stc_ses->sm_handle = sm_handle;
6991 stc_ses->ssr_transit_exec_mode = ST_EXEC_MODE_NONE;
6992 stc_ses->client_req_det_mode = ST_DET_UNKNOWN_MODE;
6993 stc_ses->state = ST_STATE_IDLE;
Quinn Male2e883752019-03-22 11:28:54 -07006994
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006995 if (st_ses) { /* Could get freed if other client exists */
Quinn Male23026702019-07-19 10:51:16 -07006996 st_ses->vendor_uuid_info = v_info;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006997 st_ses->exec_mode = exec_mode;
6998 st_ses->sm_handle = sm_handle;
6999 st_ses->lab_fp = NULL;
7000 pthread_mutex_init(&st_ses->lock, (const pthread_mutexattr_t *)&attr);
Quinn Male2e883752019-03-22 11:28:54 -07007001
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007002 stc_ses->hw_proxy_ses = st_ses;
Quinn Male58749452020-03-26 17:14:56 -07007003 list_init(&st_ses->sm_info_list);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007004 list_init(&st_ses->clients_list);
7005 list_add_tail(&st_ses->clients_list, &stc_ses->hw_list_node);
7006 ALOGD("%s: client attached: h%d <-- c%d", __func__,
7007 st_ses->sm_handle, sm_handle);
7008
7009 if (!stdev->ssr_offline_received) {
7010 STATE_TRANSITION(st_ses, idle_state_fn);
7011 } else {
7012 STATE_TRANSITION(st_ses, ssr_state_fn);
7013 status = 0;
7014 }
7015 }
Quinn Male2e883752019-03-22 11:28:54 -07007016 return status;
7017
7018cleanup:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007019 if (st_ses) {
7020 if (st_ses->hw_ses_cpe)
7021 free(st_ses->hw_ses_cpe);
7022 if (st_ses->hw_ses_adsp)
7023 free(st_ses->hw_ses_adsp);
7024 free(st_ses);
7025 }
Quinn Male2e883752019-03-22 11:28:54 -07007026 return status;
7027}
7028
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007029int st_session_deinit(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07007030{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007031 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
7032
7033 pthread_mutex_lock(&st_ses->lock);
7034 list_remove(&stc_ses->hw_list_node);
7035 ALOGV("%s: client detatched: h%d <-- c%d", __func__, st_ses->sm_handle,
7036 stc_ses->sm_handle);
7037 if (stc_ses == st_ses->det_stc_ses)
7038 st_ses->det_stc_ses = NULL;
7039
7040 if (!list_empty(&st_ses->clients_list)) {
7041 pthread_mutex_unlock(&st_ses->lock);
7042 return 0;
7043 }
Quinn Male2e883752019-03-22 11:28:54 -07007044 /* deinit cpe session */
7045 if (st_ses->hw_ses_cpe) {
Quinn Male9a345522020-03-12 17:49:25 -07007046 st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007047 free(st_ses->hw_ses_cpe);
Quinn Male2e883752019-03-22 11:28:54 -07007048 st_ses->hw_ses_cpe = NULL;
7049 }
Quinn Male2e883752019-03-22 11:28:54 -07007050 /* deinit adsp session */
7051 if (st_ses->hw_ses_adsp) {
7052 st_hw_sess_lsm_deinit(st_ses->hw_ses_adsp);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007053 free(st_ses->hw_ses_adsp);
Quinn Male2e883752019-03-22 11:28:54 -07007054 st_ses->hw_ses_adsp = NULL;
7055 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007056 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07007057 pthread_mutex_destroy(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007058 free(stc_ses->hw_proxy_ses);
7059 stc_ses->hw_proxy_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07007060
7061 return 0;
7062}