blob: cff561e89be0abb8e8eef4972ba78088bb70e802 [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 *
Quinn Male2bfe13b2020-08-27 16:53:51 -07007 * Copyright (c) 2016-2021, 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;
Harshal Ahire89337992020-07-13 02:38:14 +0530144 char *module_version;
Quinn Male2e883752019-03-22 11:28:54 -0700145 } payload;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700146 st_session_t *stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -0700147};
148
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700149static int idle_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
150static int loaded_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
151static int active_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
152static int detected_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
153static int buffering_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
154static int ssr_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
155
156static inline int process_detection_event
157(
158 st_proxy_session_t *st_ses, uint64_t timestamp, int detect_status,
159 void *payload, size_t payload_size,
160 struct sound_trigger_recognition_event **event
161);
162
Quinn Male3d7d9d42019-05-20 13:35:01 -0700163ST_DBG_DECLARE(static int file_cnt = 0);
Quinn Male2e883752019-03-22 11:28:54 -0700164
165void hw_sess_cb(st_hw_sess_event_t *hw_event, void *cookie)
166{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700167 st_proxy_session_t *st_ses = (st_proxy_session_t *)cookie;
Quinn Male2e883752019-03-22 11:28:54 -0700168 int status = 0;
169 int lock_status = 0;
170
171 if (!hw_event || !cookie) {
172 ALOGE("%s: received NULL params", __func__);
173 return;
174 }
175
176 switch (hw_event->event_id) {
177 case ST_HW_SESS_EVENT_DETECTED:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700178 {
179 st_session_ev_t ev;
180 ev.ev_id = ST_SES_EV_DETECTED;
181 ev.payload.detected = hw_event->payload.detected;
Quinn Male2e883752019-03-22 11:28:54 -0700182
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700183 do {
184 lock_status = pthread_mutex_trylock(&st_ses->lock);
185 } while (lock_status && !st_ses->device_disabled &&
186 (st_ses->exec_mode != ST_EXEC_MODE_NONE) &&
187 (st_ses->current_state != ssr_state_fn));
Quinn Male2e883752019-03-22 11:28:54 -0700188
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700189 if (st_ses->device_disabled) {
190 ALOGV("%s:[%d] device switch in progress, ignore event",
191 __func__, st_ses->sm_handle);
192 } else if (st_ses->exec_mode == ST_EXEC_MODE_NONE) {
193 ALOGV("%s:[%d] transition in progress, ignore event",
194 __func__, st_ses->sm_handle);
195 } else if (st_ses->current_state == ssr_state_fn) {
196 ALOGV("%s:[%d] SSR handling in progress, ignore event",
197 __func__, st_ses->sm_handle);
198 } else if (!lock_status) {
Quinn Male2e883752019-03-22 11:28:54 -0700199 /*
200 * TODO: Add RECOGNITION_STATUS_GET_STATE_RESPONSE to
201 * the SoundTrigger API header.
202 */
203 if (st_ses->detection_requested)
204 ev.payload.detected.detect_status = 3;
205
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700206 DISPATCH_EVENT(st_ses, ev, status);
Quinn Male2e883752019-03-22 11:28:54 -0700207 }
208
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700209 if (!lock_status)
210 pthread_mutex_unlock(&st_ses->lock);
211 break;
212 }
213
Quinn Male48490df2020-03-25 10:25:42 -0700214 case ST_HW_SESS_EVENT_BUFFERING_STOPPED:
215 {
216 st_session_ev_t ev;
217 ev.ev_id = ST_SES_EV_DEFERRED_STOP;
218 ev.stc_ses = st_ses->det_stc_ses;
219
220 /*
221 * If detection is sent to client while in buffering state,
222 * and if internal buffering is stopped due to errors, stop
223 * session internally as client is expected to restart the
224 * detection if required.
225 * Note: It is possible that detection event is not sent to
226 * client if second stage is not yet detected during internal
227 * buffering stop, in which case restart is posted from second
228 * stage thread for further detections. Only if the second
229 * stage detection hasn't be started due to internal buffering
230 * stop too early, restart session should be explictily issued.
231 */
232
233 do {
234 lock_status = pthread_mutex_trylock(&st_ses->lock);
235 } while (lock_status && !st_ses->det_stc_ses->pending_stop &&
Quinn Male31afd392020-06-30 17:35:10 -0700236 (st_ses->current_state == buffering_state_fn) &&
237 !st_ses->stdev->ssr_offline_received);
Quinn Male48490df2020-03-25 10:25:42 -0700238
Shalini Manjunathafc45b0d2020-10-13 18:09:51 +0530239 if (st_ses->det_stc_ses->pending_stop) {
Quinn Male48490df2020-03-25 10:25:42 -0700240 ALOGV("%s:[%d] pending stop already queued, ignore event",
241 __func__, st_ses->sm_handle);
Shalini Manjunathafc45b0d2020-10-13 18:09:51 +0530242 } else if (!st_ses->det_stc_ses->detection_sent) {
243 ev.ev_id = ST_SES_EV_RESTART;
244 DISPATCH_EVENT(st_ses, ev, status);
245 ALOGV("%s:[%d] client callback hasn't been called, restart detection evt_id(%d)",
246 __func__, st_ses->sm_handle, ev.ev_id);
247 } else if (st_ses->current_state != buffering_state_fn) {
Quinn Male48490df2020-03-25 10:25:42 -0700248 ALOGV("%s:[%d] session already stopped buffering, ignore event",
249 __func__, st_ses->sm_handle);
Shalini Manjunathafc45b0d2020-10-13 18:09:51 +0530250 } else if (st_ses->stdev->ssr_offline_received) {
Quinn Male31afd392020-06-30 17:35:10 -0700251 ALOGV("%s:[%d] SSR handling in progress, ignore event",
252 __func__, st_ses->sm_handle);
Shalini Manjunathafc45b0d2020-10-13 18:09:51 +0530253 } else if (!lock_status) {
Quinn Male48490df2020-03-25 10:25:42 -0700254 DISPATCH_EVENT(st_ses, ev, status);
Shalini Manjunathafc45b0d2020-10-13 18:09:51 +0530255 }
Quinn Male48490df2020-03-25 10:25:42 -0700256
257 if (!lock_status)
258 pthread_mutex_unlock(&st_ses->lock);
259 break;
260 }
261
Quinn Male2e883752019-03-22 11:28:54 -0700262 default:
263 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
264 break;
265 };
Quinn Male2e883752019-03-22 11:28:54 -0700266}
267
Quinn Male58749452020-03-26 17:14:56 -0700268static inline struct st_proxy_ses_sm_info_wrapper *get_sm_info_for_model_id
269(
270 st_proxy_session_t *st_ses,
271 uint32_t model_id
272)
273{
274 struct listnode *node = NULL;
275 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
276
277 list_for_each(node, &st_ses->sm_info_list) {
278 p_info = node_to_item(node, struct st_proxy_ses_sm_info_wrapper,
279 sm_list_node);
280
281 if (p_info->sm_info.model_id == model_id)
282 return p_info;
283 }
284
285 return NULL;
286}
287
288static inline struct st_hw_ses_config *get_sthw_cfg_for_model_id
289(
290 st_hw_session_t *hw_ses,
291 uint32_t model_id
292)
293{
294 struct listnode *node = NULL;
295 struct st_hw_ses_config *sthw_cfg = NULL;
296
297 list_for_each(node, &hw_ses->sthw_cfg_list) {
298 sthw_cfg = node_to_item(node, struct st_hw_ses_config,
299 sthw_cfg_list_node);
300
301 if (sthw_cfg->model_id == model_id)
302 return sthw_cfg;
303 }
304
305 return NULL;
306}
307
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700308static inline void free_array_ptrs(char **arr, unsigned int arr_len)
309{
310 int i = 0;
311
312 if (!arr)
313 return;
314
315 for (i = 0; i < arr_len; i++) {
316 if (arr[i]) {
317 free(arr[i]);
318 arr[i] = NULL;
319 }
320 }
321 free(arr);
322 arr = NULL;
323}
324
325static inline void alloc_array_ptrs(char ***arr, unsigned int arr_len,
326 unsigned int elem_len)
327{
328 char **str_arr = NULL;
329 int i = 0;
330
331 str_arr = (char **) calloc(arr_len, sizeof(char *));
332
333 if (!str_arr) {
334 *arr = NULL;
335 return;
336 }
337
338 for (i = 0; i < arr_len; i++) {
339 str_arr[i] = (char *) calloc(elem_len, sizeof(char));
340 if (str_arr[i] == NULL) {
341 free_array_ptrs(str_arr, i);
342 *arr = NULL;
343 return;
344 }
345 }
346 *arr = str_arr;
347 ALOGV("%s: string array %p", __func__, *arr);
348 for (i = 0; i < arr_len; i++)
349 ALOGV("%s: string array[%d] %p", __func__, i, (*arr)[i]);
350}
351
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700352static int merge_sound_models(struct sound_trigger_device *stdev,
353 unsigned int num_models, listen_model_type *in_models[],
354 listen_model_type *out_model)
355{
356 listen_status_enum sm_ret = 0;
357 int status = 0;
358
359 ALOGV("%s: num_models to merge %d", __func__, num_models);
360
361 if (!stdev->smlib_handle) {
362 ALOGE("%s: NULL sound model lib handle", __func__);
363 return -ENOSYS;
364 }
365
366 sm_ret = stdev->smlib_getMergedModelSize(num_models, in_models,
367 &out_model->size);
368 if ((sm_ret != kSucess) || !out_model->size) {
369 ALOGE("%s: smlib_getMergedModelSize failed, err %d, size %d", __func__,
370 sm_ret, out_model->size);
371 return -EINVAL;
372 }
373 ALOGD("%s: merge sound model size %d", __func__, out_model->size);
374
375 out_model->data = calloc(1, out_model->size * sizeof(char));
376 if (!out_model->data) {
377 ALOGE("%s: Merged sound model allocation failed", __func__);
378 return -ENOMEM;
379 }
380
381 sm_ret = stdev->smlib_mergeModels(num_models, in_models, out_model);
382 if (sm_ret != kSucess) {
383 ALOGE("%s: smlib_mergeModels failed, err %d", __func__, sm_ret);
384 status = -EINVAL;
385 goto cleanup;
386 }
387 if (!out_model->data || !out_model->size) {
388 ALOGE("%s: MergeModels returned NULL data or size %d", __func__,
389 out_model->size);
390 status = -EINVAL;
391 goto cleanup;
392 }
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -0700393 if (stdev->enable_debug_dumps) {
394 ST_DBG_DECLARE(FILE *sm_fd = NULL; static int sm_cnt = 0);
395 ST_DBG_FILE_OPEN_WR(sm_fd, ST_DEBUG_DUMP_LOCATION,
Quinn Male2bfe13b2020-08-27 16:53:51 -0700396 "st_smlib_output_merged_sm", "bin", sm_cnt);
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -0700397 ST_DBG_FILE_WRITE(sm_fd, out_model->data, out_model->size);
398 ST_DBG_FILE_CLOSE(sm_fd);
Quinn Male2bfe13b2020-08-27 16:53:51 -0700399 ALOGD("%s: SM returned from SML merge stored in: st_smlib_output_merged_sm_%d.bin",
400 __func__, sm_cnt);
401 sm_cnt++;
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -0700402 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700403 ALOGV("%s: Exit", __func__);
404 return 0;
405
406cleanup:
407 if (out_model->data) {
408 free(out_model->data);
409 out_model->data = NULL;
410 out_model->size = 0;
411 }
412 return status;
413}
414
415static int delete_from_merged_sound_model(struct sound_trigger_device *stdev,
416 char **keyphrases, unsigned int num_keyphrases,
417 listen_model_type *in_model, listen_model_type *out_model)
418{
419 listen_model_type merge_model = {0};
420 listen_status_enum sm_ret = 0;
421 unsigned int out_model_sz = 0;
422 int status = 0, i = 0;
423
424 out_model->data = NULL;
425 out_model->size = 0;
426 merge_model.data = in_model->data;
427 merge_model.size = in_model->size;
428
429 for (i = 0; i < num_keyphrases; i++) {
430 sm_ret = stdev->smlib_getSizeAfterDeleting(&merge_model, keyphrases[i],
431 NULL, &out_model_sz);
432 if (sm_ret != kSucess) {
433 ALOGE("%s: smlib_getSizeAfterDeleting failed %d", __func__, sm_ret);
434 status = -EINVAL;
435 goto cleanup;
436 }
437 if (out_model_sz >= in_model->size) {
438 ALOGE("%s: unexpected, smlib_getSizeAfterDeleting returned size %d"
439 "not less than merged model size %d", __func__,
440 out_model_sz, in_model->size);
441 status = -EINVAL;
442 goto cleanup;
443 }
444 ALOGV("%s: Size after deleting kw[%d] = %d", __func__, i, out_model_sz);
445 if (!out_model->data) {
446 /* Valid if deleting multiple keyphrases one after other */
447 free (out_model->data);
448 out_model->size = 0;
449 }
450 out_model->data = calloc(1, out_model_sz * sizeof(char));
451 if (!out_model->data) {
452 ALOGE("%s: Merge sound model allocation failed, size %d ", __func__,
453 out_model_sz);
454 status = -ENOMEM;
455 goto cleanup;
456 }
457 out_model->size = out_model_sz;
458
459 sm_ret = stdev->smlib_deleteFromModel(&merge_model, keyphrases[i],
460 NULL, out_model);
461 if (sm_ret != kSucess) {
462 ALOGE("%s: smlib_getSizeAfterDeleting failed %d", __func__, sm_ret);
463 status = -EINVAL;
464 goto cleanup;
465 }
466 if (out_model->size != out_model_sz) {
467 ALOGE("%s: unexpected, out_model size %d != expected size %d",
468 __func__, out_model->size, out_model_sz);
469 status = -EINVAL;
470 goto cleanup;
471 }
472 /* Used if deleting multiple keyphrases one after other */
473 merge_model.data = out_model->data;
474 merge_model.size = out_model->size;
475 }
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -0700476 if (stdev->enable_debug_dumps && out_model->data && out_model->size) {
477 ST_DBG_DECLARE(FILE *sm_fd = NULL; static int sm_cnt = 0);
478 ST_DBG_FILE_OPEN_WR(sm_fd, ST_DEBUG_DUMP_LOCATION,
Quinn Male2bfe13b2020-08-27 16:53:51 -0700479 "st_smlib_output_deleted_sm", "bin", sm_cnt);
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -0700480 ST_DBG_FILE_WRITE(sm_fd, out_model->data, out_model->size);
481 ST_DBG_FILE_CLOSE(sm_fd);
Quinn Male2bfe13b2020-08-27 16:53:51 -0700482 ALOGD("%s: SM returned from SML delete stored in: st_smlib_output_deleted_sm_%d.bin",
483 __func__, sm_cnt);
484 sm_cnt++;
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -0700485 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700486 return 0;
487
488cleanup:
489 if (out_model->data) {
490 free(out_model->data);
491 out_model->data = NULL;
492 }
493 return status;
494}
495
496static void release_sound_model_info(struct sound_model_info *sm_info)
497{
498 ALOGV("%s", __func__);
499
500 if (sm_info->cf_levels) {
501 free(sm_info->cf_levels);
502 sm_info->cf_levels = NULL;
503 sm_info->det_cf_levels = NULL;
504 }
505 free_array_ptrs(sm_info->keyphrases, sm_info->num_keyphrases);
506 sm_info->keyphrases = NULL;
507
508 free_array_ptrs(sm_info->users, sm_info->num_users);
509 sm_info->users = NULL;
510
511 free_array_ptrs(sm_info->cf_levels_kw_users, sm_info->cf_levels_size);
512 sm_info->cf_levels_kw_users = NULL;
513}
514
515static inline void stdbg_print_sound_model_header(
516 listen_sound_model_header *smh)
517{
518 int i = 0, j = 0;
519
520 ALOGV("%s", __func__);
521 ALOGV("numKeywords = %d", smh->numKeywords);
522 ALOGV("numUsers = %d", smh->numUsers);
523 ALOGV("numActiveUserKeywordPairs = %d", smh->numActiveUserKeywordPairs);
524 ALOGV("isStripped = %d", smh->isStripped);
525 ALOGV("model_indicator = %d", smh->model_indicator);
526
527 for (i = 0; i < smh->numKeywords; i++) {
528 ALOGV("kw-%d langPerKw = %d", i, smh->langPerKw[i]);
529 ALOGV("kw-%d numUsersSetPerKw = %d", i, smh->numUsersSetPerKw[i]);
530 ALOGV("kw-%d isUserDefinedKeyword = %d", i,
531 smh->isUserDefinedKeyword[i]);
532 }
533 if (smh->userKeywordPairFlags) {
534 for (i = 0; i < smh->numUsers; i++) {
535 for (j = 0; j < smh->numKeywords; j++)
536 ALOGV("userKeywordPairFlags[%d][%d] = %d", i, j,
537 smh->userKeywordPairFlags[i][j]);
538 }
539 }
540}
541
542static int query_sound_model(struct sound_trigger_device *stdev,
543 struct sound_model_info *sm_info, unsigned char *sm_data,
544 unsigned int sm_size)
545{
546 listen_sound_model_header sm_header = {0};
547 listen_model_type model = {0};
548 listen_status_enum sm_ret = 0;
549 int status = 0, i = 0, j = 0, k = 0;
550 uint16_t tmp = 0;
551
552 ALOGV("%s: enter sm_size %d", __func__, sm_size);
553
554 if (!stdev->smlib_handle) {
555 ALOGE("%s: NULL sound model lib handle", __func__);
556 return -ENOSYS;
557 }
558
559 model.data = sm_data;
560 model.size = sm_size;
561
562 sm_ret = stdev->smlib_getSoundModelHeader(&model, &sm_header);
563 if (sm_ret != kSucess) {
564 ALOGE("%s: smlib_getSoundModelHeader failed, err %d ", __func__, sm_ret);
565 return -EINVAL;
566 }
567 if (sm_header.numKeywords == 0) {
568 ALOGE("%s: num keywords zero!!", __func__);
569 return -EINVAL;
570 }
571 if (sm_header.numActiveUserKeywordPairs < sm_header.numUsers) {
572 ALOGE("%s: smlib activeUserKwPairs(%d) < total users (%d)", __func__,
573 sm_header.numActiveUserKeywordPairs, sm_header.numUsers);
574 goto cleanup;
575 }
576 if (sm_header.numUsers && !sm_header.userKeywordPairFlags) {
577 ALOGE("%s: userKeywordPairFlags is NULL, numUsers (%d)", __func__,
578 sm_header.numUsers);
579 goto cleanup;
580 }
581 stdbg_print_sound_model_header(&sm_header);
582
583 /* MAX_STRING_LEN is part of listen sound model header file */
584 alloc_array_ptrs(&sm_info->keyphrases, sm_header.numKeywords,
585 MAX_STRING_LEN);
586 if (!sm_info->keyphrases) {
587 ALOGE("%s: keyphrases allocation failed", __func__);
588 status = -ENOMEM;
589 goto cleanup;
590 }
591 sm_info->num_keyphrases = sm_header.numKeywords;
592 sm_info->num_users = sm_header.numUsers;
593
594 tmp = sm_header.numKeywords;
Zhou Songdeddfcc2019-06-18 22:25:03 +0800595 ALOGV("%s: stdb: model.data %pK, model.size %d", __func__, model.data,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700596 model.size);
597 sm_ret = stdev->smlib_getKeywordPhrases(&model, &tmp, sm_info->keyphrases);
598 if (sm_ret) {
599 ALOGE("%s: smlib_getKeywordPhrases failed, err %d ", __func__, sm_ret);
600 goto cleanup;
601 }
602 if (tmp != sm_header.numKeywords) {
603 ALOGE("%s: smlib_getkeywordPhrases(%d) != sml header (%d)", __func__,
604 tmp, sm_header.numKeywords);
605 goto cleanup;
606 }
607 for (i = 0; i < sm_header.numKeywords; i++)
608 ALOGV("%s: keyphrases names = %s", __func__, sm_info->keyphrases[i]);
609
610 if (sm_header.numUsers) {
611 alloc_array_ptrs(&sm_info->users, sm_header.numUsers, MAX_STRING_LEN);
612 if (!sm_info->users) {
613 ALOGE("%s: users allocation failed", __func__);
614 status = -ENOMEM;
615 goto cleanup;
616 }
617
618 tmp = sm_header.numUsers;
619 sm_ret = stdev->smlib_getUserNames(&model, &tmp, sm_info->users);
620 if (sm_ret) {
621 ALOGE("%s: smlib_getUserNames failed, err %d ", __func__, sm_ret);
622 goto cleanup;
623 }
624 if (tmp != sm_header.numUsers) {
625 ALOGE("%s: smlib_getUserNames(%d) != sml header (%d)", __func__,
626 tmp, sm_header.numUsers);
627 status = -EINVAL;
628 goto cleanup;
629 }
630 for (i = 0; i < sm_header.numUsers; i++)
631 ALOGV("%s: users names = %s", __func__, sm_info->users[i]);
632 }
633
634 sm_info->cf_levels_size = sm_header.numKeywords +
635 sm_header.numActiveUserKeywordPairs;
636 alloc_array_ptrs(&sm_info->cf_levels_kw_users, sm_info->cf_levels_size,
637 MAX_KW_USERS_NAME_LEN);
638 if (!sm_info->cf_levels_kw_users) {
639 ALOGE("%s: cf_levels_kw_users allocation failed", __func__);
640 status = -ENOMEM;
641 goto cleanup;
642 }
643
644 /* Used later for mapping client to/from merged DSP confidence levels */
645 sm_info->cf_levels = calloc(1, 2 * sm_info->cf_levels_size);
646 if (!sm_info->cf_levels) {
647 ALOGE("%s: cf_levels allocation failed", __func__);
648 status = -ENOMEM;
649 goto cleanup;
650 }
651 /*
652 * Used for updating detection confidence level values from DSP merged
653 * detection conf levels
654 */
655 sm_info->det_cf_levels = sm_info->cf_levels + sm_info->cf_levels_size;
656
657 /*
658 * Used for conf level setting to DSP. Reset the conf value to max value,
659 * so that the keyword of a loaded and in-active model in a merged model
660 * doesn't detect.
661 */
662 memset(sm_info->cf_levels, MAX_CONF_LEVEL_VALUE, sm_info->cf_levels_size);
663
664 /*
665 * Derive the confidence level payload for keyword and user pairs.
666 * Store the user-keyword pair names in an array that will be used for
667 * mapping the DSP detection and confidence levels to the client.
668 */
669 char **kw_names = sm_info->cf_levels_kw_users;
670 char **ukw_names = &sm_info->cf_levels_kw_users[sm_header.numKeywords];
671 int ukw_idx = 0;
672
673 for (i = 0; i < sm_header.numKeywords; i++) {
674 strlcpy(kw_names[i], sm_info->keyphrases[i], MAX_KW_USERS_NAME_LEN);
675 if (!sm_header.numUsersSetPerKw)
676 continue;
677 for (j = 0, k = 0; j < sm_header.numUsers; j++) {
678 if (k >= sm_header.numUsersSetPerKw[i])
679 break;
680 if (sm_header.userKeywordPairFlags[j][i]) {
681 strlcpy(ukw_names[ukw_idx], sm_info->users[j],
682 MAX_KW_USERS_NAME_LEN);
683 strlcat(ukw_names[ukw_idx], sm_info->keyphrases[i],
684 MAX_KW_USERS_NAME_LEN);
685 ukw_idx++;
686 k++;
687 }
688 }
689 }
690 for (i = 0; i < sm_info->cf_levels_size; i++)
691 ALOGV("%s: cf_levels_kw_users = %s", __func__,
692 sm_info->cf_levels_kw_users[i]);
693
694 sm_ret = stdev->smlib_releaseSoundModelHeader(&sm_header);
695 if (sm_ret != kSucess) {
696 ALOGE("%s: smlib_releaseSoundModelHeader failed, err %d ", __func__,
697 sm_ret);
698 status = -EINVAL;
699 goto cleanup_1;
700 }
701 ALOGV("%s: exit", __func__);
702 return 0;
703
704cleanup:
705 sm_ret = stdev->smlib_releaseSoundModelHeader(&sm_header);
706 if (sm_ret != kSucess)
707 ALOGE("%s: smlib_releaseSoundModelHeader failed, err %d ", __func__,
708 sm_ret);
709
710cleanup_1:
711 release_sound_model_info(sm_info);
712
713 return status;
714}
715
716static int add_sound_model(st_session_t *stc_ses, unsigned char *sm_data,
717 unsigned int sm_size)
718{
719 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
720 struct listnode *node = NULL;
721 st_session_t *c_ses = NULL;
722 listen_model_type **in_models = NULL;
723 listen_model_type out_model = {0};
Quinn Male58749452020-03-26 17:14:56 -0700724 struct sound_model_info sm_info = {0};
725 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700726 int status = 0, num_models = 0;
727
728 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
729 if (stc_ses->sm_info.sm_data) {
730 ALOGD("%s:[c%d] Already added", __func__, stc_ses->sm_handle);
731 return 0;
732 }
Quinn Male58749452020-03-26 17:14:56 -0700733 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
734 stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700735 stc_ses->sm_info.sm_data = sm_data;
736 stc_ses->sm_info.sm_size = sm_size;
Quinn Male58749452020-03-26 17:14:56 -0700737 stc_ses->sm_info.sm_type = stc_ses->sm_type;
738 stc_ses->sm_info.model_id =
739 (stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) ?
740 stc_ses->sm_handle : 0;
741
742 p_info = calloc(1, sizeof(struct st_proxy_ses_sm_info_wrapper));
743 if (!p_info) {
744 ALOGE("%s: failed to alloc struct st_proxy_ses_sm_info_wrapper",
745 __func__);
746 return -ENOMEM;
747 }
748
749 memcpy((uint8_t *)&p_info->sm_info, (uint8_t *)&stc_ses->sm_info,
750 sizeof(struct sound_model_info));
751
752 if (stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
753 st_ses->recognition_mode |= stc_ses->recognition_mode;
754 p_info->sm_info.cf_levels = calloc(1, 2 * MAX_MULTI_SM_CONF_LEVELS);
755 if (!p_info->sm_info.cf_levels) {
756 ALOGE("%s: failed to alloc cf_levels",
757 __func__);
758 free(p_info);
759 return -ENOMEM;
760 }
761 memset(p_info->sm_info.cf_levels, MAX_CONF_LEVEL_VALUE,
762 MAX_MULTI_SM_CONF_LEVELS);
763 p_info->sm_info.det_cf_levels = p_info->sm_info.cf_levels +
764 MAX_MULTI_SM_CONF_LEVELS;
765 memset(p_info->sm_info.det_cf_levels, 0,
766 MAX_MULTI_SM_CONF_LEVELS);
767 stc_ses->sm_info.cf_levels = p_info->sm_info.cf_levels;
768 stc_ses->sm_info.det_cf_levels = p_info->sm_info.det_cf_levels;
769 }
770 list_add_tail(&st_ses->sm_info_list, &p_info->sm_list_node);
771 if (stc_ses->f_stage_version == ST_MODULE_TYPE_GMM)
772 ALOGD("%s:[c%d] no merge", __func__, stc_ses->sm_handle);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700773 return 0;
774 }
775 /* get sound model header information for client model */
776 status = query_sound_model(st_ses->stdev, &stc_ses->sm_info,
777 sm_data, sm_size);
778 if (status)
779 return status;
780
781 stc_ses->sm_info.sm_data = sm_data;
782 stc_ses->sm_info.sm_size = sm_size;
Zhou Songdeddfcc2019-06-18 22:25:03 +0800783 ALOGV("%s: stc_ses %pK - sm_data %pK, sm_size %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700784 stc_ses, stc_ses->sm_info.sm_data,
785 stc_ses->sm_info.sm_size);
786
787 /* Check for remaining client sound models to merge */
788 list_for_each(node, &st_ses->clients_list) {
789 c_ses = node_to_item(node, st_session_t, hw_list_node);
790 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data)
791 num_models++;
792 }
793 if (!num_models) {
Quinn Male58749452020-03-26 17:14:56 -0700794 p_info = calloc(1, sizeof(struct st_proxy_ses_sm_info_wrapper));
795 if (!p_info) {
796 ALOGE("%s: failed to alloc struct st_proxy_ses_sm_info_wrapper",
797 __func__);
798 return -ENOMEM;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700799 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700800 st_ses->recognition_mode = stc_ses->recognition_mode;
801 stc_ses->sm_info.sm_type = stc_ses->sm_type;
Quinn Male58749452020-03-26 17:14:56 -0700802 stc_ses->sm_info.model_id = 0;
803 memcpy((uint8_t *)&p_info->sm_info, (uint8_t *)&stc_ses->sm_info,
804 sizeof(struct sound_model_info));
805 st_ses->sm_merged = false;
806 list_add_tail(&st_ses->sm_info_list, &p_info->sm_list_node);
807 ALOGD("%s: Copy from single client c%d model, size %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700808 stc_ses->sm_handle, stc_ses->sm_info.sm_size);
809 return 0;
810 }
811 ALOGV("%s: num existing models %d", __func__, num_models);
812 /*
813 * Merge this client model with already existing merged model due to other
814 * clients models.
815 */
Quinn Male58749452020-03-26 17:14:56 -0700816 p_info = get_sm_info_for_model_id(st_ses, 0);
817 if (!p_info) {
818 ALOGE("%s: Unexpected, no matching model_id in sm_info list,"
819 "num current models %d", __func__, num_models);
820 status = -EINVAL;
821 goto cleanup;
822 }
823
824 if (!p_info->sm_info.sm_data) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700825 if (num_models == 1) {
826 /*
Quinn Male58749452020-03-26 17:14:56 -0700827 * Its not a merged model yet, but proxy ses sm_data is valid
828 * and must be pointing to client sm_data
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700829 */
Quinn Male58749452020-03-26 17:14:56 -0700830 ALOGE("%s: Unexpected, sm_data NULL, num current"
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700831 "models %d", __func__, num_models);
832 status = -EINVAL;
833 goto cleanup;
Quinn Male58749452020-03-26 17:14:56 -0700834 } else if (!st_ses->sm_merged) {
835 ALOGE("%s: Unexpected, no pre-existing merged model,"
836 "num current models %d", __func__, num_models);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700837 status = -EINVAL;
838 goto cleanup;
839 }
840 }
841
842 /* Merge this client model with remaining clients models */
843 num_models = 2;/* re-use */
844 alloc_array_ptrs((char***)&in_models, num_models, sizeof(listen_model_type));
845 if (!in_models) {
846 ALOGE("%s: in_models allocation failed", __func__);
847 status = -ENOMEM;
848 goto cleanup;
849 }
850 /* Add existing model */
Quinn Male58749452020-03-26 17:14:56 -0700851 in_models[0]->data = p_info->sm_info.sm_data;
852 in_models[0]->size = p_info->sm_info.sm_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700853 /* Add this client model */
854 in_models[1]->data = sm_data;
855 in_models[1]->size = sm_size;
856
857 status = merge_sound_models(st_ses->stdev, 2, in_models, &out_model);
858 if (status)
859 goto cleanup;
860
861 sm_info.sm_data = out_model.data;
862 sm_info.sm_size = out_model.size;
Quinn Male58749452020-03-26 17:14:56 -0700863 sm_info.model_id = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700864
865 status = query_sound_model(st_ses->stdev, &sm_info,
866 out_model.data, out_model.size);
867 if (status)
868 goto cleanup;
869
Quinn Male58749452020-03-26 17:14:56 -0700870 if (out_model.size < p_info->sm_info.sm_size) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700871 ALOGE("%s: Unexpected, merged model sz %d < current sz %d",
Quinn Male58749452020-03-26 17:14:56 -0700872 __func__, out_model.size, p_info->sm_info.sm_size);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700873 release_sound_model_info(&sm_info);
874 status = -EINVAL;
875 goto cleanup;
876 }
877 free_array_ptrs((char **)in_models, num_models);
878 in_models = NULL;
879
880 /* Update the new merged model */
Quinn Male58749452020-03-26 17:14:56 -0700881 if (st_ses->sm_merged && p_info->sm_info.sm_data) {
882 release_sound_model_info(&p_info->sm_info);
883 free(p_info->sm_info.sm_data);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700884 }
885 ALOGD("%s: Updated sound model: current size %d, new size %d", __func__,
Quinn Male58749452020-03-26 17:14:56 -0700886 p_info->sm_info.sm_size, out_model.size);
887 memcpy((uint8_t *)&p_info->sm_info, (uint8_t *)&sm_info,
888 sizeof(struct sound_model_info));
889 st_ses->sm_merged = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700890
891 /*
892 * If any of the clients has user identificaiton enabled, underlying
893 * hw session has to operate with user identification enabled.
894 */
895 if (stc_ses->recognition_mode & RECOGNITION_MODE_USER_IDENTIFICATION)
896 st_ses->recognition_mode |= stc_ses->recognition_mode;
897
898 return 0;
899
900cleanup:
901 release_sound_model_info(&stc_ses->sm_info);
902 stc_ses->sm_info.sm_data = NULL;
903
904 if (out_model.data)
905 free(out_model.data);
906
907 if (in_models)
908 free_array_ptrs((char **)in_models, num_models);
909
910 return status;
911}
912
913static int delete_sound_model(st_session_t *stc_ses)
914{
915 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
916 struct listnode *node = NULL;
917 st_session_t *c_ses = NULL, *c_ses_rem = NULL;
918 listen_model_type in_model = {0};
919 listen_model_type out_model = {0};
920 struct sound_model_info sm_info = {0};
Quinn Male58749452020-03-26 17:14:56 -0700921 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
922 struct st_hw_ses_config *sthw_cfg = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700923 int status = 0, num_models = 0;
924 unsigned int rec_mode = RECOGNITION_MODE_VOICE_TRIGGER;
925
926 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
927 if (!stc_ses->sm_info.sm_data) {
928 ALOGD("%s:[c%d] Already deleted", __func__, stc_ses->sm_handle);
929 return 0;
930 }
Quinn Male58749452020-03-26 17:14:56 -0700931
932 p_info = get_sm_info_for_model_id(st_ses, stc_ses->sm_info.model_id);
933 if (!p_info) {
934 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
935 return -EINVAL;
936 }
937
938 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
939 stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
940 list_remove(&p_info->sm_list_node);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700941 /*
Quinn Male58749452020-03-26 17:14:56 -0700942 * As it directly points to client model, just set sm_data
943 * as NULL without freeing
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700944 */
Quinn Male58749452020-03-26 17:14:56 -0700945 if (stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
946 /* Update overall recogniton mode from remaining clients */
947 list_for_each(node, &st_ses->clients_list) {
948 c_ses = node_to_item(node, st_session_t, hw_list_node);
949 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data) {
950 if (c_ses->recognition_mode &
951 RECOGNITION_MODE_USER_IDENTIFICATION)
952 rec_mode |= RECOGNITION_MODE_USER_IDENTIFICATION;
953 }
954 }
955 st_ses->recognition_mode = rec_mode;
956
957 if (p_info->sm_info.cf_levels) {
958 free(p_info->sm_info.cf_levels);
959 p_info->sm_info.cf_levels = NULL;
960 }
961 }
962 p_info->sm_info.sm_data = NULL;
963 free(p_info);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700964 stc_ses->sm_info.sm_data = NULL;
Quinn Male58749452020-03-26 17:14:56 -0700965 if (stc_ses->f_stage_version == ST_MODULE_TYPE_GMM)
966 ALOGD("%s:[c%d] no merge", __func__, stc_ses->sm_handle);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700967 return 0;
968 }
969
Zhou Songdeddfcc2019-06-18 22:25:03 +0800970 ALOGV("%s: stc_ses %pK - sm_data %pK, sm_size %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700971 stc_ses, stc_ses->sm_info.sm_data,
972 stc_ses->sm_info.sm_size);
973
974 /* Check for remaining clients sound models to merge */
975 list_for_each(node, &st_ses->clients_list) {
976 c_ses = node_to_item(node, st_session_t, hw_list_node);
977 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data) {
978 c_ses_rem = c_ses;
979 num_models++;
980 }
981 }
Quinn Male58749452020-03-26 17:14:56 -0700982
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700983 if (num_models == 0) {
984 ALOGD("%s: No remaining models", __func__);
985 /* Delete current client model */
Quinn Male58749452020-03-26 17:14:56 -0700986 release_sound_model_info(&p_info->sm_info);
987 list_remove(&p_info->sm_list_node);
988 p_info->sm_info.sm_data = NULL;
989 free(p_info);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700990 stc_ses->sm_info.sm_data = NULL;
991 return 0;
992 }
993
994 if (num_models == 1) {
995 ALOGD("%s: reuse only remaining client model, size %d", __func__,
996 c_ses_rem->sm_info.sm_size);
997 /* If only one remaining client model exists, re-use it */
Quinn Male58749452020-03-26 17:14:56 -0700998 if (st_ses->sm_merged) {
999 release_sound_model_info(&p_info->sm_info);
1000 if (p_info->sm_info.sm_data)
1001 free(p_info->sm_info.sm_data);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001002 }
Quinn Male58749452020-03-26 17:14:56 -07001003 memcpy((uint8_t *)&p_info->sm_info, (uint8_t *)&c_ses_rem->sm_info,
1004 sizeof(struct sound_model_info));
1005 st_ses->sm_merged = false;
1006
1007 sthw_cfg = get_sthw_cfg_for_model_id(st_ses->hw_ses_current, 0);
1008 if (!sthw_cfg) {
1009 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
1010 return -EINVAL;
1011 }
1012
1013 sthw_cfg->conf_levels = p_info->sm_info.cf_levels;
1014 sthw_cfg->num_conf_levels =
1015 p_info->sm_info.cf_levels_size;
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -07001016 st_ses->recognition_mode = c_ses_rem->recognition_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001017 /* Delete current client model */
1018 release_sound_model_info(&stc_ses->sm_info);
1019 stc_ses->sm_info.sm_data = NULL;
1020 return 0;
1021 }
1022 /* Update overall recogniton mode from remaining clients */
1023 list_for_each(node, &st_ses->clients_list) {
1024 c_ses = node_to_item(node, st_session_t, hw_list_node);
1025 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data) {
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -07001026 if (c_ses->recognition_mode & RECOGNITION_MODE_USER_IDENTIFICATION)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001027 rec_mode |= RECOGNITION_MODE_USER_IDENTIFICATION;
1028 }
1029 }
1030
1031 /*
1032 * Delete this client model with already existing merged model due to other
1033 * clients models.
1034 */
Quinn Male58749452020-03-26 17:14:56 -07001035 if (!st_ses->sm_merged || !p_info->sm_info.sm_data) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001036 ALOGE("%s: Unexpected, no pre-existing merged model to delete from,"
1037 "num current models %d", __func__, num_models);
1038 goto cleanup;
1039 }
1040
1041 /* Existing merged model from which the current client model to be deleted */
Quinn Male58749452020-03-26 17:14:56 -07001042 in_model.data = p_info->sm_info.sm_data;
1043 in_model.size = p_info->sm_info.sm_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001044
1045 status = delete_from_merged_sound_model(st_ses->stdev,
1046 stc_ses->sm_info.keyphrases, stc_ses->sm_info.num_keyphrases,
1047 &in_model, &out_model);
1048
1049 if (status)
1050 goto cleanup;
1051
1052 sm_info.sm_data = out_model.data;
1053 sm_info.sm_size = out_model.size;
Quinn Male58749452020-03-26 17:14:56 -07001054 sm_info.model_id = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001055
1056 /* Update existing merged model info with new merged model */
1057 status = query_sound_model(st_ses->stdev, &sm_info, out_model.data,
1058 out_model.size);
1059 if (status)
1060 goto cleanup;
1061
Quinn Male58749452020-03-26 17:14:56 -07001062 if (out_model.size > p_info->sm_info.sm_size) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001063 ALOGE("%s: Unexpected, merged model sz %d > current sz %d",
Quinn Male58749452020-03-26 17:14:56 -07001064 __func__, out_model.size, p_info->sm_info.sm_size);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001065 release_sound_model_info(&sm_info);
1066 status = -EINVAL;
1067 goto cleanup;
1068 }
1069
Quinn Male58749452020-03-26 17:14:56 -07001070 if (st_ses->sm_merged && p_info->sm_info.sm_data) {
1071 release_sound_model_info(&p_info->sm_info);
1072 free(p_info->sm_info.sm_data);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001073 }
1074
1075 ALOGD("%s: Updated sound model: current size %d, new size %d", __func__,
Quinn Male58749452020-03-26 17:14:56 -07001076 p_info->sm_info.sm_size, out_model.size);
1077 memcpy((uint8_t *)&p_info->sm_info, (uint8_t *)&sm_info,
1078 sizeof(struct sound_model_info));
1079 st_ses->sm_merged = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001080 /*
1081 * If any of the remaining clients has user identificaiton enabled,
1082 * underlying hw session has to operate with user identificaiton enabled.
1083 */
1084 st_ses->recognition_mode = rec_mode;
1085
1086 /* Release current client model */
1087 release_sound_model_info(&stc_ses->sm_info);
1088 stc_ses->sm_info.sm_data = NULL;
1089
1090 return 0;
1091
1092cleanup:
1093 release_sound_model_info(&stc_ses->sm_info);
1094 stc_ses->sm_info.sm_data = NULL;
1095
1096 if (out_model.data)
1097 free(out_model.data);
1098
1099 return status;
1100}
1101
1102static int update_sound_model(st_session_t *stc_ses, bool add)
1103{
1104 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
1105 struct sound_trigger_phrase_sound_model *phrase_sm = stc_ses->phrase_sm;
1106 struct sound_trigger_sound_model *common_sm =
1107 (struct sound_trigger_sound_model*)stc_ses->phrase_sm;
1108 unsigned char *sm_data = NULL;
1109 unsigned int sm_size = 0;
1110 int status = 0;
1111
1112 ALOGV("%s: Enter", __func__);
1113
1114 if (stc_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
1115 sm_data = (unsigned char*)phrase_sm + phrase_sm->common.data_offset;
1116 sm_size = phrase_sm->common.data_size;
1117 } else {
1118 sm_data = (unsigned char*)common_sm + common_sm->data_offset;
1119 sm_size = common_sm->data_size;
1120 }
1121
1122 pthread_mutex_lock(&st_ses->lock);
1123 if (add)
1124 status = add_sound_model(stc_ses, sm_data, sm_size);
1125 else
1126 status = delete_sound_model(stc_ses);
1127 pthread_mutex_unlock(&st_ses->lock);
1128
1129 ALOGV("%s: Exit", __func__);
1130 return status;
1131}
1132
1133static int update_merge_conf_levels_payload(st_proxy_session_t *st_ses,
1134 struct sound_model_info *src_sm_info, unsigned char *src,
1135 unsigned int src_size, bool set)
1136{
1137 int i = 0, j = 0;
Quinn Male58749452020-03-26 17:14:56 -07001138 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001139
1140 if (!st_ses || !src) {
1141 ALOGE("%s: NULL pointer", __func__);
1142 return -EINVAL;
1143 }
1144
Quinn Male58749452020-03-26 17:14:56 -07001145 if (!st_ses->sm_merged)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001146 return 0;
1147
Quinn Male58749452020-03-26 17:14:56 -07001148 p_info = get_sm_info_for_model_id(st_ses, 0);
1149 if (!p_info) {
1150 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
1151 return -EINVAL;
1152 }
1153
1154 if (src_size > p_info->sm_info.cf_levels_size) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001155 ALOGE("%s:[%d] Unexpected, client conf levels %d > "
1156 "merged conf levels %d", __func__, st_ses->sm_handle,
Quinn Male58749452020-03-26 17:14:56 -07001157 src_size, p_info->sm_info.cf_levels_size);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001158 return -EINVAL;
1159 }
1160
1161 for (i = 0; i < src_size; i++)
1162 ALOGV("%s: src cf_levels[%d]=%d", __func__, i, src[i]);
1163
1164 /* Populate DSP merged sound model conf levels */
1165 for (i = 0; i < src_size; i++) {
Quinn Male58749452020-03-26 17:14:56 -07001166 for (j = 0; j < p_info->sm_info.cf_levels_size; j++) {
1167 if (!strcmp(p_info->sm_info.cf_levels_kw_users[j],
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001168 src_sm_info->cf_levels_kw_users[i])) {
1169 if (set) {
Quinn Male58749452020-03-26 17:14:56 -07001170 p_info->sm_info.cf_levels[j] = src[i];
1171 ALOGV("%s: set: cf_levels[%d]=%d", __func__,
1172 j, p_info->sm_info.cf_levels[j]);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001173 } else {
Quinn Male58749452020-03-26 17:14:56 -07001174 p_info->sm_info.cf_levels[j] = MAX_CONF_LEVEL_VALUE;
1175 ALOGV("%s: reset: cf_levels[%d]=%d", __func__,
1176 j, p_info->sm_info.cf_levels[j]);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001177 }
1178 }
1179 }
1180 }
1181 return 0;
1182}
1183
1184static int update_merge_conf_levels_payload_with_active_clients(
1185 st_proxy_session_t *st_ses)
1186{
1187 int status = 0;
1188 struct listnode *node = NULL;
1189 st_session_t *c_ses = NULL;
1190
1191 list_for_each(node, &st_ses->clients_list) {
1192 c_ses = node_to_item(node, st_session_t, hw_list_node);
1193 if (c_ses->state == ST_STATE_ACTIVE) {
1194 ALOGV("%s: update merge conf levels with other active"
1195 "client %d ", __func__, c_ses->sm_handle);
1196 status = update_merge_conf_levels_payload(st_ses,
1197 &c_ses->sm_info, c_ses->sm_info.cf_levels,
1198 c_ses->sm_info.cf_levels_size, true);
1199 if (status)
1200 return status;
1201 }
1202 }
1203 return status;
1204}
1205
1206static void check_and_extract_det_conf_levels_payload(
1207 st_proxy_session_t *st_ses,
1208 unsigned char *src, unsigned int src_size,
1209 unsigned char **dst, unsigned int *dst_size)
1210{
1211 st_session_t *stc_ses = st_ses->det_stc_ses;
Quinn Male58749452020-03-26 17:14:56 -07001212 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001213 int i = 0, j = 0;
1214
1215 *dst = src;
1216 *dst_size = src_size;
1217
1218 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
Quinn Male58749452020-03-26 17:14:56 -07001219 !st_ses->sm_merged ||
1220 stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001221 ALOGV("%s:[%d] not merged", __func__, st_ses->sm_handle);
1222 return;
1223 }
1224
Quinn Male58749452020-03-26 17:14:56 -07001225 p_info = get_sm_info_for_model_id(st_ses, 0);
1226 if (!p_info) {
1227 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
1228 return;
1229 }
1230
1231 if (src_size < p_info->sm_info.cf_levels_size) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001232 ALOGE("%s:[%d] Unexpected, detection conf payload size %d < %d",
1233 __func__, st_ses->sm_handle, src_size,
Quinn Male58749452020-03-26 17:14:56 -07001234 p_info->sm_info.cf_levels_size);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001235 return;
1236 }
1237
1238 /* Reset any cached previous detection values */
1239 memset(stc_ses->sm_info.det_cf_levels, 0, stc_ses->sm_info.cf_levels_size);
1240
1241 /* Extract the client conf level values from DSP payload */
Quinn Male58749452020-03-26 17:14:56 -07001242 for(i = 0; i < p_info->sm_info.cf_levels_size; i++) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001243 if (!src[i])
1244 continue;
1245 for(j = 0; j < stc_ses->sm_info.cf_levels_size; j++) {
1246 if (!strcmp(stc_ses->sm_info.cf_levels_kw_users[j],
Quinn Male58749452020-03-26 17:14:56 -07001247 p_info->sm_info.cf_levels_kw_users[i])) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001248 stc_ses->sm_info.det_cf_levels[j] = src[i];
1249 }
1250 }
1251 }
1252 for (i = 0; i < stc_ses->sm_info.cf_levels_size; i++)
1253 ALOGD("%s: c%d det_cf_levels[%d]=%d", __func__, stc_ses->sm_handle, i,
1254 stc_ses->sm_info.det_cf_levels[i]);
1255
1256 *dst = stc_ses->sm_info.det_cf_levels;
1257 *dst_size = stc_ses->sm_info.cf_levels_size;
1258}
1259
1260static inline bool check_for_multi_clients(st_proxy_session_t *st_ses)
1261{
1262 struct listnode *node = NULL;
1263 int cnt = 0;
1264
1265 list_for_each(node, &st_ses->clients_list) {
1266 if (++cnt > 1)
1267 return true;
1268 }
1269 return false;
1270}
1271
1272static inline bool is_other_client_attached(st_proxy_session_t *st_ses,
1273 st_session_t *stc_ses)
1274{
1275 struct listnode *node = NULL;
1276 st_session_t *c_ses = NULL;
1277
1278 list_for_each(node, &st_ses->clients_list) {
1279 c_ses = node_to_item(node, st_session_t, hw_list_node);
1280 if (c_ses != stc_ses)
1281 return true;
1282 }
1283 return false;
1284}
1285
1286static inline void reset_clients_pending_load(st_proxy_session_t *st_ses)
1287{
1288 struct listnode *node = NULL;
1289 st_session_t *c_ses = NULL;
1290
1291 list_for_each(node, &st_ses->clients_list) {
1292 c_ses = node_to_item(node, st_session_t, hw_list_node);
1293 c_ses->pending_load = false;
1294 }
1295}
1296
1297static inline int is_any_client_not_pending_load(st_proxy_session_t *st_ses)
1298{
1299 struct listnode *node = NULL;
1300 st_session_t *c_ses = NULL;
1301
1302 list_for_each(node, &st_ses->clients_list) {
1303 c_ses = node_to_item(node, st_session_t, hw_list_node);
1304 if (!c_ses->pending_load)
1305 return true;
1306 }
1307 return false;
1308}
1309
1310static inline int is_any_client_not_pending_set_device(
1311 st_proxy_session_t *st_ses)
1312{
1313 struct listnode *node = NULL;
1314 st_session_t *c_ses = NULL;
1315
1316 list_for_each(node, &st_ses->clients_list) {
1317 c_ses = node_to_item(node, st_session_t, hw_list_node);
1318 if (!c_ses->pending_set_device)
1319 return true;
1320 }
1321 return false;
1322}
1323
1324static inline void reset_clients_pending_set_device(st_proxy_session_t *st_ses)
1325{
1326 struct listnode *node = NULL;
1327 st_session_t *c_ses = NULL;
1328
1329 list_for_each(node, &st_ses->clients_list) {
1330 c_ses = node_to_item(node, st_session_t, hw_list_node);
1331 c_ses->pending_set_device = false;
1332 }
1333}
1334
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001335static inline bool is_any_client_paused(st_proxy_session_t *st_ses)
1336{
1337 struct listnode *node = NULL;
1338 st_session_t *c_ses = NULL;
1339
1340 list_for_each(node, &st_ses->clients_list) {
1341 c_ses = node_to_item(node, st_session_t, hw_list_node);
1342 if (c_ses->paused)
1343 return true;
1344 }
1345 return false;
1346}
1347
1348static inline bool is_any_client_in_state(st_proxy_session_t *st_ses,
1349 enum client_states_t state)
1350{
1351 struct listnode *node = NULL;
1352 st_session_t *c_ses = NULL;
1353
1354 list_for_each(node, &st_ses->clients_list) {
1355 c_ses = node_to_item(node, st_session_t, hw_list_node);
1356 if (c_ses->state == state)
1357 return true;
1358 }
1359 return false;
1360}
1361
1362static void update_hw_config_on_restart(st_proxy_session_t *st_ses,
1363 st_session_t *stc_ses)
1364{
1365 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male58749452020-03-26 17:14:56 -07001366 struct st_hw_ses_config *sthw_cfg = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001367 struct listnode *node = NULL;
1368 st_session_t *c_ses = NULL;
1369 int hb_sz = 0, pr_sz = 0;
1370 bool enable_lab = false;
1371
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001372 /*
1373 * Adjust history buffer and preroll durations to highest of
1374 * all clients, including current restarting client.
1375 * If any of the clients requested capture or enabled the
1376 * second stage, the underlying hw session buffering needs to be
1377 * enabled.
1378 */
1379 list_for_each(node, &st_ses->clients_list) {
1380 c_ses = node_to_item(node, st_session_t, hw_list_node);
1381 if ((c_ses == stc_ses) || (c_ses->state == ST_STATE_ACTIVE)) {
1382 if (hb_sz < c_ses->hist_buf_duration)
1383 hb_sz = c_ses->hist_buf_duration;
1384 if (pr_sz < c_ses->preroll_duration)
1385 pr_sz = c_ses->preroll_duration;
1386 if (!enable_lab)
1387 enable_lab = (c_ses->rc_config &&
1388 c_ses->rc_config->capture_requested) ||
1389 !list_empty(&c_ses->second_stage_list);
1390 }
1391 }
1392
Quinn Male58749452020-03-26 17:14:56 -07001393 sthw_cfg = get_sthw_cfg_for_model_id(hw_ses, stc_ses->sm_info.model_id);
1394 if (!sthw_cfg) {
1395 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
1396 return;
1397 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001398
Quinn Male58749452020-03-26 17:14:56 -07001399 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
1400 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
1401 !st_ses->sm_merged)
1402 return;
1403
1404 sthw_cfg->client_req_hist_buf = hb_sz;
1405 hw_ses->max_hist_buf = hb_sz;
1406 sthw_cfg->client_req_preroll = pr_sz;
1407 hw_ses->max_preroll = pr_sz;
1408 st_ses->lab_enabled = enable_lab;
1409
1410 update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
1411 stc_ses->sm_info.cf_levels,
1412 stc_ses->sm_info.cf_levels_size,
1413 true);
1414 } else {
1415 sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
1416 hw_ses->max_hist_buf = hb_sz;
1417 sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
1418 hw_ses->max_preroll = pr_sz;
1419 st_ses->lab_enabled = enable_lab;
1420
1421 /*
1422 * During stop, the conf levels get set to the max value
1423 * to prevent detections while its client state is loaded
1424 * and another sound model's client state is active. So
1425 * during restart, the conf levels need to be reset from
1426 * the cached stc_values to enable detections again.
1427 */
1428 memset(sthw_cfg->conf_levels, MAX_CONF_LEVEL_VALUE,
1429 MAX_MULTI_SM_CONF_LEVELS);
1430 memcpy(sthw_cfg->conf_levels, stc_ses->sm_info.cf_levels,
1431 stc_ses->sm_info.cf_levels_size);
1432 sthw_cfg->num_conf_levels = stc_ses->sm_info.cf_levels_size;
1433 }
1434
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001435 hw_ses->sthw_cfg_updated = true;
1436
1437 ALOGV("%s:[%d] lab_enabled %d, hb_sz %d, pr_sz %d", __func__,
1438 st_ses->sm_handle, st_ses->lab_enabled,
1439 sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
1440}
1441
1442static bool update_hw_config_on_stop(st_proxy_session_t *st_ses,
1443 st_session_t *stc_ses)
1444{
1445 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male58749452020-03-26 17:14:56 -07001446 struct st_hw_ses_config *sthw_cfg = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001447 struct listnode *node = NULL;
1448 st_session_t *c_ses = NULL;
1449 int hb_sz = 0, pr_sz = 0;
1450 bool active = false, enable_lab = false;
1451
Quinn Male58749452020-03-26 17:14:56 -07001452 sthw_cfg = get_sthw_cfg_for_model_id(hw_ses, stc_ses->sm_info.model_id);
1453 if (!sthw_cfg) {
1454 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
1455 return false;
1456 }
1457
1458 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels &&
1459 stc_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
1460
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001461 if (sthw_cfg->conf_levels) {
1462 ALOGV("%s: free hw conf_levels", __func__);
1463 free(sthw_cfg->conf_levels);
1464 sthw_cfg->conf_levels = NULL;
1465 }
1466 return false;
1467 }
1468 /*
1469 * Adjust history buffer and preroll durations to highest of
1470 * remaining clients.
1471 * If any of the remaining clients requested capture or enabled the
1472 * second stage, the underlying hw session buffering needs to be
1473 * enabled.
1474 */
1475 list_for_each(node, &st_ses->clients_list) {
1476 c_ses = node_to_item(node, st_session_t, hw_list_node);
1477 if ((c_ses != stc_ses) && (c_ses->state == ST_STATE_ACTIVE)) {
1478 active = true;
1479 if (hb_sz < c_ses->hist_buf_duration)
1480 hb_sz = c_ses->hist_buf_duration;
1481 if (pr_sz < c_ses->preroll_duration)
1482 pr_sz = c_ses->preroll_duration;
1483 if (!enable_lab)
1484 enable_lab = c_ses->rc_config->capture_requested ||
1485 !list_empty(&c_ses->second_stage_list);
1486 }
1487 }
Quinn Male58749452020-03-26 17:14:56 -07001488
1489 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
1490 if (!active) {
1491 sthw_cfg->client_req_hist_buf = 0;
1492 hw_ses->max_hist_buf = 0;
1493 sthw_cfg->client_req_preroll = 0;
1494 hw_ses->max_preroll = 0;
1495 st_ses->lab_enabled = false;
1496 hw_ses->custom_data = NULL;
1497 hw_ses->custom_data_size = 0;
1498 hw_ses->sthw_cfg_updated = true;
1499 ALOGV("%s:[%d] no active client hw cfg is reset", __func__,
1500 st_ses->sm_handle);
1501 return false;
1502 }
1503
1504 sthw_cfg->client_req_hist_buf = hb_sz;
1505 hw_ses->max_hist_buf = hb_sz;
1506 sthw_cfg->client_req_preroll = pr_sz;
1507 hw_ses->max_preroll = pr_sz;
1508 st_ses->lab_enabled = enable_lab;
1509
1510 update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
1511 stc_ses->sm_info.cf_levels,
1512 stc_ses->sm_info.cf_levels_size,
1513 false);
1514 } else {
1515 if (!active) {
1516 hw_ses->max_hist_buf = 0;
1517 hw_ses->max_preroll = 0;
1518 st_ses->lab_enabled = false;
1519 hw_ses->custom_data = NULL;
1520 hw_ses->custom_data_size = 0;
1521 hw_ses->sthw_cfg_updated = true;
1522 return false;
1523 }
1524
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001525 sthw_cfg->client_req_hist_buf = 0;
Quinn Male58749452020-03-26 17:14:56 -07001526 hw_ses->max_hist_buf = hb_sz;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001527 sthw_cfg->client_req_preroll = 0;
Quinn Male58749452020-03-26 17:14:56 -07001528 hw_ses->max_preroll = pr_sz;
1529 st_ses->lab_enabled = enable_lab;
1530
1531 memset(sthw_cfg->conf_levels, MAX_CONF_LEVEL_VALUE,
1532 MAX_MULTI_SM_CONF_LEVELS);
1533 sthw_cfg->num_conf_levels = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001534 }
1535
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001536 hw_ses->sthw_cfg_updated = true;
1537
1538 ALOGV("%s:[%d] lab_enabled %d, hb_sz %d, pr_sz %d", __func__,
1539 st_ses->sm_handle, st_ses->lab_enabled,
1540 sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
1541
1542 return active;
1543}
1544
1545static void get_conf_levels_from_dsp_payload(st_proxy_session_t *st_ses,
1546 unsigned char *payload, unsigned int payload_size,
1547 unsigned char **conf_levels, unsigned int *conf_levels_size)
1548{
1549 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
1550 uint32_t key_id = 0, key_payload_size = 0;
1551 unsigned int i = 0;
1552
1553 if (hw_ses->is_generic_event) {
1554 while (i < payload_size) {
1555 key_id = *(uint32_t *)payload;
1556 key_payload_size = *((uint32_t *)payload + 1);
1557
1558 if (key_id == KEY_ID_CONFIDENCE_LEVELS) {
1559 *conf_levels = payload + (4 * sizeof(uint32_t));
1560 *conf_levels_size = *((uint32_t *)payload + 3);;
1561 ALOGV("%s: generic_event: DSP num conf levels %d", __func__,
1562 *conf_levels_size);
1563 break;
1564 }
1565 i += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Quinn Male58749452020-03-26 17:14:56 -07001566 payload += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001567 }
1568 } else {
Quinn Male9a345522020-03-12 17:49:25 -07001569 if (st_ses->exec_mode == ST_EXEC_MODE_CPE) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001570 *conf_levels = payload + 2;
1571 *conf_levels_size = payload_size - 2;
1572 } else {
1573 *conf_levels = payload;
1574 *conf_levels_size = payload_size;
1575 }
1576 }
1577}
1578
1579st_session_t* get_detected_client(st_proxy_session_t *st_ses,
1580 unsigned char *payload, unsigned int payload_size)
1581{
1582 struct listnode *node = NULL;
1583 st_session_t *c_ses = NULL;
1584 unsigned char *conf_levels = NULL;
Quinn Male58749452020-03-26 17:14:56 -07001585 unsigned int conf_levels_size = 0, key_id = 0, key_payload_size = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001586 int i = 0, j = 0;
Quinn Male58749452020-03-26 17:14:56 -07001587 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
1588 multi_model_result_info_t *result_info = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001589
Quinn Male58749452020-03-26 17:14:56 -07001590 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
1591 p_info = get_sm_info_for_model_id(st_ses, 0);
1592 if (!p_info) {
1593 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001594 return NULL;
1595 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001596
Quinn Male58749452020-03-26 17:14:56 -07001597 if (list_empty(&st_ses->clients_list)) {
1598 ALOGE("%s:[%d] no clients attached!!", __func__,
1599 st_ses->sm_handle);
1600 return NULL;
1601 }
1602 /*
1603 * If only single client exist, this detection is not for merged
1604 * sound model, hence return this as only available client
1605 */
1606 if (!check_for_multi_clients(st_ses)) {
1607 ALOGV("%s:[%d] single client detection", __func__,
1608 st_ses->sm_handle);
1609 node = list_head(&st_ses->clients_list);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001610 c_ses = node_to_item(node, st_session_t, hw_list_node);
Quinn Male58749452020-03-26 17:14:56 -07001611 if (c_ses->state == ST_STATE_ACTIVE) {
1612 ALOGD("%s: detected c%d", __func__, c_ses->sm_handle);
1613 return c_ses;
1614 } else {
1615 ALOGE("%s: detected c%d is not active", __func__,
1616 c_ses->sm_handle);
1617 return NULL;
1618 }
1619 }
1620
1621 get_conf_levels_from_dsp_payload(st_ses, payload, payload_size,
1622 &conf_levels, &conf_levels_size);
1623 if (!conf_levels) {
1624 ALOGE("%s:[%d] no conf levels payload found!!", __func__,
1625 st_ses->sm_handle);
1626 return NULL;
1627 }
1628 if (conf_levels_size < p_info->sm_info.num_keyphrases) {
1629 ALOGE("%s:[%d] detection conf levels size %d < num of keywords %d",
1630 __func__, st_ses->sm_handle, conf_levels_size,
1631 p_info->sm_info.num_keyphrases);
1632 return NULL;
1633 }
1634
1635 /*
1636 * The DSP payload contains the keyword conf levels from the beginning.
1637 * Only one keyword conf level is expected to be non-zero from keyword
1638 * detection. Find non-zero conf level up to number of keyphrases and
1639 * if one is found, match it to the corresponding keyphrase from list
1640 * of clients to obtain the detected client.
1641 */
1642 for (i = 0; i < p_info->sm_info.num_keyphrases; i++) {
1643 if (!conf_levels[i])
1644 continue;
1645 list_for_each(node, &st_ses->clients_list) {
1646 c_ses = node_to_item(node, st_session_t, hw_list_node);
1647 for (j = 0; j < c_ses->sm_info.num_keyphrases; j++) {
1648 if (!strcmp(p_info->sm_info.keyphrases[i],
1649 c_ses->sm_info.keyphrases[j])) {
1650 if (c_ses->state == ST_STATE_ACTIVE) {
1651 ALOGV("%s: detected c%d", __func__,
1652 c_ses->sm_handle);
1653 return c_ses;
1654 } else {
1655 ALOGE("%s: detected c%d is not active", __func__,
1656 c_ses->sm_handle);
1657 return NULL;
1658 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001659 }
1660 }
1661 }
1662 }
Quinn Male58749452020-03-26 17:14:56 -07001663 } else {
1664 while (i < payload_size) {
1665 key_id = *(uint32_t *)payload;
1666 key_payload_size = *((uint32_t *)payload + 1);
1667
1668 if (key_id == KEY_ID_MULTI_MODEL_RESULT_INFO) {
1669 result_info = (multi_model_result_info_t *)(payload +
1670 GENERIC_DET_EVENT_HEADER_SIZE);
1671 list_for_each(node, &st_ses->clients_list) {
1672 c_ses = node_to_item(node, st_session_t, hw_list_node);
1673 if (c_ses->sm_info.model_id ==
1674 result_info->detected_model_id) {
1675 if (c_ses->state == ST_STATE_ACTIVE) {
Quinn Malea15c5ff2020-06-18 18:05:20 -07001676 ALOGD("%s: detected c%d, 1st stage conf level = %d",
1677 __func__, c_ses->sm_handle,
1678 result_info->best_confidence_level);
Quinn Male58749452020-03-26 17:14:56 -07001679 return c_ses;
1680 } else {
1681 ALOGE("%s: detected c%d is not active", __func__,
1682 c_ses->sm_handle);
1683 return NULL;
1684 }
1685 }
1686 }
1687 break;
1688 } else {
1689 ALOGE("%s: Unexpected key id for PDK5 0x%x", __func__,
1690 key_id);
1691 break;
1692 }
1693 i += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
1694 payload += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
1695 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001696 }
1697 return c_ses;
1698}
1699
1700static int fill_conf_levels_payload_from_rc_config
1701(
1702 const struct sound_trigger_phrase_sound_model *phrase_sm,
1703 const struct sound_trigger_recognition_config *rc_config,
1704 unsigned char *conf_levels,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001705 unsigned int total_num_users
1706)
1707{
1708 int status = 0;
1709 unsigned int user_level, user_id;
1710 unsigned int i = 0, j = 0;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001711 unsigned int num_conf_levels = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001712 unsigned char *user_id_tracker;
1713
Zhou Songdeddfcc2019-06-18 22:25:03 +08001714 if (!phrase_sm || !rc_config || !conf_levels) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001715 ALOGE("%s: ERROR. Invalid inputs",__func__);
1716 return -EINVAL;
1717 }
1718
Zhou Songdeddfcc2019-06-18 22:25:03 +08001719 if ((UINT32_MAX - total_num_users) > rc_config->num_phrases)
1720 num_conf_levels = total_num_users + rc_config->num_phrases;
1721
1722 if (!num_conf_levels) {
1723 ALOGE("%s: ERROR. Invalid num_conf_levels input", __func__);
1724 return -EINVAL;
1725 }
1726
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001727 /* Example: Say the recognition structure has 3 keywords with users
1728 * |kid|
1729 * [0] k1 |uid|
1730 * [3] u1 - 1st trainer
1731 * [4] u2 - 4th trainer
1732 * [6] u3 - 3rd trainer
1733 * [1] k2
1734 * [5] u2 - 2nd trainer
1735 * [7] u3 - 5th trainer
1736 * [2] k3
1737 * [8] u4 - 6th trainer
1738 *
1739 * Output confidence level array will be
1740 * [k1, k2, k3, u1k1, u2k1, u2k2, u3k1, u3k2, u4k3]
1741 */
1742
1743 user_id_tracker = calloc(1, num_conf_levels);
1744 if (!user_id_tracker) {
1745 ALOGE("%s: failed to allocate user_id_tracker", __func__);
1746 return -ENOMEM;
1747 }
1748
1749 for (i = 0; i < rc_config->num_phrases; i++) {
1750 ALOGV("%s: [%d] kw level %d", __func__, i,
1751 rc_config->phrases[i].confidence_level);
1752 for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
1753 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
1754 rc_config->phrases[i].levels[j].user_id,
1755 rc_config->phrases[i].levels[j].level);
1756 }
1757 }
1758
1759 for (i = 0; i < rc_config->num_phrases; i++) {
Zhou Songdeddfcc2019-06-18 22:25:03 +08001760 if (i < num_conf_levels) {
1761 conf_levels[i] = rc_config->phrases[i].confidence_level;
1762 } else {
1763 ALOGE("%s: ERROR. Invalid number of phrases", __func__);
1764 status = -EINVAL;
1765 goto exit;
1766 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001767 for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
1768 user_level = rc_config->phrases[i].levels[j].level;
1769 user_id = rc_config->phrases[i].levels[j].user_id;
1770 if ((user_id < rc_config->num_phrases) ||
1771 (user_id >= num_conf_levels)) {
1772 ALOGE("%s: ERROR. Invalid params user id %d>%d",
1773 __func__, user_id, total_num_users);
1774 status = -EINVAL;
1775 goto exit;
1776 } else {
1777 if (user_id_tracker[user_id] == 1) {
1778 ALOGE("%s: ERROR. Duplicate user id %d",
1779 __func__, user_id);
1780 status = -EINVAL;
1781 goto exit;
1782 }
1783 conf_levels[user_id] = (user_level < 100) ? user_level: 100;
1784 user_id_tracker[user_id] = 1;
1785 ALOGV("%s: user_conf_levels[%d] = %d", __func__,
1786 user_id, conf_levels[user_id]);
1787 }
1788 }
1789 }
1790
1791exit:
1792 free(user_id_tracker);
1793 return status;
1794}
1795
1796int generate_conf_levels_payload_from_rc_config
1797(
1798 const struct sound_trigger_phrase_sound_model *phrase_sm,
1799 const struct sound_trigger_recognition_config *rc_config,
1800 unsigned char **out_payload,
1801 unsigned int *out_payload_size
1802)
1803{
1804 int status = 0;
1805 unsigned int total_num_users = 0, num_conf_levels = 0;
1806 unsigned int i = 0, j = 0;
1807 unsigned char *conf_levels = NULL;
1808
1809 if (!phrase_sm || !rc_config || !out_payload || !out_payload_size) {
1810 ALOGE("%s: ERROR. Invalid inputs",__func__);
1811 status = -EINVAL;
1812 goto exit;
1813 }
1814 *out_payload = NULL;
1815 *out_payload_size = 0;
1816
1817 if((rc_config->num_phrases == 0) ||
1818 (rc_config->num_phrases > phrase_sm->num_phrases)) {
1819 ALOGE("%s: ERROR. Invalid phrases %d!=%d",__func__,
1820 rc_config->num_phrases, phrase_sm->num_phrases);
1821 status = -EINVAL;
1822 goto exit;
1823 }
1824 for (i = 0; i < rc_config->num_phrases; i++) {
1825 for (j = 0; j < rc_config->phrases[i].num_levels; j++)
1826 total_num_users++;
1827 }
1828
1829 num_conf_levels = total_num_users + rc_config->num_phrases;
1830 conf_levels = calloc(1, num_conf_levels);
1831 if (!conf_levels) {
1832 ALOGE("%s: ERROR. conf levels alloc failed",__func__);
1833 status = -ENOMEM;
1834 goto exit;
1835 }
1836
1837 status = fill_conf_levels_payload_from_rc_config(phrase_sm, rc_config,
Zhou Songdeddfcc2019-06-18 22:25:03 +08001838 conf_levels, total_num_users);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001839 if (status) {
1840 ALOGE("%s: fill config payload failed, error %d", __func__, status);
1841 goto exit;
1842 }
1843
1844 *out_payload = conf_levels;
1845 *out_payload_size = num_conf_levels;
1846
1847 return status;
1848
1849exit:
1850 if (conf_levels)
1851 free(conf_levels);
1852 return status;
1853}
1854
1855int generate_conf_levels_payload_from_rc_config_v2
1856(
1857 const struct sound_trigger_phrase_sound_model *phrase_sm,
1858 const struct sound_trigger_recognition_config *rc_config,
1859 unsigned char **out_payload,
1860 unsigned int *out_payload_size
1861)
1862{
1863 int status = 0;
1864 unsigned int total_num_users = 0, num_conf_levels = 0;
1865 unsigned char *conf_levels = NULL;
1866 unsigned int i = 0, j = 0;
1867
1868 ALOGV("%s: Enter...", __func__);
1869
1870 if (!phrase_sm || !rc_config || !out_payload || !out_payload_size) {
1871 ALOGE("%s: ERROR. Invalid inputs",__func__);
1872 status = -EINVAL;
1873 goto exit;
1874 }
1875 *out_payload = NULL;
1876 *out_payload_size = 0;
1877
1878 if((rc_config->num_phrases == 0) ||
1879 (rc_config->num_phrases > phrase_sm->num_phrases)) {
1880 ALOGE("%s: ERROR. Invalid phrases %d!=%d",__func__,
1881 rc_config->num_phrases, phrase_sm->num_phrases);
1882 status = -EINVAL;
1883 goto exit;
1884 }
1885 for (i = 0; i < rc_config->num_phrases; i++) {
1886 for (j = 0; j < rc_config->phrases[i].num_levels; j++)
1887 total_num_users++;
1888 }
1889
1890 num_conf_levels = total_num_users + rc_config->num_phrases;
1891 /*
1892 * allocate dsp payload w/additional 2 bytes for minor_version and
1893 * num_active_models and additional num_conf_levels for KW enable
1894 * fields
1895 */
1896 conf_levels = calloc(1, 2 + 2 * num_conf_levels);
1897 if (!conf_levels) {
1898 ALOGE("%s: ERROR. conf levels alloc failed",__func__);
1899 status = -ENOMEM;
1900 goto exit;
1901 }
1902
1903 conf_levels[0] = 1; /* minor version */
1904 conf_levels[1] = num_conf_levels; /* num_active_models */
1905 status = fill_conf_levels_payload_from_rc_config(phrase_sm, rc_config,
Zhou Songdeddfcc2019-06-18 22:25:03 +08001906 conf_levels + 2, total_num_users);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001907 if (status) {
1908 ALOGE("%s: fill config payload failed, error %d", __func__, status);
1909 goto exit;
1910 }
1911
1912 /*
1913 * set KW enable fields to 1 for now
1914 * TODO: set appropriately based on what client is passing in rc_config
1915 */
1916 memset(&conf_levels[num_conf_levels + 2], 0x1, num_conf_levels);
1917 ALOGV("%s: here", __func__);
1918 *out_payload = conf_levels;
1919 /* add size of minor version and num_active_models */
1920 *out_payload_size = 2 + 2 * num_conf_levels;
1921 return status;
1922
1923exit:
1924 if (conf_levels)
1925 free(conf_levels);
1926 return status;
1927}
1928
1929static int fill_sound_trigger_recognition_config_payload
1930(
1931 const void *sm_levels_generic,
1932 unsigned char *conf_levels,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001933 unsigned int total_num_users,
1934 uint32_t version
1935)
1936{
1937 int status = 0;
1938 unsigned int user_level = 0, user_id = 0;
1939 unsigned int i = 0, j = 0;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001940 unsigned int num_conf_levels = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001941 unsigned char *user_id_tracker = NULL;
1942 struct st_sound_model_conf_levels *sm_levels = NULL;
1943 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
1944
1945 /* Example: Say the recognition structure has 3 keywords with users
1946 * |kid|
1947 * [0] k1 |uid|
1948 * [3] u1 - 1st trainer
1949 * [4] u2 - 4th trainer
1950 * [6] u3 - 3rd trainer
1951 * [1] k2
1952 * [5] u2 - 2nd trainer
1953 * [7] u3 - 5th trainer
1954 * [2] k3
1955 * [8] u4 - 6th trainer
1956 *
1957 * Output confidence level array will be
1958 * [k1, k2, k3, u1k1, u2k1, u2k2, u3k1, u3k2, u4k3]
1959 */
1960
1961 if (version != CONF_LEVELS_INTF_VERSION_0002) {
1962 sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001963 if (!sm_levels || !conf_levels) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001964 ALOGE("%s: ERROR. Invalid inputs", __func__);
1965 return -EINVAL;
1966 }
Zhou Songdeddfcc2019-06-18 22:25:03 +08001967
1968 if ((UINT32_MAX - total_num_users) > sm_levels->num_kw_levels)
1969 num_conf_levels = total_num_users + sm_levels->num_kw_levels;
1970
1971 if (!num_conf_levels) {
1972 ALOGE("%s: ERROR. Invalid num_conf_levels input", __func__);
1973 return -EINVAL;
1974 }
1975
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001976 user_id_tracker = calloc(1, num_conf_levels);
1977 if (!user_id_tracker) {
1978 ALOGE("%s: failed to allocate user_id_tracker", __func__);
1979 return -ENOMEM;
1980 }
1981
1982 for (i = 0; i < sm_levels->num_kw_levels; i++) {
1983 ALOGV("%s: [%d] kw level %d", __func__, i,
1984 sm_levels->kw_levels[i].kw_level);
1985 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++) {
1986 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
1987 sm_levels->kw_levels[i].user_levels[j].user_id,
1988 sm_levels->kw_levels[i].user_levels[j].level);
1989 }
1990 }
1991
1992 for (i = 0; i < sm_levels->num_kw_levels; i++) {
Zhou Songdeddfcc2019-06-18 22:25:03 +08001993 if (i < num_conf_levels) {
1994 conf_levels[i] = sm_levels->kw_levels[i].kw_level;
1995 } else {
1996 ALOGE("%s: ERROR. Invalid numver of kw levels", __func__);
1997 status = -EINVAL;
1998 goto exit;
1999 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002000 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++) {
2001 user_level = sm_levels->kw_levels[i].user_levels[j].level;
2002 user_id = sm_levels->kw_levels[i].user_levels[j].user_id;
2003 if ((user_id < sm_levels->num_kw_levels) ||
2004 (user_id >= num_conf_levels)) {
2005 ALOGE("%s: ERROR. Invalid params user id %d>%d",
2006 __func__, user_id, total_num_users);
2007 status = -EINVAL;
2008 goto exit;
2009 } else {
2010 if (user_id_tracker[user_id] == 1) {
2011 ALOGE("%s: ERROR. Duplicate user id %d",
2012 __func__, user_id);
2013 status = -EINVAL;
2014 goto exit;
2015 }
2016 conf_levels[user_id] = (user_level < 100) ?
2017 user_level: 100;
2018 user_id_tracker[user_id] = 1;
2019 ALOGV("%s: user_conf_levels[%d] = %d", __func__,
2020 user_id, conf_levels[user_id]);
2021 }
2022 }
2023 }
2024 } else {
2025 sm_levels_v2 =
2026 (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
Zhou Songdeddfcc2019-06-18 22:25:03 +08002027 if (!sm_levels_v2 || !conf_levels) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002028 ALOGE("%s: ERROR. Invalid inputs", __func__);
2029 return -EINVAL;
2030 }
Zhou Songdeddfcc2019-06-18 22:25:03 +08002031
2032 if ((UINT32_MAX - total_num_users) > sm_levels_v2->num_kw_levels)
2033 num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
2034
2035 if (!num_conf_levels) {
2036 ALOGE("%s: ERROR. Invalid num_conf_levels input", __func__);
2037 return -EINVAL;
2038 }
2039
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002040 user_id_tracker = calloc(1, num_conf_levels);
2041 if (!user_id_tracker) {
2042 ALOGE("%s: failed to allocate user_id_tracker", __func__);
2043 return -ENOMEM;
2044 }
2045
2046 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
2047 ALOGV("%s: [%d] kw level %d", __func__, i,
2048 sm_levels_v2->kw_levels[i].kw_level);
2049 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++) {
2050 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
2051 sm_levels_v2->kw_levels[i].user_levels[j].user_id,
2052 sm_levels_v2->kw_levels[i].user_levels[j].level);
2053 }
2054 }
2055
2056 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
Zhou Songdeddfcc2019-06-18 22:25:03 +08002057 if (i < num_conf_levels) {
2058 conf_levels[i] = sm_levels_v2->kw_levels[i].kw_level;
2059 } else {
2060 ALOGE("%s: ERROR. Invalid numver of kw levels", __func__);
2061 status = -EINVAL;
2062 goto exit;
2063 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002064 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++) {
2065 user_level = sm_levels_v2->kw_levels[i].user_levels[j].level;
2066 user_id = sm_levels_v2->kw_levels[i].user_levels[j].user_id;
2067 if ((user_id < sm_levels_v2->num_kw_levels) ||
2068 (user_id >= num_conf_levels)) {
2069 ALOGE("%s: ERROR. Invalid params user id %d>%d",
2070 __func__, user_id, total_num_users);
2071 status = -EINVAL;
2072 goto exit;
2073 } else {
2074 if (user_id_tracker[user_id] == 1) {
2075 ALOGE("%s: ERROR. Duplicate user id %d",
2076 __func__, user_id);
2077 status = -EINVAL;
2078 goto exit;
2079 }
2080 conf_levels[user_id] = (user_level < 100) ?
2081 user_level: 100;
2082 user_id_tracker[user_id] = 1;
2083 ALOGV("%s: user_conf_levels[%d] = %d", __func__,
2084 user_id, conf_levels[user_id]);
2085 }
2086 }
2087 }
2088 }
2089
2090exit:
2091 free(user_id_tracker);
2092 return status;
2093}
2094
2095static int generate_sound_trigger_recognition_config_payload
2096(
2097 const void *sm_levels_generic,
2098 unsigned char **out_payload,
2099 unsigned int *out_payload_size,
2100 uint32_t version
2101)
2102{
2103 int status = 0;
2104 unsigned int total_num_users = 0, num_conf_levels = 0;
2105 unsigned char *conf_levels = NULL;
2106 unsigned int i = 0, j = 0;
2107 struct st_sound_model_conf_levels *sm_levels = NULL;
2108 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
2109
2110 ALOGV("%s: Enter...", __func__);
2111
2112 if (version != CONF_LEVELS_INTF_VERSION_0002) {
2113 sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
2114 if (!sm_levels || !out_payload || !out_payload_size) {
2115 ALOGE("%s: ERROR. Invalid inputs", __func__);
2116 status = -EINVAL;
2117 goto exit;
2118 }
2119 *out_payload = NULL;
2120 *out_payload_size = 0;
2121
2122 if (sm_levels->num_kw_levels == 0) {
2123 ALOGE("%s: ERROR. No confidence levels present", __func__);
2124 status = -EINVAL;
2125 goto exit;
2126 }
2127 for (i = 0; i < sm_levels->num_kw_levels; i++) {
2128 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++)
2129 total_num_users++;
2130 }
2131
2132 num_conf_levels = total_num_users + sm_levels->num_kw_levels;
2133 conf_levels = calloc(1, num_conf_levels);
2134 if (!conf_levels) {
2135 ALOGE("%s: ERROR. conf levels alloc failed", __func__);
2136 status = -ENOMEM;
2137 goto exit;
2138 }
2139 } else {
2140 sm_levels_v2 =
2141 (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
2142 if (!sm_levels_v2 || !out_payload || !out_payload_size) {
2143 ALOGE("%s: ERROR. Invalid inputs", __func__);
2144 status = -EINVAL;
2145 goto exit;
2146 }
2147 *out_payload = NULL;
2148 *out_payload_size = 0;
2149
2150 if (sm_levels_v2->num_kw_levels == 0) {
2151 ALOGE("%s: ERROR. No confidence levels present", __func__);
2152 status = -EINVAL;
2153 goto exit;
2154 }
2155 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
2156 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++)
2157 total_num_users++;
2158 }
2159
2160 num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
2161 conf_levels = calloc(1, num_conf_levels);
2162 if (!conf_levels) {
2163 ALOGE("%s: ERROR. conf levels alloc failed", __func__);
2164 status = -ENOMEM;
2165 goto exit;
2166 }
2167 }
2168
2169 status = fill_sound_trigger_recognition_config_payload(sm_levels_generic,
Zhou Songdeddfcc2019-06-18 22:25:03 +08002170 conf_levels, total_num_users, version);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002171 if (status) {
2172 ALOGE("%s: fill config payload failed, error %d", __func__, status);
2173 goto exit;
2174 }
2175
2176 *out_payload = conf_levels;
2177 *out_payload_size = num_conf_levels;
2178
2179 return status;
2180
2181exit:
2182 if (conf_levels)
2183 free(conf_levels);
2184
2185 return status;
2186}
2187
2188static int generate_sound_trigger_recognition_config_payload_v2
2189(
2190 const void *sm_levels_generic,
2191 unsigned char **out_payload,
2192 unsigned int *out_payload_size,
2193 uint32_t version
2194)
2195{
2196 int status = 0;
2197 unsigned int total_num_users = 0, num_conf_levels = 0;
2198 unsigned char *conf_levels = NULL;
2199 unsigned int i = 0, j = 0;
2200 struct st_sound_model_conf_levels *sm_levels = NULL;
2201 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
2202
2203 ALOGV("%s: Enter...", __func__);
2204
2205 if (version != CONF_LEVELS_INTF_VERSION_0002) {
2206 sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
2207 if (!sm_levels || !out_payload || !out_payload_size) {
2208 ALOGE("%s: ERROR. Invalid inputs", __func__);
2209 status = -EINVAL;
2210 goto exit;
2211 }
2212 *out_payload = NULL;
2213 *out_payload_size = 0;
2214
2215 if (sm_levels->num_kw_levels == 0) {
2216 ALOGE("%s: ERROR. No confidence levels present", __func__);
2217 status = -EINVAL;
2218 goto exit;
2219 }
2220 for (i = 0; i < sm_levels->num_kw_levels; i++) {
2221 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++)
2222 total_num_users++;
2223 }
2224
2225 num_conf_levels = total_num_users + sm_levels->num_kw_levels;
2226 } else {
2227 sm_levels_v2 =
2228 (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
2229 if (!sm_levels_v2 || !out_payload || !out_payload_size) {
2230 ALOGE("%s: ERROR. Invalid inputs", __func__);
2231 status = -EINVAL;
2232 goto exit;
2233 }
2234 *out_payload = NULL;
2235 *out_payload_size = 0;
2236
2237 if (sm_levels_v2->num_kw_levels == 0) {
2238 ALOGE("%s: ERROR. No confidence levels present", __func__);
2239 status = -EINVAL;
2240 goto exit;
2241 }
2242 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
2243 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++)
2244 total_num_users++;
2245 }
2246 num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
2247 }
2248
2249 /*
2250 * allocate dsp payload w/additional 2 bytes for minor_version and
2251 * num_active_models and additional num_conf_levels for KW enable
2252 * fields
2253 */
2254 conf_levels = calloc(1, 2 + 2 * num_conf_levels);
2255 if (!conf_levels) {
2256 ALOGE("%s: ERROR. conf levels alloc failed", __func__);
2257 status = -ENOMEM;
2258 goto exit;
2259 }
2260
2261 conf_levels[0] = 1; /* minor version */
2262 conf_levels[1] = num_conf_levels; /* num_active_models */
2263 status = fill_sound_trigger_recognition_config_payload(sm_levels_generic,
Zhou Songdeddfcc2019-06-18 22:25:03 +08002264 conf_levels + 2, total_num_users, version);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002265 if (status) {
2266 ALOGE("%s: fill config payload failed, error %d", __func__, status);
2267 goto exit;
2268 }
2269
2270 /* set KW enable fields to 1 for now
2271 * TODO set appropriately based on what client is passing in rc_config
2272 */
2273 memset(&conf_levels[num_conf_levels + 2], 0x1, num_conf_levels);
2274 ALOGV("%s: here", __func__);
2275 *out_payload = conf_levels;
2276 /* add size of minor version and num_active_models */
2277 *out_payload_size = 2 + 2 * num_conf_levels;
2278
2279 return status;
2280
2281exit:
2282 if (conf_levels)
2283 free(conf_levels);
2284
2285 return status;
2286}
2287
2288static int parse_rc_config_key_conf_levels
2289(
2290 st_session_t *stc_ses,
2291 st_hw_session_t *st_hw_ses,
2292 void *opaque_conf_levels,
2293 unsigned char **out_conf_levels,
2294 unsigned int *out_num_conf_levels
2295)
2296{
2297 struct st_confidence_levels_info *conf_levels = NULL;
2298 struct st_confidence_levels_info_v2 *conf_levels_v2 = NULL;
2299 struct st_sound_model_conf_levels *sm_levels = NULL;
2300 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
2301 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
2302 struct listnode *node = NULL;
2303 st_lsm_ss_config_t *ss_cfg = NULL;
2304 st_arm_second_stage_t *st_sec_stage = NULL;
2305 int status = 0;
2306 uint32_t i = 0;
2307 bool gmm_conf_found = false;
2308 uint8_t confidence_level = 0;
2309 int32_t confidence_level_v2 = 0;
2310 bool arm_second_stage = !list_empty(&stc_ses->second_stage_list);
2311 bool adsp_second_stage = (st_hw_ses == st_ses->hw_ses_adsp &&
2312 !list_empty(&st_hw_ses->lsm_ss_cfg_list));
2313
2314 if (arm_second_stage || adsp_second_stage) {
2315 if (stc_ses->rc_config->num_phrases > 1) {
2316 ALOGE("%s: Multi keyword is unsupported with 2nd stage detection",
2317 __func__);
2318 return -EINVAL;
2319 }
2320
2321 if (stc_ses->rc_config->phrases[0].num_levels > 1) {
2322 ALOGE("%s: Multi user is unsupported with 2nd stage detection",
2323 __func__);
2324 return -EINVAL;
2325 }
2326 }
2327
2328 if (stc_ses->st_conf_levels) {
2329 free(stc_ses->st_conf_levels);
2330 stc_ses->st_conf_levels = NULL;
2331 }
2332
2333 if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002) {
2334 conf_levels = (struct st_confidence_levels_info *)
2335 ((char *)opaque_conf_levels + sizeof(struct st_param_header));
2336
2337 stc_ses->st_conf_levels =
2338 calloc(1, sizeof(struct st_confidence_levels_info));
2339 if (!stc_ses->st_conf_levels) {
2340 ALOGE("%s: failed to alloc st_conf_levels", __func__);
2341 return -ENOMEM;
2342 }
2343 /* Cache to use during detection event processing */
2344 memcpy(stc_ses->st_conf_levels, (char *)conf_levels,
2345 sizeof(struct st_confidence_levels_info));
2346
2347 for (i = 0; i < conf_levels->num_sound_models; i++) {
2348 sm_levels = &conf_levels->conf_levels[i];
2349 if (sm_levels->sm_id == ST_SM_ID_SVA_GMM) {
Quinn Male9a345522020-03-12 17:49:25 -07002350 if (st_hw_ses == st_ses->hw_ses_cpe)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002351 status =
2352 generate_sound_trigger_recognition_config_payload_v2(
2353 (void *)sm_levels, out_conf_levels, out_num_conf_levels,
2354 stc_ses->conf_levels_intf_version);
2355 else
2356 status =
2357 generate_sound_trigger_recognition_config_payload(
2358 (void *)sm_levels, out_conf_levels, out_num_conf_levels,
2359 stc_ses->conf_levels_intf_version);
2360 gmm_conf_found = true;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002361 } else if (IS_SECOND_STAGE_MODEL(sm_levels->sm_id)) {
2362 confidence_level = IS_KEYWORD_DETECTION_MODEL(sm_levels->sm_id) ?
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002363 sm_levels->kw_levels[0].kw_level:
2364 sm_levels->kw_levels[0].user_levels[0].level;
2365 if (arm_second_stage) {
2366 list_for_each(node, &stc_ses->second_stage_list) {
2367 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
2368 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002369 if (IS_MATCHING_SS_MODEL(st_sec_stage->ss_info->sm_id,
2370 sm_levels->sm_id))
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002371 st_sec_stage->ss_session->confidence_threshold =
2372 confidence_level;
2373 }
2374 } else if (adsp_second_stage) {
2375 list_for_each(node, &st_hw_ses->lsm_ss_cfg_list) {
2376 ss_cfg = node_to_item(node, st_lsm_ss_config_t,
2377 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002378 if (IS_MATCHING_SS_MODEL(ss_cfg->ss_info->sm_id,
2379 sm_levels->sm_id))
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002380 ss_cfg->confidence_threshold = confidence_level;
2381 }
2382 }
2383 } else {
2384 ALOGE("%s: Unsupported sm id (%d), exiting", __func__,
2385 sm_levels->sm_id);
2386 status = -EINVAL;
2387 break;
2388 }
2389 }
2390 } else {
2391 conf_levels_v2 = (struct st_confidence_levels_info_v2 *)
2392 ((char *)opaque_conf_levels + sizeof(struct st_param_header));
2393
2394 stc_ses->st_conf_levels =
2395 calloc(1, sizeof(struct st_confidence_levels_info_v2));
2396 if (!stc_ses->st_conf_levels) {
2397 ALOGE("%s: failed to alloc st_conf_levels", __func__);
2398 return -ENOMEM;
2399 }
2400 /* Cache to use during detection event processing */
2401 memcpy(stc_ses->st_conf_levels, (char *)conf_levels_v2,
2402 sizeof(struct st_confidence_levels_info_v2));
2403
2404 for (i = 0; i < conf_levels_v2->num_sound_models; i++) {
2405 sm_levels_v2 = &conf_levels_v2->conf_levels[i];
2406 if (sm_levels_v2->sm_id == ST_SM_ID_SVA_GMM) {
Quinn Male9a345522020-03-12 17:49:25 -07002407 if (st_hw_ses == st_ses->hw_ses_cpe)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002408 status =
2409 generate_sound_trigger_recognition_config_payload_v2(
2410 (void *)sm_levels_v2, out_conf_levels, out_num_conf_levels,
2411 stc_ses->conf_levels_intf_version);
2412 else
2413 status =
2414 generate_sound_trigger_recognition_config_payload(
2415 (void *)sm_levels_v2, out_conf_levels,
2416 out_num_conf_levels, stc_ses->conf_levels_intf_version);
2417 gmm_conf_found = true;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002418 } else if (IS_SECOND_STAGE_MODEL(sm_levels_v2->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002419 confidence_level_v2 =
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002420 (IS_KEYWORD_DETECTION_MODEL(sm_levels_v2->sm_id)) ?
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002421 sm_levels_v2->kw_levels[0].kw_level:
2422 sm_levels_v2->kw_levels[0].user_levels[0].level;
2423 if (arm_second_stage) {
2424 list_for_each(node, &stc_ses->second_stage_list) {
2425 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
2426 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002427 if (IS_MATCHING_SS_MODEL(st_sec_stage->ss_info->sm_id,
2428 sm_levels_v2->sm_id))
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002429 st_sec_stage->ss_session->confidence_threshold =
2430 confidence_level_v2;
2431 }
2432 } else if (adsp_second_stage) {
2433 list_for_each(node, &st_hw_ses->lsm_ss_cfg_list) {
2434 ss_cfg = node_to_item(node, st_lsm_ss_config_t,
2435 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002436 if (IS_MATCHING_SS_MODEL(ss_cfg->ss_info->sm_id,
2437 sm_levels_v2->sm_id))
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002438 ss_cfg->confidence_threshold = confidence_level_v2;
2439 }
2440 }
2441 } else {
2442 ALOGE("%s: Unsupported sm id (%d), exiting", __func__,
2443 sm_levels_v2->sm_id);
2444 status = -EINVAL;
2445 break;
2446 }
2447 }
2448 }
2449
2450 if (!gmm_conf_found) {
2451 ALOGE("%s: Did not receive GMM confidence threshold, error!", __func__);
2452 status = -EINVAL;
2453 }
2454
2455 if (status && stc_ses->st_conf_levels) {
2456 free(stc_ses->st_conf_levels);
2457 stc_ses->st_conf_levels = NULL;
2458 }
2459 return status;
2460}
2461
2462static int update_hw_config_on_start(st_session_t *stc_ses,
2463 st_hw_session_t *st_hw_ses)
2464{
2465 struct st_param_header *param_hdr = NULL;
2466 struct st_hist_buffer_info *hist_buf = NULL;
2467 struct st_det_perf_mode_info *det_perf_mode = NULL;
2468 struct sound_trigger_recognition_config *rc_config = stc_ses->rc_config;
2469 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
2470 struct st_vendor_info *v_info = NULL;
2471 struct st_hw_ses_config *sthw_cfg = NULL;
2472 unsigned char *conf_levels = NULL;
2473 unsigned int num_conf_levels = 0;
2474 uint8_t *opaque_ptr = NULL;
2475 unsigned int opaque_size = 0, conf_levels_payload_size = 0;
2476 int status = 0;
2477 bool enable_lab = false;
Quinn Male58749452020-03-26 17:14:56 -07002478 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002479
Quinn Maleaba13db2019-07-11 15:52:14 -07002480 if (st_ses->stdev->enable_debug_dumps) {
2481 ST_DBG_DECLARE(FILE *rc_opaque_fd = NULL;
2482 static int rc_opaque_cnt = 0);
2483 ST_DBG_FILE_OPEN_WR(rc_opaque_fd, ST_DEBUG_DUMP_LOCATION,
Quinn Male2bfe13b2020-08-27 16:53:51 -07002484 "rc_config_opaque_data", "bin", rc_opaque_cnt);
Quinn Maleaba13db2019-07-11 15:52:14 -07002485 ST_DBG_FILE_WRITE(rc_opaque_fd,
2486 (uint8_t *)rc_config + rc_config->data_offset,
2487 rc_config->data_size);
2488 ST_DBG_FILE_CLOSE(rc_opaque_fd);
Quinn Male2bfe13b2020-08-27 16:53:51 -07002489 ALOGD("%s: rc_config opaque data dump stored in: rc_config_opaque_data_%d.bin",
2490 __func__, rc_opaque_cnt);
2491 rc_opaque_cnt++;
Quinn Maleaba13db2019-07-11 15:52:14 -07002492 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002493
2494 if (!st_hw_ses) {
2495 ALOGE("%s: NULL hw session !!!", __func__);
2496 return -EINVAL;
2497 }
2498
2499 v_info = st_hw_ses->vendor_uuid_info;
2500
2501 if ((rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
2502 v_info->is_qcva_uuid) {
2503 stc_ses->client_req_det_mode = ST_DET_UNKNOWN_MODE;
2504
2505 opaque_ptr = (uint8_t *)rc_config + rc_config->data_offset;
2506 while (opaque_size < rc_config->data_size) {
2507 param_hdr = (struct st_param_header *)opaque_ptr;
2508 ALOGV("%s: key %d, payload size %d", __func__,
2509 param_hdr->key_id, param_hdr->payload_size);
2510
2511 switch(param_hdr->key_id) {
2512 case ST_PARAM_KEY_CONFIDENCE_LEVELS:
2513 stc_ses->conf_levels_intf_version =
2514 *(uint32_t *)(opaque_ptr + sizeof(struct st_param_header));
2515
2516 if (stc_ses->conf_levels_intf_version !=
2517 CONF_LEVELS_INTF_VERSION_0002) {
2518 conf_levels_payload_size =
2519 sizeof(struct st_confidence_levels_info);
2520 } else {
2521 conf_levels_payload_size =
2522 sizeof(struct st_confidence_levels_info_v2);
2523 }
2524 if (param_hdr->payload_size != conf_levels_payload_size) {
2525 ALOGE("%s: Conf level format error, exiting", __func__);
2526 return -EINVAL;
2527 }
2528 status = parse_rc_config_key_conf_levels(stc_ses, st_hw_ses,
2529 opaque_ptr, &conf_levels, &num_conf_levels);
2530 opaque_size += sizeof(struct st_param_header) +
2531 conf_levels_payload_size;
2532 opaque_ptr += sizeof(struct st_param_header) +
2533 conf_levels_payload_size;
2534 if (status) {
2535 ALOGE("%s: parsing conf levels failed(status=%d)",
2536 __func__, status);
2537 return -EINVAL;
2538 }
2539 break;
2540 case ST_PARAM_KEY_HISTORY_BUFFER_CONFIG:
2541 if (param_hdr->payload_size !=
2542 sizeof(struct st_hist_buffer_info)) {
2543 ALOGE("%s: History buffer config format error, exiting",
2544 __func__);
2545 return -EINVAL;
2546 }
2547 hist_buf = (struct st_hist_buffer_info *)(opaque_ptr +
2548 sizeof(struct st_param_header));
2549 stc_ses->hist_buf_duration =
2550 hist_buf->hist_buffer_duration_msec;
2551 stc_ses->preroll_duration = hist_buf->pre_roll_duration_msec;
2552 ALOGV("%s: recognition config history buf len = %d, "
2553 "preroll len = %d, minor version = %d",
2554 __func__, hist_buf->hist_buffer_duration_msec,
2555 hist_buf->pre_roll_duration_msec, hist_buf->version);
2556 opaque_size += sizeof(struct st_param_header) +
2557 sizeof(struct st_hist_buffer_info);
2558 opaque_ptr += sizeof(struct st_param_header) +
2559 sizeof(struct st_hist_buffer_info);
2560 break;
2561 case ST_PARAM_KEY_DETECTION_PERF_MODE:
2562 if (param_hdr->payload_size !=
2563 sizeof(struct st_det_perf_mode_info)) {
2564 ALOGE("%s: Opaque data format error, exiting", __func__);
2565 return -EINVAL;
2566 }
2567 det_perf_mode = (struct st_det_perf_mode_info *)(opaque_ptr +
2568 sizeof(struct st_param_header));
2569 ALOGV("set perf mode to %d", det_perf_mode->mode);
2570 stc_ses->client_req_det_mode = det_perf_mode->mode;
2571 opaque_size += sizeof(struct st_param_header) +
2572 sizeof(struct st_det_perf_mode_info);
2573 opaque_ptr += sizeof(struct st_param_header) +
2574 sizeof(struct st_det_perf_mode_info);
2575 break;
2576 default:
2577 ALOGE("%s: Unsupported opaque data key id, exiting", __func__);
2578 return -EINVAL;
2579 }
2580 }
2581 } else if (stc_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
2582 struct sound_trigger_phrase_sound_model *phrase_sm = stc_ses->phrase_sm;
2583
2584 ALOGV("%s: num_phrases=%d, id=%d", __func__,
2585 rc_config->num_phrases, rc_config->phrases[0].id);
2586
2587 if (st_ses->vendor_uuid_info->is_qcva_uuid ||
2588 st_ses->vendor_uuid_info->is_qcmd_uuid) {
Quinn Male9a345522020-03-12 17:49:25 -07002589 if (st_hw_ses == st_ses->hw_ses_cpe)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002590 status = generate_conf_levels_payload_from_rc_config_v2(
2591 phrase_sm, rc_config, &conf_levels, &num_conf_levels);
2592 else
2593 status = generate_conf_levels_payload_from_rc_config(
2594 phrase_sm, rc_config, &conf_levels, &num_conf_levels);
2595 if (status || !conf_levels) {
2596 ALOGE("%s: failed to get conf levels from lib handle",
2597 __func__);
2598 return status;
2599 }
2600 } else {
2601 ALOGD("%s: No smlib, opaque data would be sent as is", __func__);
2602 }
2603 }
2604
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002605 enable_lab = stc_ses->rc_config->capture_requested ||
2606 !list_empty(&stc_ses->second_stage_list);
2607
Quinn Male58749452020-03-26 17:14:56 -07002608 sthw_cfg = get_sthw_cfg_for_model_id(st_hw_ses,
2609 stc_ses->sm_info.model_id);
2610 if (!sthw_cfg) {
2611 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
2612 return -EINVAL;
2613 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002614
Quinn Male58749452020-03-26 17:14:56 -07002615 if (stc_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
2616 if (v_info->merge_fs_soundmodels) {
2617 /* merge_fs_soundmodels is true only for QC SVA UUID */
2618
Xiaoyu Yeb067f472020-07-31 09:09:08 -07002619 if (conf_levels == NULL) {
2620 ALOGE("%s: Unexpected, conf_levels pointer is NULL",
2621 __func__);
2622 status = -EINVAL;
2623 return status;
2624 }
Quinn Male58749452020-03-26 17:14:56 -07002625 /*
2626 * Note:
2627 * For ADSP case, the generated conf levles size must be equal to
2628 * SML queried conf levels.
2629 * For WDSP gcs case, there is additional payload for KW enable
2630 * fields in generated conf_levels. If merge sound model is supported
2631 * on WDSP case, update logic here accordingly.
2632 */
2633 if (num_conf_levels != stc_ses->sm_info.cf_levels_size) {
2634 ALOGE("%s: Unexpected, client cf levels %d != sm_info cf levels %d",
2635 __func__, num_conf_levels, stc_ses->sm_info.cf_levels_size);
2636 return -EINVAL;
2637 }
2638
2639 /*
2640 * If any of the active clients requested capture or enabled the
2641 * second stage, the underlying hw session buffering needs to
2642 * be enabled. Ignore if it is already enabled.
2643 */
2644 if (!st_ses->lab_enabled && enable_lab)
2645 st_ses->lab_enabled = true;
2646
2647 /* Aggregate DSP configuration for highest client configuration */
2648
2649 /* SVA2.0 sound models */
2650 if (!stc_ses->hist_buf_duration &&
2651 stc_ses->rc_config->capture_requested &&
2652 (stc_ses->rc_config->data_size > 0)) {
2653 stc_ses->hist_buf_duration = st_ses->vendor_uuid_info->kw_duration;
2654 stc_ses->preroll_duration = 0;
2655 }
2656
2657 if (stc_ses->hist_buf_duration > sthw_cfg->client_req_hist_buf) {
2658 sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
2659 st_hw_ses->max_hist_buf = stc_ses->hist_buf_duration;
2660 }
2661 if (stc_ses->preroll_duration > sthw_cfg->client_req_preroll) {
2662 sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
2663 st_hw_ses->max_preroll = stc_ses->preroll_duration;
2664 }
2665
2666 ALOGV("%s: client hb_sz %d pr_sz %d, sthw lab %d hb_sz %d "
2667 "pr_sz %d", __func__, stc_ses->hist_buf_duration,
2668 stc_ses->preroll_duration, st_ses->lab_enabled,
2669 sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
2670
2671 /* Cache it to use when client restarts without config update or
2672 * during only one remaining client model as there won't be a
2673 * merged model yet.
2674 */
Revathi Uddaraju1e743262020-08-03 17:29:20 +05302675 if (!conf_levels) {
2676 ALOGE("%s: ERROR. conf levels alloc failed", __func__);
2677 status = -ENOMEM;
2678 return status;
2679 }
Quinn Male58749452020-03-26 17:14:56 -07002680 memcpy(stc_ses->sm_info.cf_levels, conf_levels,
2681 stc_ses->sm_info.cf_levels_size);
2682
2683 status = update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
2684 conf_levels, num_conf_levels, true);
2685 free(conf_levels); /* Merged model conf levels will be used further */
2686 if (status)
2687 return status;
2688
2689 p_info = get_sm_info_for_model_id(st_ses, 0);
2690 if (!p_info) {
2691 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
2692 status = -EINVAL;
2693 return status;
2694 }
2695
2696 sthw_cfg->conf_levels = p_info->sm_info.cf_levels;
2697 sthw_cfg->num_conf_levels = p_info->sm_info.cf_levels_size;
2698 sthw_cfg->model_id = 0;
2699 st_hw_ses->sthw_cfg_updated = true;
2700
2701 /*
2702 * Merging further unknown custom data is not needed, as
2703 * SVA doesn't support unkown custom data. if required in future,
2704 * handle here.
2705 * For now just copy the the current client data which is same
2706 * across SVA engines.
2707 * Update the custom data for the case in which one client session
2708 * does not have custom data and another one does.
2709 */
2710 if (rc_config->data_size > st_hw_ses->custom_data_size) {
2711 st_hw_ses->custom_data = (char *)rc_config + rc_config->data_offset;
2712 st_hw_ses->custom_data_size = rc_config->data_size;
2713 }
2714 } else {
2715 st_ses->recognition_mode = stc_ses->recognition_mode;
2716 st_ses->lab_enabled = enable_lab;
2717 sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
2718 st_hw_ses->max_hist_buf = stc_ses->hist_buf_duration;
2719 sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
2720 st_hw_ses->max_preroll = stc_ses->preroll_duration;
2721
2722 if (sthw_cfg->conf_levels)
2723 free(sthw_cfg->conf_levels);
2724 sthw_cfg->conf_levels = conf_levels;
2725 sthw_cfg->num_conf_levels = num_conf_levels;
2726
2727 st_hw_ses->custom_data = (char *)rc_config + rc_config->data_offset;
2728 st_hw_ses->custom_data_size = rc_config->data_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002729 }
2730
Quinn Male58749452020-03-26 17:14:56 -07002731
2732 } else {
Xiaoyu Yeb067f472020-07-31 09:09:08 -07002733 if (conf_levels == NULL) {
2734 ALOGE("%s: Unexpected, conf_levels pointer is NULL",
2735 __func__);
2736 status = -EINVAL;
2737 return status;
2738 }
2739
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002740 if (!st_ses->lab_enabled && enable_lab)
2741 st_ses->lab_enabled = true;
2742
Quinn Male58749452020-03-26 17:14:56 -07002743 sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
2744 if (st_hw_ses->max_hist_buf < stc_ses->hist_buf_duration)
2745 st_hw_ses->max_hist_buf = stc_ses->hist_buf_duration;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002746
Quinn Male58749452020-03-26 17:14:56 -07002747 sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
2748 if (st_hw_ses->max_preroll < stc_ses->preroll_duration)
2749 st_hw_ses->max_preroll = stc_ses->preroll_duration;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002750
2751 /*
Quinn Malebed88ad2020-07-10 14:51:12 -07002752 * User verification confidence is not required
2753 * in SVA5 PDK_UV case. As first stage doesn't
2754 * support user verification.
2755 */
2756 num_conf_levels = 1;
2757
2758 /*
Quinn Male58749452020-03-26 17:14:56 -07002759 * Cache it to use when client restarts without
2760 * config update
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002761 */
Quinn Male58749452020-03-26 17:14:56 -07002762 memcpy(stc_ses->sm_info.cf_levels, conf_levels,
2763 num_conf_levels);
2764 stc_ses->sm_info.cf_levels_size = num_conf_levels;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002765
Quinn Male58749452020-03-26 17:14:56 -07002766 memcpy(sthw_cfg->conf_levels, conf_levels,
2767 num_conf_levels);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002768 sthw_cfg->num_conf_levels = num_conf_levels;
Quinn Male58749452020-03-26 17:14:56 -07002769 free(conf_levels);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002770
Quinn Male58749452020-03-26 17:14:56 -07002771 if (rc_config->data_size >= st_hw_ses->custom_data_size) {
2772 st_hw_ses->custom_data = (char *)rc_config + rc_config->data_offset;
2773 st_hw_ses->custom_data_size = rc_config->data_size;
2774 }
2775 st_hw_ses->sthw_cfg_updated = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002776 }
2777 ALOGD("%s:[%d] lab enabled %d", __func__, st_ses->sm_handle,
2778 st_ses->lab_enabled);
2779
2780 return status;
2781}
2782
Quinn Male58749452020-03-26 17:14:56 -07002783static int reg_all_sm(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses)
2784{
2785 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
2786 struct listnode *node = NULL;
2787 int status = 0;
2788
2789 list_for_each(node, &st_ses->sm_info_list) {
2790 p_info = node_to_item(node, struct st_proxy_ses_sm_info_wrapper,
2791 sm_list_node);
2792 status = hw_ses->fptrs->reg_sm(hw_ses, p_info->sm_info.sm_data,
2793 p_info->sm_info.sm_size, p_info->sm_info.model_id);
2794 if (status) {
2795 ALOGE("%s:[%d] reg_sm failed, model_id = %d, status = %d", __func__,
2796 st_ses->sm_handle, p_info->sm_info.model_id, status);
2797 return status;
2798 }
2799 }
2800
2801 return 0;
2802}
2803
2804static int dereg_all_sm(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses)
2805{
2806 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
2807 struct listnode *node = NULL;
2808 int status = 0, ret = 0;
2809
2810 list_for_each(node, &st_ses->sm_info_list) {
2811 p_info = node_to_item(node, struct st_proxy_ses_sm_info_wrapper,
2812 sm_list_node);
2813 status = hw_ses->fptrs->dereg_sm(hw_ses, p_info->sm_info.model_id);
2814 if (status) {
2815 ALOGE("%s:[%d] dereg_sm failed, model_id = %d, status = %d", __func__,
2816 st_ses->sm_handle, p_info->sm_info.model_id, status);
2817 ret = status;
2818 }
2819 }
2820
2821 return ret;
2822}
2823
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002824static void do_hw_sess_cleanup(st_proxy_session_t *st_ses,
2825 st_hw_session_t *hw_ses, enum hw_session_err_mask err)
Quinn Male2e883752019-03-22 11:28:54 -07002826{
2827 if (err & HW_SES_ERR_MASK_BUFFERING)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002828 hw_ses->fptrs->stop_buffering(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002829
2830 if (err & HW_SES_ERR_MASK_STARTED) {
2831 hw_ses->fptrs->stop(hw_ses);
2832 st_ses->hw_session_started = false;
2833 }
2834
2835 if (err & HW_SES_ERR_MASK_REG_SM_PARAM)
2836 hw_ses->fptrs->dereg_sm_params(hw_ses);
2837
2838 if (err & HW_SES_ERR_MASK_DEVICE_SET)
2839 hw_ses->fptrs->set_device(hw_ses, false);
2840
2841 if (err & HW_SES_ERR_MASK_REG_SM)
Quinn Male58749452020-03-26 17:14:56 -07002842 dereg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002843}
2844
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002845static void reg_hal_event_session(st_session_t *stc_ses,
2846 st_hw_session_t *hw_ses)
Quinn Male2e883752019-03-22 11:28:54 -07002847{
2848 struct sound_trigger_event_info event_info;
2849 /* Pass the pcm information to audio hal for capturing LAB */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002850 if ((stc_ses->rc_config &&
2851 stc_ses->rc_config->capture_requested) &&
2852 stc_ses->stdev->audio_hal_cb) {
2853 ALOGD("%s:[c%d] ST_EVENT_SESSION_REGISTER capture_handle %d",
2854 __func__, stc_ses->sm_handle, stc_ses->capture_handle);
2855 event_info.st_ses.p_ses = (void *)stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07002856 event_info.st_ses.config = hw_ses->config;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002857 event_info.st_ses.capture_handle = stc_ses->capture_handle;
Quinn Male2e883752019-03-22 11:28:54 -07002858 /*
2859 * set pcm to NULL as this version of st_hal doesn't pass pcm to
2860 * audio HAL
2861 */
2862 event_info.st_ses.pcm = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002863 stc_ses->stdev->audio_hal_cb(ST_EVENT_SESSION_REGISTER, &event_info);
Quinn Male2e883752019-03-22 11:28:54 -07002864 }
2865}
2866
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002867static void dereg_hal_event_session(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07002868{
2869 struct sound_trigger_event_info event_info;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002870 /* Indicate to audio hal that to stop reading LAB data */
2871 if ((stc_ses->rc_config &&
2872 stc_ses->rc_config->capture_requested) &&
2873 stc_ses->stdev->audio_hal_cb) {
2874 ALOGD("%s:[c%d] ST_EVENT_SESSION_DEREGISTER capture_handle %d",
2875 __func__, stc_ses->sm_handle, stc_ses->capture_handle);
2876 event_info.st_ses.p_ses = (void *)stc_ses;
2877 event_info.st_ses.capture_handle = stc_ses->capture_handle;
Quinn Male2e883752019-03-22 11:28:54 -07002878 event_info.st_ses.pcm = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002879 stc_ses->stdev->audio_hal_cb(ST_EVENT_SESSION_DEREGISTER, &event_info);
Quinn Male2e883752019-03-22 11:28:54 -07002880 }
2881}
2882
Zhou Songcd3c8e62019-07-16 13:30:19 +08002883static bool check_gcs_usecase_switch
2884(
2885 st_proxy_session_t *st_ses
2886)
2887{
2888 struct st_vendor_info *v_info = NULL;
2889 st_hw_session_t *p_ses = NULL;
2890 st_hw_session_gcs_t *p_gcs_ses = NULL;
2891 int st_device = 0;
2892 unsigned int device_acdb_id = 0;
2893 int capture_device;
2894
2895 if (!st_ses || st_ses->exec_mode != ST_EXEC_MODE_CPE) {
2896 ALOGE("%s: Invalid session or non CPE session!", __func__);
2897 return false;
2898 }
2899
2900 p_ses = st_ses->hw_ses_cpe;
2901 p_gcs_ses = (st_hw_session_gcs_t *)p_ses;
2902 v_info = p_ses->vendor_uuid_info;
2903
2904 if (list_empty(&v_info->gcs_usecase_list)) {
2905 ALOGE("%s: gcs usecase not available", __func__);
2906 return false;
2907 }
2908
2909 /* check if need to switch gcs usecase for new capture device */
2910 capture_device = platform_stdev_get_capture_device(p_ses->stdev->platform);
2911 st_device = platform_stdev_get_device(p_ses->stdev->platform,
2912 v_info, capture_device, p_ses->exec_mode);
2913 device_acdb_id = platform_stdev_get_acdb_id(st_device,
2914 p_ses->exec_mode);
2915 if (platform_stdev_get_xml_version(p_ses->stdev->platform) >=
2916 PLATFORM_XML_VERSION_0x0102) {
2917 int i = 0;
2918 while ((i < MAX_GCS_USECASE_ACDB_IDS) &&
2919 p_gcs_ses->gcs_usecase->acdb_ids[i]) {
2920 if (p_gcs_ses->gcs_usecase->acdb_ids[i] == device_acdb_id)
2921 return false;
2922 i++;
2923 }
2924 ALOGD("%s: gcs usecase doesn't match for new device", __func__);
2925 return true;
2926 } else {
2927 return false;
2928 }
2929}
2930
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002931static int start_hw_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
2932 bool load_sm)
Quinn Male2e883752019-03-22 11:28:54 -07002933{
2934 int status = 0, err = 0;
Zhou Songcd3c8e62019-07-16 13:30:19 +08002935 bool do_unload = false;
Quinn Male2e883752019-03-22 11:28:54 -07002936
2937 /*
Quinn Male3d7d9d42019-05-20 13:35:01 -07002938 * It is possible the BE LPI mode has been updated, but not the FE mode.
2939 * DSP requires both FE and BE to be in the same mode for any configuration
2940 * changes between LPI and non-LPI switch, so update the FE mode to the
Quinn Malecc1affd2019-07-18 16:13:31 -07002941 * same as BE mode by re-opening LSM session. This is also used for
2942 * other transition usecases which require dereg_sm and reg_sm.
Quinn Male2e883752019-03-22 11:28:54 -07002943 */
Quinn Malecc1affd2019-07-18 16:13:31 -07002944 if (hw_ses->lpi_enable != hw_ses->stdev->lpi_enable ||
2945 (hw_ses->barge_in_mode != hw_ses->stdev->barge_in_mode &&
2946 !hw_ses->stdev->support_dynamic_ec_update)) {
Quinn Male3d7d9d42019-05-20 13:35:01 -07002947 hw_ses->lpi_enable = hw_ses->stdev->lpi_enable;
Quinn Malecc1affd2019-07-18 16:13:31 -07002948 hw_ses->barge_in_mode = hw_ses->stdev->barge_in_mode;
Zhou Songcd3c8e62019-07-16 13:30:19 +08002949 do_unload = true;
Zhou Song388d0342020-02-16 16:31:05 +08002950 platform_stdev_reset_backend_cfg(hw_ses->stdev->platform);
Zhou Songcd3c8e62019-07-16 13:30:19 +08002951 }
2952
2953 /*
2954 * For gcs sessions, uid may be changed for new capture device,
2955 * in this case, sm must be dereg and reg again.
2956 */
2957 if (check_gcs_usecase_switch(st_ses))
2958 do_unload = true;
2959
2960 if (do_unload) {
Quinn Male2e883752019-03-22 11:28:54 -07002961 if (!load_sm) {
2962 load_sm = true;
Quinn Male58749452020-03-26 17:14:56 -07002963 status = dereg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002964 if (status)
2965 ALOGW("%s:[%d] failed to dereg_sm err %d", __func__,
2966 st_ses->sm_handle, status);
2967 }
2968 }
2969
2970 if (load_sm) {
Quinn Male58749452020-03-26 17:14:56 -07002971 status = reg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002972 if (status) {
2973 ALOGE("%s:[%d] failed to reg_sm err %d", __func__,
2974 st_ses->sm_handle, status);
2975 goto cleanup;
2976 }
2977 err |= HW_SES_ERR_MASK_REG_SM;
2978 }
2979
2980 status = hw_ses->fptrs->set_device(hw_ses, true);
2981 if (status) {
2982 ALOGE("%s:[%d] failed to set_device err %d", __func__,
2983 st_ses->sm_handle, status);
2984 goto cleanup;
2985 }
2986 err |= HW_SES_ERR_MASK_DEVICE_SET;
2987
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002988 status = hw_ses->fptrs->reg_sm_params(hw_ses, st_ses->recognition_mode,
Quinn Male58749452020-03-26 17:14:56 -07002989 st_ses->lab_enabled, st_ses->rc_config);
Quinn Male2e883752019-03-22 11:28:54 -07002990 if (status) {
2991 ALOGE("%s:[%d] failed to reg_sm_params err %d", __func__,
2992 st_ses->sm_handle, status);
2993 goto cleanup;
2994 }
2995 err |= HW_SES_ERR_MASK_REG_SM_PARAM;
2996
2997 status = hw_ses->fptrs->start(hw_ses);
2998 if (status) {
2999 ALOGE("%s:[%d] failed to start err %d", __func__,
3000 st_ses->sm_handle, status);
3001 goto cleanup;
3002 }
3003 err |= HW_SES_ERR_MASK_STARTED;
3004
3005 st_ses->hw_session_started = true;
3006 return status;
3007
3008cleanup:
3009 do_hw_sess_cleanup(st_ses, hw_ses, err);
3010 return status;
3011}
3012
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003013static int stop_hw_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
3014 bool unload_sm)
Quinn Male2e883752019-03-22 11:28:54 -07003015{
3016 int status = 0;
3017 int rc = 0;
3018
3019 status = hw_ses->fptrs->stop(hw_ses);
3020 if (status) {
3021 ALOGE("%s:[%d] failed to stop err %d", __func__,
3022 st_ses->sm_handle, status);
3023 rc = status;
3024 }
3025
3026 status = hw_ses->fptrs->dereg_sm_params(hw_ses);
3027 if (status) {
3028 ALOGE("%s:[%d] failed to dereg_sm_params err %d", __func__,
3029 st_ses->sm_handle, status);
3030 rc = status;
3031 }
3032
3033 status = hw_ses->fptrs->set_device(hw_ses, false);
3034 if (status) {
3035 ALOGE("%s:[%d] failed to set_device err %d", __func__,
3036 st_ses->sm_handle, status);
3037 rc = status;
3038 }
3039 if (unload_sm) {
Quinn Male58749452020-03-26 17:14:56 -07003040 status = dereg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07003041 if (status) {
3042 ALOGE("%s:[%d] failed to dereg_sm, err %d", __func__,
3043 st_ses->sm_handle, status);
3044 rc = status;
3045 }
3046 }
3047
3048 /* This must be set to false irrespective as the above calls may
3049 * return error (esp for SSR)
3050 */
3051 st_ses->hw_session_started = false;
3052 return rc;
3053}
3054
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003055static int start_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
3056 bool load_sm)
Quinn Male2e883752019-03-22 11:28:54 -07003057{
3058 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003059
Quinn Male2e883752019-03-22 11:28:54 -07003060 if (st_ses->hw_session_started) {
3061 ALOGE("%s:[%d] already started", __func__, st_ses->sm_handle);
3062 return -1;
3063 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003064
Quinn Male2e883752019-03-22 11:28:54 -07003065 status = start_hw_session(st_ses, hw_ses, load_sm);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003066 hw_ses->sthw_cfg_updated = false;
3067
Quinn Male2e883752019-03-22 11:28:54 -07003068 return status;
3069}
3070
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003071static int restart_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses)
Quinn Male2e883752019-03-22 11:28:54 -07003072{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003073 int status = 0;
3074
3075 status = hw_ses->fptrs->restart(hw_ses, st_ses->recognition_mode,
Quinn Male58749452020-03-26 17:14:56 -07003076 st_ses->rc_config);
Quinn Male2e883752019-03-22 11:28:54 -07003077 if (status == 0) {
3078 st_ses->hw_session_started = true;
3079 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003080 ALOGE("%s:[%d] failed to restart", __func__, st_ses->sm_handle);
Zhou Song944d8742019-09-26 16:22:06 +08003081 /*
3082 * lower layers like gcs/lsm need to handle double stop calls properly
3083 * to avoid possible crash, as some of the clean ups are already issued
3084 * during fptrs->restart() when it's failed.
3085 */
3086 stop_hw_session(st_ses, hw_ses, true);
Quinn Male2e883752019-03-22 11:28:54 -07003087 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003088
Quinn Male2e883752019-03-22 11:28:54 -07003089 return status;
3090}
3091
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003092static int stop_session(st_proxy_session_t *st_ses,
3093 st_hw_session_t *hw_ses, bool unload_sm)
Quinn Male2e883752019-03-22 11:28:54 -07003094{
3095 if (!st_ses->hw_session_started) {
3096 ALOGV("%s:[%d] already stopped", __func__, st_ses->sm_handle);
3097 return 0;
3098 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003099 st_ses->detection_requested = false;
Quinn Male2e883752019-03-22 11:28:54 -07003100 return stop_hw_session(st_ses, hw_ses, unload_sm);
3101}
3102
3103/*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003104 * This function gets the first stage detection keyword indices, which are
3105 * needed by the second stage sessions. If the legacy DSP is used, which does
3106 * not provide keyword indices, set the indices to include the entire keyword
3107 * duration. This function also gets the user confidence level if there is an
3108 * active voiceprint session.
Quinn Male2e883752019-03-22 11:28:54 -07003109 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003110static int get_first_stage_detection_params(st_proxy_session_t *st_ses,
3111 void *payload, size_t payload_size)
Quinn Male2e883752019-03-22 11:28:54 -07003112{
3113 size_t count_size = 0;
3114 uint8_t *payload_ptr = (uint8_t *)payload;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003115 uint8_t *cf_levels = NULL;
3116 uint32_t key_id = 0, key_payload_size = 0, cf_levels_size = 0;
Quinn Male2e883752019-03-22 11:28:54 -07003117 uint32_t kw_start_ms = 0, kw_end_ms = 0;
3118 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003119 struct listnode *node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07003120 st_arm_second_stage_t *st_sec_stage = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003121 st_session_t *stc_ses = st_ses->det_stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07003122 bool is_active_vop_session = false;
Quinn Male58749452020-03-26 17:14:56 -07003123 multi_model_result_info_t *result_info = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07003124
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003125 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07003126 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003127 if (st_sec_stage->ss_info->sm_detection_type ==
3128 ST_SM_TYPE_USER_VERIFICATION) {
Quinn Male2e883752019-03-22 11:28:54 -07003129 is_active_vop_session = true;
3130 break;
3131 }
3132 }
3133
3134 if (hw_ses->is_generic_event) {
3135 /*
3136 * This case is for the generic detection event from the DSP. Set the
3137 * keyword start and end indices and user confidence level based on key
3138 * id, if applicable.
3139 */
3140 while (count_size < payload_size) {
3141 key_id = *(uint32_t *)payload_ptr;
3142 key_payload_size = *((uint32_t *)payload_ptr + 1);
3143
3144 switch (key_id) {
Quinn Male58749452020-03-26 17:14:56 -07003145 case KEY_ID_MULTI_MODEL_RESULT_INFO:
3146 result_info = (multi_model_result_info_t *)(payload_ptr +
3147 GENERIC_DET_EVENT_HEADER_SIZE);
3148 hw_ses->kw_start_idx = result_info->keyword_start_idx_bytes;
3149 hw_ses->kw_end_idx = result_info->keyword_end_idx_bytes;
3150 break;
3151
Quinn Male2e883752019-03-22 11:28:54 -07003152 case KEY_ID_CONFIDENCE_LEVELS:
3153 if (is_active_vop_session) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003154 /*
3155 * It is expected that VoP is supported with single KW/user
3156 * SVA3.0 model, hence get it directly with hard offset.
3157 */
Quinn Male58749452020-03-26 17:14:56 -07003158 if (!st_ses->sm_merged) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003159 hw_ses->user_level = (int32_t)(*(payload_ptr +
3160 GENERIC_DET_EVENT_USER_LEVEL_OFFSET));
3161 } else {
3162 /* Extract from first stage merged conf levels */
3163 check_and_extract_det_conf_levels_payload(st_ses,
3164 payload_ptr + (4 * sizeof(uint32_t)),
3165 *((uint32_t *)payload_ptr + 3),
3166 &cf_levels, &cf_levels_size);
3167 if (!cf_levels || !cf_levels_size)
3168 break;
3169 hw_ses->user_level = cf_levels[1];
3170 ALOGV("%s:hw_ses->user_level %d at cf_levels[1]",
3171 __func__, hw_ses->user_level);
3172 }
Quinn Male2e883752019-03-22 11:28:54 -07003173 }
3174 break;
3175
3176 case KEY_ID_KEYWORD_POSITION_STATS:
3177 hw_ses->kw_start_idx = *((uint32_t *)payload_ptr +
3178 GENERIC_DET_EVENT_KW_START_OFFSET);
3179 hw_ses->kw_end_idx = *((uint32_t *)payload_ptr +
3180 GENERIC_DET_EVENT_KW_END_OFFSET);
3181 break;
3182
Quinn Male58749452020-03-26 17:14:56 -07003183 case KEY_ID_TIMESTAMP_INFO:
3184 /* No op */
3185 break;
3186
Quinn Male2e883752019-03-22 11:28:54 -07003187 default:
3188 ALOGW("%s: Unsupported generic detection event key id",
3189 __func__);
3190 break;
3191 }
3192 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Quinn Male58749452020-03-26 17:14:56 -07003193 payload_ptr += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Quinn Male2e883752019-03-22 11:28:54 -07003194 }
3195 } else {
3196 /*
3197 * This case is for the DSP detection events which are not the generic
3198 * detection event. There will be no keyword indices from first stage
3199 * detection, so the start index will be 0 and the end index will be the
3200 * buffer duration sent from the app. If this is not sent, the keyword
3201 * duration from platform xml will be used.
3202 */
3203 hw_ses->kw_start_idx = 0;
Quinn Male58749452020-03-26 17:14:56 -07003204 if (hw_ses->max_hist_buf) {
Quinn Male2e883752019-03-22 11:28:54 -07003205 hw_ses->kw_end_idx =
Quinn Male58749452020-03-26 17:14:56 -07003206 convert_ms_to_bytes(hw_ses->max_hist_buf,
Quinn Male2e883752019-03-22 11:28:54 -07003207 &hw_ses->config);
3208 } else {
3209 hw_ses->kw_end_idx =
3210 convert_ms_to_bytes(st_ses->vendor_uuid_info->kw_duration,
3211 &hw_ses->config);
3212 }
3213
3214 if (is_active_vop_session) {
Quinn Male9a345522020-03-12 17:49:25 -07003215 if (st_ses->exec_mode == ST_EXEC_MODE_CPE) {
Quinn Male2e883752019-03-22 11:28:54 -07003216 hw_ses->user_level = (int32_t)(*(payload_ptr +
3217 GCS_NON_GENERIC_USER_LEVEL_OFFSET));
Quinn Male9a345522020-03-12 17:49:25 -07003218 } else if (st_ses->exec_mode == ST_EXEC_MODE_ADSP) {
Quinn Male2e883752019-03-22 11:28:54 -07003219 hw_ses->user_level = (int32_t)(*(payload_ptr +
3220 LSM_NON_GENERIC_USER_LEVEL_OFFSET));
3221 }
3222 }
3223 }
3224
3225 kw_start_ms = convert_bytes_to_ms(hw_ses->kw_start_idx, &hw_ses->config);
3226 kw_end_ms = convert_bytes_to_ms(hw_ses->kw_end_idx, &hw_ses->config);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003227 ALOGD("%s:[%d] 1st stage kw_start = %dms, kw_end = %dms,"
3228 "is_generic_event %d", __func__, st_ses->sm_handle,
3229 kw_start_ms, kw_end_ms, hw_ses->is_generic_event);
Quinn Male2e883752019-03-22 11:28:54 -07003230
3231 return 0;
3232}
3233
Quinn Male12f5c6f2019-11-14 17:34:10 -08003234static inline int prepare_second_stage_for_client(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07003235{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003236 struct listnode *node = NULL;
3237 st_arm_second_stage_t *st_sec_stage = NULL;
3238 int status = 0;
3239
3240 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
3241
3242 list_for_each(node, &stc_ses->second_stage_list) {
3243 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
3244 status = st_second_stage_prepare_session(st_sec_stage);
3245 }
3246 return status;
3247}
3248
3249static inline int start_second_stage_for_client(st_session_t *stc_ses)
3250{
3251 struct listnode *node = NULL;
3252 st_arm_second_stage_t *st_sec_stage = NULL;
3253 int status = 0;
3254
3255 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
3256
3257 list_for_each(node, &stc_ses->second_stage_list) {
3258 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
3259 status = st_second_stage_start_session(st_sec_stage);
3260 }
3261 return status;
3262}
3263
3264static inline void stop_second_stage_for_client(st_session_t *stc_ses)
3265{
3266 struct listnode *node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07003267 st_arm_second_stage_t *st_sec_stage = NULL;
3268
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003269 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
3270
3271 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07003272 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
3273 st_second_stage_stop_session(st_sec_stage);
3274 }
3275}
3276
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003277static int generate_legacy_st_phrase_recognition_event
3278(
3279 const struct sound_trigger_phrase_sound_model *phrase_sm,
3280 const struct sound_trigger_recognition_config *rc_config,
3281 const void *payload,
3282 unsigned int payload_size,
3283 struct sound_trigger_phrase_recognition_event **out_rc_event
3284)
3285{
3286 struct sound_trigger_phrase_recognition_event *event;
3287 unsigned int i = 0, j = 0, user_id = 0;
3288
3289 ALOGD("%s: Enter payload_size %d", __func__, payload_size);
3290
3291 if(!payload || !phrase_sm || !rc_config || !out_rc_event) {
3292 ALOGE("%s: Null params", __func__);
3293 return -EINVAL;
3294 }
3295
3296 *out_rc_event = NULL;
3297 event = calloc(1, sizeof(*event) + payload_size);
3298 if (!event) {
3299 ALOGE("%s: event allocation failed size %d", __func__, payload_size);
3300 return -ENODEV;
3301 }
3302
3303 event->num_phrases = rc_config->num_phrases;
3304 event->common.data_offset = sizeof(*event);
3305 event->common.data_size = payload_size;
3306 memcpy((char *)event + event->common.data_offset, payload, payload_size);
3307
3308 /* fill confidence levels */
3309 for (i = 0; i < rc_config->num_phrases; i++) {
3310 event->phrase_extras[i].id = rc_config->phrases[i].id;
3311 event->phrase_extras[i].recognition_modes =
3312 phrase_sm->phrases[0].recognition_mode;
3313 event->phrase_extras[i].confidence_level = ((char *)payload)[i];
3314 event->phrase_extras[i].num_levels = rc_config->phrases[i].num_levels;
3315 for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
3316 user_id = rc_config->phrases[i].levels[j].user_id;
3317 event->phrase_extras[i].levels[j].user_id = user_id;
3318 event->phrase_extras[i].levels[j].level =
3319 ((char *)payload)[user_id];
3320 }
3321 }
3322
3323 *out_rc_event = event;
3324 return 0;
3325}
3326
3327/*
3328 * This function sets the opaque data size for the DSP's generic detection
3329 * events. This opaque data can now have varying size based on the requested
3330 * params.
3331 */
3332static size_t set_opaque_data_size(char *payload, size_t payload_size,
3333 uint32_t version)
3334{
3335 size_t count_size = 0, opaque_size = 0;
3336 uint32_t key_id = 0, key_payload_size = 0;
3337
3338 while (count_size < payload_size) {
3339 key_id = *(uint32_t *)payload;
3340 key_payload_size = *((uint32_t *)payload + 1);
3341
3342 switch (key_id) {
Quinn Male58749452020-03-26 17:14:56 -07003343 case KEY_ID_MULTI_MODEL_RESULT_INFO:
3344 opaque_size += sizeof(struct st_param_header);
3345 if (version != CONF_LEVELS_INTF_VERSION_0002) {
3346 opaque_size +=
3347 sizeof(struct st_confidence_levels_info);
3348 } else {
3349 opaque_size +=
3350 sizeof(struct st_confidence_levels_info_v2);
3351 }
3352
3353 opaque_size += sizeof(struct st_param_header) +
3354 sizeof(struct st_keyword_indices_info);
3355 opaque_size += sizeof(struct st_param_header) +
3356 sizeof(struct st_timestamp_info);
3357 break;
3358
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003359 case KEY_ID_CONFIDENCE_LEVELS:
3360 opaque_size += sizeof(struct st_param_header);
3361 if (version != CONF_LEVELS_INTF_VERSION_0002) {
3362 opaque_size +=
3363 sizeof(struct st_confidence_levels_info);
3364 } else {
3365 opaque_size +=
3366 sizeof(struct st_confidence_levels_info_v2);
3367 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003368 break;
3369
3370 case KEY_ID_KEYWORD_POSITION_STATS:
3371 opaque_size += sizeof(struct st_param_header) +
3372 sizeof(struct st_keyword_indices_info);
Quinn Male58749452020-03-26 17:14:56 -07003373 break;
3374
3375 case KEY_ID_TIMESTAMP_INFO:
3376 opaque_size += sizeof(struct st_param_header) +
3377 sizeof(struct st_timestamp_info);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003378 break;
3379
3380 default:
3381 ALOGE("%s: Unsupported generic detection event key id", __func__);
Quinn Male58749452020-03-26 17:14:56 -07003382 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003383 }
Quinn Male58749452020-03-26 17:14:56 -07003384 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
3385 payload += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003386 }
3387
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003388 return opaque_size;
3389}
3390
3391/*
3392 * This function packs the updated opaque data confidence levels which are
3393 * passed to the client via callback.
3394 */
3395static int pack_opaque_data_conf_levels(
3396 st_proxy_session_t *st_ses, void *opaque_data,
3397 uint8_t *payload,
3398 unsigned int payload_size)
3399{
3400 uint8_t *payload_ptr = payload;
3401 unsigned int i = 0, j = 0, k = 0, user_id = 0;
3402 st_arm_second_stage_t *st_sec_stage = NULL;
3403 struct listnode *node = NULL;
3404 struct st_confidence_levels_info *conf_levels = NULL;
3405 struct st_confidence_levels_info_v2 *conf_levels_v2 = NULL;
3406 st_session_t *stc_ses = st_ses->det_stc_ses;
3407 int32_t kw_level = 0, user_level = 0;
3408
3409 list_for_each(node, &stc_ses->second_stage_list) {
3410 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003411 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003412 kw_level = st_sec_stage->ss_session->confidence_score;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003413 } else if (IS_USER_VERIFICATION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003414 user_level = st_sec_stage->ss_session->confidence_score;
3415 }
3416 }
3417
3418 if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002) {
3419 conf_levels = (struct st_confidence_levels_info *)opaque_data;
3420 for (i = 0; i < conf_levels->num_sound_models; i++) {
3421 if (conf_levels->conf_levels[i].sm_id == ST_SM_ID_SVA_GMM) {
3422 for (j = 0;
3423 j < conf_levels->conf_levels[i].num_kw_levels; j++) {
3424 if (j <= payload_size)
3425 conf_levels->conf_levels[i].kw_levels[j].kw_level =
3426 payload_ptr[j];
3427 else
3428 ALOGE("%s: unexpected conf size %d < %d", __func__,
3429 payload_size, j);
3430 for (k = 0;
3431 k < conf_levels->conf_levels[i].kw_levels[j].num_user_levels;
3432 k++) {
3433 user_id =
3434 conf_levels->conf_levels[i].kw_levels[j].
3435 user_levels[k].user_id;
3436 if (user_id <= payload_size)
3437 conf_levels->conf_levels[i].kw_levels[j].
3438 user_levels[k].level = payload_ptr[user_id];
3439 else
3440 ALOGE("%s: Unexpected conf size %d < %d", __func__,
3441 payload_size, user_id);
3442 }
3443 }
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003444 } else if (IS_KEYWORD_DETECTION_MODEL(conf_levels->conf_levels[i].sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003445 conf_levels->conf_levels[i].kw_levels[0].kw_level = kw_level;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003446 } else if (IS_USER_VERIFICATION_MODEL(conf_levels->conf_levels[i].sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003447 /*
3448 * Fill both the keyword and user confidence level with the
3449 * confidence score returned from the voiceprint algorithm.
3450 */
3451 conf_levels->conf_levels[i].kw_levels[0].kw_level =
3452 (uint8_t)user_level;
3453 conf_levels->conf_levels[i].kw_levels[0].user_levels[0].level =
3454 (uint8_t)user_level;
3455 }
3456 }
3457 } else {
3458 conf_levels_v2 = (struct st_confidence_levels_info_v2 *)opaque_data;
3459 for (i = 0; i < conf_levels_v2->num_sound_models; i++) {
3460 if (conf_levels_v2->conf_levels[i].sm_id == ST_SM_ID_SVA_GMM) {
3461 for (j = 0;
3462 j < conf_levels_v2->conf_levels[i].num_kw_levels; j++) {
3463 if (j <= payload_size)
3464 conf_levels_v2->conf_levels[i].kw_levels[j].kw_level =
3465 payload_ptr[j];
3466 else
3467 ALOGE("%s: unexpected conf size %d < %d", __func__,
3468 payload_size, j);
3469
3470 for (k = 0;
3471 k < conf_levels_v2->conf_levels[i].kw_levels[j].num_user_levels;
3472 k++) {
3473 user_id =
3474 conf_levels_v2->conf_levels[i].kw_levels[j].
3475 user_levels[k].user_id;
3476 if (user_id <= payload_size)
3477 conf_levels_v2->conf_levels[i].kw_levels[j].
3478 user_levels[k].level = payload_ptr[user_id];
3479 else
3480 ALOGE("%s: Unexpected conf size %d < %d", __func__,
3481 payload_size, user_id);
3482 }
3483 }
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003484 } else if (IS_KEYWORD_DETECTION_MODEL(conf_levels_v2->conf_levels[i].sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003485 conf_levels_v2->conf_levels[i].kw_levels[0].kw_level = kw_level;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003486 } else if (IS_USER_VERIFICATION_MODEL(conf_levels_v2->conf_levels[i].sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003487 /*
3488 * Fill both the keyword and user confidence level with the
3489 * confidence score returned from the voiceprint algorithm.
3490 */
3491 conf_levels_v2->conf_levels[i].kw_levels[0].kw_level =
3492 user_level;
3493 conf_levels_v2->conf_levels[i].kw_levels[0].user_levels[0].level =
3494 user_level;
3495 }
3496 }
3497 }
3498
3499 return 0;
3500}
3501
3502/* This function packs the sound trigger API confidence levels */
3503static int pack_recognition_event_conf_levels(
3504 st_proxy_session_t *st_ses, uint8_t *payload,
3505 unsigned int payload_size,
3506 struct sound_trigger_phrase_recognition_event *local_event)
3507{
3508 unsigned int j = 0, k = 0, user_id = 0;
3509 st_arm_second_stage_t *st_sec_stage = NULL;
3510 struct listnode *node = NULL;
3511 st_session_t *stc_ses = st_ses->det_stc_ses;
3512 struct sound_trigger_phrase_sound_model *phrase_sm =
3513 (struct sound_trigger_phrase_sound_model *)stc_ses->phrase_sm;
3514
3515 /*
3516 * Fill in the GMM confidence levels to the sound trigger recognition event
3517 * APIs first. If any second stage session is enabled, overwrite the APIs
3518 * with the second stage confidence levels.
3519 */
3520 for (j = 0; j < stc_ses->rc_config->num_phrases; j++) {
3521 local_event->phrase_extras[j].id = stc_ses->rc_config->phrases[j].id;
3522 local_event->phrase_extras[j].recognition_modes =
3523 phrase_sm->phrases[j].recognition_mode;
3524 local_event->phrase_extras[j].num_levels =
3525 stc_ses->rc_config->phrases[j].num_levels;
3526 if (j <= payload_size)
3527 local_event->phrase_extras[j].confidence_level = payload[j];
3528 else
3529 ALOGE("%s: unexpected conf size %d < %d", __func__,
3530 payload_size, j);
3531
3532 for (k = 0; k < stc_ses->rc_config->phrases[j].num_levels; k++) {
3533 user_id = stc_ses->rc_config->phrases[j].levels[k].user_id;
3534 if (user_id <= payload_size) {
3535 local_event->phrase_extras[j].levels[k].user_id = user_id;
3536 local_event->phrase_extras[j].levels[k].level =
3537 payload[user_id];
3538 } else {
3539 ALOGE("%s: Unexpected conf size %d < %d", __func__,
3540 payload_size, user_id);
3541 }
3542 }
3543 }
3544
3545 list_for_each(node, &stc_ses->second_stage_list) {
3546 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003547 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003548 local_event->phrase_extras[0].confidence_level =
3549 (uint8_t)st_sec_stage->ss_session->confidence_score;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003550 } else if (IS_USER_VERIFICATION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003551 local_event->phrase_extras[0].levels[0].level =
3552 (uint8_t)st_sec_stage->ss_session->confidence_score;
3553 }
3554 }
3555 return 0;
3556}
3557
3558static int parse_generic_event_and_pack_opaque_data(
3559 st_proxy_session_t *st_ses, uint8_t *opaque_data,
3560 uint8_t *payload, size_t payload_size,
3561 struct sound_trigger_phrase_recognition_event *local_event)
3562{
3563 uint32_t key_id = 0, key_payload_size = 0;
Quinn Male58749452020-03-26 17:14:56 -07003564 uint32_t timestamp_msw = 0, timestamp_lsw = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003565 struct st_param_header *param_hdr = NULL;
3566 struct st_keyword_indices_info *kw_indices = NULL;
3567 struct st_timestamp_info *timestamps = NULL;
3568 size_t count_size = 0;
3569 st_arm_second_stage_t *st_sec_stage = NULL;
3570 struct listnode *node = NULL;
3571 st_session_t *stc_ses = st_ses->det_stc_ses;
3572 int status = 0;
3573 unsigned char *cf_levels = NULL;
3574 unsigned int cf_levels_size = 0;
Quinn Male58749452020-03-26 17:14:56 -07003575 multi_model_result_info_t *result_info = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003576
3577 while (count_size < payload_size) {
3578 key_id = *(uint32_t *)payload;
3579 key_payload_size = *((uint32_t *)payload + 1);
3580
3581 switch (key_id) {
Quinn Male58749452020-03-26 17:14:56 -07003582 case KEY_ID_MULTI_MODEL_RESULT_INFO:
3583 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
3584 ALOGE("%s: Error. Multi sm result info supported on PDK5 only",
3585 __func__);
3586 status = -EINVAL;
3587 goto exit;
3588 }
3589 /* Set confidence levels */
3590 param_hdr = (struct st_param_header *)opaque_data;
3591 param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
3592 opaque_data += sizeof(struct st_param_header);
3593 if (stc_ses->conf_levels_intf_version !=
3594 CONF_LEVELS_INTF_VERSION_0002) {
3595 param_hdr->payload_size =
3596 sizeof(struct st_confidence_levels_info);
3597 } else {
3598 param_hdr->payload_size =
3599 sizeof(struct st_confidence_levels_info_v2);
3600 }
3601 result_info = (multi_model_result_info_t *)(payload +
3602 GENERIC_DET_EVENT_HEADER_SIZE);
3603
3604 memset(stc_ses->sm_info.det_cf_levels, 0,
3605 MAX_MULTI_SM_CONF_LEVELS);
3606
3607 cf_levels = stc_ses->sm_info.det_cf_levels;
3608 cf_levels_size = stc_ses->sm_info.cf_levels_size;
3609 memcpy(opaque_data, stc_ses->st_conf_levels,
3610 param_hdr->payload_size);
3611 *(cf_levels + result_info->detected_keyword_id) =
3612 result_info->best_confidence_level;
3613 pack_opaque_data_conf_levels(st_ses, opaque_data,
3614 cf_levels, cf_levels_size);
3615 pack_recognition_event_conf_levels(st_ses, cf_levels,
3616 cf_levels_size, local_event);
3617 opaque_data += param_hdr->payload_size;
3618
3619 /* Set keyword indices */
3620 param_hdr = (struct st_param_header *)opaque_data;
3621 param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
3622 param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
3623 opaque_data += sizeof(struct st_param_header);
3624 kw_indices = (struct st_keyword_indices_info *)opaque_data;
3625 kw_indices->version = 0x1;
3626 kw_indices->start_index = result_info->keyword_start_idx_bytes;
3627 kw_indices->end_index = result_info->keyword_end_idx_bytes;
3628
3629 list_for_each(node, &stc_ses->second_stage_list) {
3630 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
3631 list_node);
3632 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
3633 kw_indices->start_index =
3634 st_sec_stage->ss_session->kw_start_idx;
3635 kw_indices->end_index =
3636 st_sec_stage->ss_session->kw_end_idx;
3637 }
3638 }
3639 opaque_data += sizeof(struct st_keyword_indices_info);
3640
3641 /* Set timestamp */
3642 param_hdr = (struct st_param_header *)opaque_data;
3643 param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
3644 param_hdr->payload_size = sizeof(struct st_timestamp_info);
3645 opaque_data += sizeof(struct st_param_header);
3646 timestamps = (struct st_timestamp_info *)opaque_data;
3647 timestamps->version = 0x1;
3648 timestamps->first_stage_det_event_time =
3649 (uint64_t)result_info->timestamp_msw_us << 32 |
3650 result_info->timestamp_lsw_us;
3651 if (!list_empty(&stc_ses->second_stage_list))
3652 timestamps->second_stage_det_event_time =
3653 st_ses->hw_ses_current->second_stage_det_event_time;
3654 opaque_data += sizeof(struct st_timestamp_info);
3655 break;
3656
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003657 case KEY_ID_CONFIDENCE_LEVELS:
3658 /* Pack the opaque data confidence levels structure */
Quinn Male58749452020-03-26 17:14:56 -07003659 param_hdr = (struct st_param_header *)opaque_data;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003660 param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
3661 opaque_data += sizeof(struct st_param_header);
3662 if (stc_ses->conf_levels_intf_version !=
3663 CONF_LEVELS_INTF_VERSION_0002) {
3664 param_hdr->payload_size =
3665 sizeof(struct st_confidence_levels_info);
3666 } else {
3667 param_hdr->payload_size =
3668 sizeof(struct st_confidence_levels_info_v2);
3669 }
3670 check_and_extract_det_conf_levels_payload(st_ses,
3671 payload + (4 * sizeof(uint32_t)), *((uint32_t *)payload + 3),
3672 &cf_levels, &cf_levels_size);
3673 if (!cf_levels || !cf_levels_size) {
3674 status = -EINVAL;
3675 goto exit;
3676 }
3677 memcpy(opaque_data, stc_ses->st_conf_levels,
3678 param_hdr->payload_size);
3679 pack_opaque_data_conf_levels(st_ses, opaque_data,
3680 cf_levels, cf_levels_size);
3681 pack_recognition_event_conf_levels(st_ses, cf_levels,
3682 cf_levels_size, local_event);
3683 opaque_data += param_hdr->payload_size;
3684 break;
3685
3686 case KEY_ID_KEYWORD_POSITION_STATS:
3687 /* Pack the opaque data keyword indices structure */
Quinn Male58749452020-03-26 17:14:56 -07003688 param_hdr = (struct st_param_header *)opaque_data;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003689 param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
3690 param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
3691 opaque_data += sizeof(struct st_param_header);
Quinn Male58749452020-03-26 17:14:56 -07003692 kw_indices = (struct st_keyword_indices_info *)opaque_data;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003693 kw_indices->version = 0x1;
3694 kw_indices->start_index = *((uint32_t *)payload + 3);
3695 kw_indices->end_index = *((uint32_t *)payload + 4);
3696
3697 list_for_each(node, &stc_ses->second_stage_list) {
3698 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
3699 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003700 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003701 kw_indices->start_index =
3702 st_sec_stage->ss_session->kw_start_idx;
3703 kw_indices->end_index =
3704 st_sec_stage->ss_session->kw_end_idx;
3705 }
3706 }
3707 opaque_data += sizeof(struct st_keyword_indices_info);
3708 break;
3709
Quinn Male58749452020-03-26 17:14:56 -07003710 case KEY_ID_TIMESTAMP_INFO:
3711 /* Pack the opaque data detection timestamp structure */
3712 param_hdr = (struct st_param_header *)opaque_data;
3713 param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
3714 param_hdr->payload_size = sizeof(struct st_timestamp_info);
3715 opaque_data += sizeof(struct st_param_header);
3716 timestamp_lsw = *((uint32_t *)payload + 3);
3717 timestamp_msw = *((uint32_t *)payload + 4);
3718 timestamps = (struct st_timestamp_info *)opaque_data;
3719 timestamps->version = 0x1;
3720 timestamps->first_stage_det_event_time =
3721 (uint64_t)timestamp_msw << 32 | timestamp_lsw;
3722 if (!list_empty(&stc_ses->second_stage_list))
3723 timestamps->second_stage_det_event_time =
3724 st_ses->hw_ses_current->second_stage_det_event_time;
3725 opaque_data += sizeof(struct st_timestamp_info);
3726 break;
3727
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003728 default:
3729 ALOGE("%s: Unsupported generic detection event key id", __func__);
3730 status = -EINVAL;
3731 goto exit;
3732 }
3733 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Quinn Male58749452020-03-26 17:14:56 -07003734 payload += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003735 }
3736
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003737exit:
3738 return status;
3739}
3740
3741static int parse_generic_event_without_opaque_data(
3742 st_proxy_session_t *st_ses, uint8_t *payload, size_t payload_size,
3743 struct sound_trigger_phrase_recognition_event *local_event)
3744{
3745 uint32_t key_id = 0, key_payload_size = 0;
3746 size_t count_size = 0;
3747 int status = 0;
3748 unsigned char *cf_levels = NULL;
Quinn Male58749452020-03-26 17:14:56 -07003749 unsigned int cf_levels_size = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003750
3751 while (count_size < payload_size) {
3752 key_id = *(uint32_t *)payload;
3753 key_payload_size = *((uint32_t *)payload + 1);
3754
3755 switch (key_id) {
3756 case KEY_ID_CONFIDENCE_LEVELS:
3757 check_and_extract_det_conf_levels_payload(st_ses,
3758 payload + (4 * sizeof(uint32_t)), *((uint32_t *)payload + 3),
3759 &cf_levels, &cf_levels_size);
3760 if (!cf_levels || !cf_levels_size) {
3761 status = -EINVAL;
3762 return status;
3763 }
3764 pack_recognition_event_conf_levels(st_ses, cf_levels,
3765 cf_levels_size, local_event);
3766 return status;
3767
3768 case KEY_ID_KEYWORD_POSITION_STATS:
3769 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Quinn Male58749452020-03-26 17:14:56 -07003770 payload += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
3771 break;
3772
3773 case KEY_ID_TIMESTAMP_INFO:
3774 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
3775 payload += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003776 break;
3777
3778 default:
3779 ALOGE("%s: Unsupported generic detection event key id", __func__);
3780 status = -EINVAL;
3781 return status;
3782 }
3783 }
3784 return status;
3785}
3786
3787/*
3788 * This function handles detection payloads in the format of the DSP's
3789 * generic detection event.
3790 */
3791int process_detection_event_keyphrase_v2(
3792 st_proxy_session_t *st_ses, int detect_status,
3793 void *payload, size_t payload_size,
3794 struct sound_trigger_phrase_recognition_event **event)
3795{
3796 st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
3797 st_session_t *stc_ses = st_ses->det_stc_ses;
3798 unsigned int i = 0, j = 0;
3799 int status = 0;
3800 uint8_t *opaque_data = NULL;
3801 size_t opaque_size = 0;
3802 struct sound_trigger_phrase_recognition_event *local_event = NULL;
3803
3804 if (st_ses->vendor_uuid_info->is_qcva_uuid)
3805 opaque_size = set_opaque_data_size(payload, payload_size,
3806 stc_ses->conf_levels_intf_version);
3807 else
3808 opaque_size = payload_size;
3809
3810 local_event = calloc(1,
3811 sizeof(struct sound_trigger_phrase_recognition_event) + opaque_size);
3812 if (!local_event) {
3813 ALOGE("%s: local_event allocation failed, opaque data size = %d",
3814 __func__, (unsigned int)opaque_size);
3815 return -ENOMEM;
3816 }
3817
3818 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3819 local_event->common.data_offset =
3820 sizeof(struct sound_trigger_phrase_recognition_event);
3821 local_event->common.data_size = opaque_size;
3822 opaque_data = (uint8_t *)local_event + local_event->common.data_offset;
3823
3824 if (st_ses->vendor_uuid_info->is_qcva_uuid) {
3825 if (stc_ses->rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) {
3826 status = parse_generic_event_and_pack_opaque_data(st_ses,
3827 opaque_data, payload, payload_size, local_event);
3828 if (status) {
3829 ALOGE("%s: Failed to parse generic detection event with opaque"
3830 "data %d", __func__, status);
3831 goto exit;
3832 }
3833
Quinn Maleaba13db2019-07-11 15:52:14 -07003834 if (st_ses->stdev->enable_debug_dumps) {
3835 ST_DBG_DECLARE(FILE *opaque_fd = NULL;
3836 static int opaque_cnt = 0);
3837 ST_DBG_FILE_OPEN_WR(opaque_fd, ST_DEBUG_DUMP_LOCATION,
Quinn Male2bfe13b2020-08-27 16:53:51 -07003838 "detection_opaque_data", "bin", opaque_cnt);
Quinn Maleaba13db2019-07-11 15:52:14 -07003839 ST_DBG_FILE_WRITE(opaque_fd, opaque_data, opaque_size);
3840 ST_DBG_FILE_CLOSE(opaque_fd);
Quinn Male2bfe13b2020-08-27 16:53:51 -07003841 ALOGD("%s: detection opaque data dump stored in: detection_opaque_data_%d.bin",
3842 __func__, opaque_cnt);
3843 opaque_cnt++;
Quinn Maleaba13db2019-07-11 15:52:14 -07003844 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003845 } else {
3846 status = parse_generic_event_without_opaque_data(st_ses, payload,
3847 payload_size, local_event);
3848 if (status) {
3849 ALOGE("%s: Failed to parse generic detection event without"
3850 "opaque data %d", __func__, status);
3851 goto exit;
3852 }
3853 }
3854 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003855 memcpy(local_event->phrase_extras,
3856 stc_ses->rc_config->phrases, stc_ses->rc_config->num_phrases *
3857 sizeof(struct sound_trigger_phrase_recognition_extra));
3858 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3859 local_event->common.data_offset = sizeof(*local_event);
3860 local_event->common.data_size = opaque_size;
3861 memcpy(opaque_data, payload, opaque_size);
3862 opaque_data += opaque_size;
3863 }
3864
3865 /*
3866 * fill the remaining recognition event parameters not specific
3867 * to soundmodel lib
3868 */
3869 local_event->common.status = detect_status;
3870 local_event->common.type = stc_ses->phrase_sm->common.type;
3871 local_event->common.model = stc_ses->sm_handle;
3872 local_event->common.capture_available =
3873 stc_ses->rc_config->capture_requested;
3874 local_event->common.capture_delay_ms = 0;
3875 local_event->common.capture_preamble_ms = 0;
3876 local_event->common.audio_config.sample_rate =
3877 SOUND_TRIGGER_SAMPLING_RATE_16000;
3878 local_event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
3879 local_event->common.audio_config.channel_mask =
3880 audio_channel_in_mask_from_count(st_hw_ses->config.channels);
3881
3882 for (i = 0; i < local_event->num_phrases; ++i) {
3883 ALOGV("%s: [%d] kw_id %d level %d", __func__, i,
3884 local_event->phrase_extras[i].id,
3885 local_event->phrase_extras[i].confidence_level);
3886 for (j = 0; j < local_event->phrase_extras[i].num_levels; ++j) {
3887 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
3888 local_event->phrase_extras[i].levels[j].user_id,
3889 local_event->phrase_extras[i].levels[j].level);
3890 }
3891 }
3892
3893 ALOGI("%s:[c%d]", __func__, stc_ses->sm_handle);
3894
3895 ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
3896 "num_phrases=%d id=%d", __func__, stc_ses->sm_handle,
3897 local_event->common.status, local_event->common.type,
3898 local_event->common.model, local_event->common.capture_available,
3899 local_event->num_phrases, local_event->phrase_extras[0].id);
3900
3901 *event = local_event;
3902 return 0;
3903
3904exit:
3905 if (local_event)
3906 free(local_event);
3907 return status;
3908}
3909
3910/*
3911 * This function handles detection payloads in the format of the DSP's
3912 * legacy (non-generic) detection event.
3913 * TODO: Deprecate this when DSP for all shared targets of this component
3914 * move to generic event.
3915 */
3916static int process_detection_event_keyphrase(
3917 st_proxy_session_t *st_ses, int detect_status,
3918 void *payload, size_t payload_size,
3919 struct sound_trigger_phrase_recognition_event **event)
3920{
3921 st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
3922 st_session_t *stc_ses = st_ses->det_stc_ses;
3923 unsigned int i = 0, j = 0;
3924 int status = 0;
3925 struct sound_trigger_phrase_recognition_event *local_event = NULL;
3926 size_t opaque_size = 0;
3927 uint8_t *opaque_data = NULL, *payload_ptr = NULL;
3928 struct st_param_header *param_hdr = NULL;
3929 st_arm_second_stage_t *st_sec_stage = NULL;
3930 struct listnode *node = NULL;
3931 struct st_keyword_indices_info *kw_indices = NULL;
3932 struct st_timestamp_info *timestamps = NULL;
3933 bool enable_kw_indices = false;
3934 unsigned char *cf_levels = NULL;
3935 unsigned int cf_levels_size = 0;
3936
3937 if ((stc_ses->rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
3938 st_ses->vendor_uuid_info->is_qcva_uuid) {
3939 /*
3940 * This logic is for the updated opaque data format. Sound trigger
3941 * recognition event APIs are filled along with the opaque data's
3942 * confidence levels, keyword indices, and timestamp parameters.
3943 */
3944 opaque_size = (2 * sizeof(struct st_param_header)) +
3945 sizeof(struct st_timestamp_info);
3946 if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002)
3947 opaque_size += sizeof(struct st_confidence_levels_info);
3948 else
3949 opaque_size += sizeof(struct st_confidence_levels_info_v2);
3950
3951 list_for_each(node, &stc_ses->second_stage_list) {
3952 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003953 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003954 enable_kw_indices = true;
3955 opaque_size += sizeof(struct st_param_header) +
3956 sizeof(struct st_keyword_indices_info);
3957 break;
3958 }
3959 }
3960
3961 local_event = calloc(1,
3962 sizeof(struct sound_trigger_phrase_recognition_event) +
3963 opaque_size);
3964 if (!local_event) {
3965 ALOGE("%s: local_event allocation failed, opaque data size = %d",
3966 __func__, (unsigned int)opaque_size);
3967 return -ENOMEM;
3968 }
3969
3970 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3971 local_event->common.data_offset =
3972 sizeof(struct sound_trigger_phrase_recognition_event);
3973 local_event->common.data_size = opaque_size;
3974 opaque_data = (uint8_t *)local_event + local_event->common.data_offset;
Quinn Male9a345522020-03-12 17:49:25 -07003975 if (st_ses->exec_mode == ST_EXEC_MODE_CPE) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003976 payload_ptr = (uint8_t *)payload + 2;
3977 payload_size -= 2; /* Re-use */
Quinn Male9a345522020-03-12 17:49:25 -07003978 } else if (st_ses->exec_mode == ST_EXEC_MODE_ADSP) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003979 payload_ptr = (uint8_t *)payload;
3980 } else {
3981 ALOGE("%s: Invalid execution mode, exiting", __func__);
3982 status = -EINVAL;
3983 goto err_exit;
3984 }
3985
3986 /* Pack the opaque data confidence levels structure */
3987 param_hdr = (struct st_param_header *)opaque_data;
3988 param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
3989 opaque_data += sizeof(struct st_param_header);
3990 if (stc_ses->conf_levels_intf_version !=
3991 CONF_LEVELS_INTF_VERSION_0002) {
3992 param_hdr->payload_size =
3993 sizeof(struct st_confidence_levels_info);
3994 } else {
3995 param_hdr->payload_size =
3996 sizeof(struct st_confidence_levels_info_v2);
3997 }
3998 check_and_extract_det_conf_levels_payload(st_ses, payload_ptr,
3999 payload_size, &cf_levels, &cf_levels_size);
4000 if (!cf_levels || !cf_levels_size) {
4001 status = -EINVAL;
4002 goto err_exit;
4003 }
4004 memcpy(opaque_data, stc_ses->st_conf_levels, param_hdr->payload_size);
4005 pack_opaque_data_conf_levels(st_ses, opaque_data, cf_levels,
4006 cf_levels_size);
4007 pack_recognition_event_conf_levels(st_ses, cf_levels, cf_levels_size,
4008 local_event);
4009 opaque_data += param_hdr->payload_size;
4010
4011 /* Pack the opaque data keyword indices structure */
4012 if (enable_kw_indices) {
4013 param_hdr = (struct st_param_header *)opaque_data;
4014 param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
4015 param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
4016 opaque_data += sizeof(struct st_param_header);
4017 kw_indices = (struct st_keyword_indices_info *)opaque_data;
4018 kw_indices->version = 0x1;
4019 list_for_each(node, &stc_ses->second_stage_list) {
4020 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
4021 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07004022 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004023 kw_indices->start_index =
4024 st_sec_stage->ss_session->kw_start_idx;
4025 kw_indices->end_index =
4026 st_sec_stage->ss_session->kw_end_idx;
4027 }
4028 }
4029 opaque_data += sizeof(struct st_keyword_indices_info);
4030 }
4031
4032 /* Pack the opaque data detection timestamp structure */
4033 param_hdr = (struct st_param_header *)opaque_data;
4034 param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
4035 param_hdr->payload_size = sizeof(struct st_timestamp_info);
4036 opaque_data += sizeof(struct st_param_header);
4037 timestamps = (struct st_timestamp_info *)opaque_data;
4038 timestamps->version = 0x1;
4039 timestamps->first_stage_det_event_time =
4040 st_hw_ses->first_stage_det_event_time;
4041 if (!list_empty(&stc_ses->second_stage_list))
4042 timestamps->second_stage_det_event_time =
4043 st_hw_ses->second_stage_det_event_time;
4044 opaque_data += sizeof(struct st_timestamp_info);
4045
Quinn Maleaba13db2019-07-11 15:52:14 -07004046 if (st_ses->stdev->enable_debug_dumps) {
4047 ST_DBG_DECLARE(FILE *opaque_fd = NULL; static int opaque_cnt = 0);
4048 ST_DBG_FILE_OPEN_WR(opaque_fd, ST_DEBUG_DUMP_LOCATION,
Quinn Male2bfe13b2020-08-27 16:53:51 -07004049 "detection_opaque_data", "bin", opaque_cnt);
Quinn Maleaba13db2019-07-11 15:52:14 -07004050 ST_DBG_FILE_WRITE(opaque_fd, (opaque_data - opaque_size),
4051 opaque_size);
4052 ST_DBG_FILE_CLOSE(opaque_fd);
Quinn Male2bfe13b2020-08-27 16:53:51 -07004053 ALOGD("%s: detection opaque data dump stored in: detection_opaque_data_%d.bin",
4054 __func__, opaque_cnt);
4055 opaque_cnt++;
Quinn Maleaba13db2019-07-11 15:52:14 -07004056 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004057
4058 } else {
4059 if (st_ses->vendor_uuid_info->is_qcva_uuid ||
4060 st_ses->vendor_uuid_info->is_qcmd_uuid) {
Quinn Male9a345522020-03-12 17:49:25 -07004061 if (ST_EXEC_MODE_CPE == st_ses->exec_mode &&
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004062 !st_hw_ses->is_generic_event) {
4063 payload_ptr = payload;
4064 payload_ptr += 2; /* Skip minor_version and num_active_models */
4065 payload_size -= 2;
4066 } else {
4067 payload_ptr = payload;
4068 }
4069 status = generate_legacy_st_phrase_recognition_event(
4070 stc_ses->phrase_sm, stc_ses->rc_config, payload_ptr,
4071 payload_size, &local_event);
4072
4073 if (status)
4074 goto exit;
4075 } else {
4076 ALOGD("%s: Send detection payload as is", __func__);
4077
4078 local_event = calloc(1, sizeof(*local_event) + payload_size);
4079 if (!local_event) {
4080 ALOGE("%s: event allocation failed, size %zd", __func__,
4081 payload_size);
4082 status = -ENOMEM;
4083 goto exit;
4084 }
4085 memcpy(local_event->phrase_extras,
4086 stc_ses->rc_config->phrases, stc_ses->rc_config->num_phrases *
4087 sizeof(struct sound_trigger_phrase_recognition_extra));
4088 local_event->num_phrases = stc_ses->rc_config->num_phrases;
4089 local_event->common.data_offset = sizeof(*local_event);
4090 local_event->common.data_size = payload_size;
4091 memcpy((char *)local_event + local_event->common.data_offset,
4092 payload, payload_size);
4093 }
4094 }
4095
4096 /* fill the remaining recognition event parameters not specific
4097 to soundmodel lib */
4098 local_event->common.status = detect_status;
4099 local_event->common.type = stc_ses->phrase_sm->common.type;
4100 local_event->common.model = stc_ses->sm_handle;
4101 local_event->common.capture_available =
4102 stc_ses->rc_config->capture_requested;
4103 local_event->common.capture_delay_ms = 0;
4104 local_event->common.capture_preamble_ms = 0;
4105 local_event->common.audio_config.sample_rate =
4106 SOUND_TRIGGER_SAMPLING_RATE_16000;
4107 local_event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
4108 local_event->common.audio_config.channel_mask =
4109 audio_channel_in_mask_from_count(st_hw_ses->config.channels);
4110
4111 for (i = 0; i < local_event->num_phrases; ++i) {
4112 ALOGV("%s: [%d] kw_id %d level %d", __func__, i,
4113 local_event->phrase_extras[i].id,
4114 local_event->phrase_extras[i].confidence_level);
4115 for (j = 0; j < local_event->phrase_extras[i].num_levels; ++j) {
4116 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
4117 local_event->phrase_extras[i].levels[j].user_id,
4118 local_event->phrase_extras[i].levels[j].level);
4119 }
4120 }
4121
4122 ALOGI("%s:[c%d]", __func__, stc_ses->sm_handle);
4123
4124 ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
4125 "num_phrases=%d id=%d", __func__, stc_ses->sm_handle,
4126 local_event->common.status, local_event->common.type,
4127 local_event->common.model, local_event->common.capture_available,
4128 local_event->num_phrases, local_event->phrase_extras[0].id);
4129
4130 *event = local_event;
4131 return 0;
4132
4133err_exit:
4134 if (local_event)
4135 free(local_event);
4136
4137exit:
4138 return status;
4139}
4140
4141static int process_detection_event_generic(st_proxy_session_t *st_ses,
4142 int detect_status,
4143 void *payload, size_t payload_size,
4144 struct sound_trigger_recognition_event **event)
4145{
4146 st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
4147 st_session_t *stc_ses = st_ses->det_stc_ses;
4148 struct st_vendor_info *v_info = st_ses->vendor_uuid_info;
4149 int status = 0;
4150 struct sound_trigger_recognition_event *local_event = NULL;
4151
4152 local_event = calloc(1, sizeof(*local_event) + payload_size);
4153 if (!local_event) {
4154 ALOGE("%s: event allocation failed, size %zd", __func__,
4155 payload_size);
4156 status = -ENOMEM;
4157 goto exit;
4158 }
4159
4160 local_event->status = detect_status;
4161 local_event->type = stc_ses->sm_type;
4162 local_event->model = stc_ses->sm_handle;
4163 local_event->capture_available = stc_ses->rc_config->capture_requested;
4164 local_event->capture_delay_ms = 0;
4165 local_event->capture_preamble_ms = 0;
4166 local_event->audio_config.sample_rate = v_info ?
4167 v_info->sample_rate : SOUND_TRIGGER_SAMPLING_RATE_16000;
4168 local_event->audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
4169 local_event->audio_config.channel_mask =
4170 audio_channel_in_mask_from_count(st_hw_ses->config.channels);
4171
4172 local_event->data_offset = sizeof(*local_event);
4173 local_event->data_size = payload_size;
4174 memcpy((char *)local_event + local_event->data_offset,
4175 payload, payload_size);
4176
4177 ALOGI("%s:[%d]", __func__, stc_ses->sm_handle);
4178 ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d",
4179 __func__, stc_ses->sm_handle, local_event->status,
4180 local_event->type, local_event->model,
4181 local_event->capture_available);
4182
4183 *event = local_event;
4184
4185exit:
4186 return status;
4187}
4188
4189static inline int process_detection_event(st_proxy_session_t *st_ses,
4190 uint64_t timestamp __unused,
4191 int detect_status,
4192 void *payload, size_t payload_size,
4193 struct sound_trigger_recognition_event **event)
4194{
4195 int ret;
4196 struct sound_trigger_phrase_recognition_event *phrase_event = NULL;
4197
4198 *event = NULL;
Quinn Male58749452020-03-26 17:14:56 -07004199 if (st_ses->det_stc_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004200 if (sthw_extn_check_process_det_ev_support())
4201 ret = sthw_extn_process_detection_event_keyphrase(st_ses,
4202 timestamp, detect_status, payload, payload_size, &phrase_event);
4203 else if (st_ses->hw_ses_current->is_generic_event &&
4204 !st_ses->vendor_uuid_info->is_qcmd_uuid)
4205 ret = process_detection_event_keyphrase_v2(st_ses, detect_status,
4206 payload, payload_size, &phrase_event);
4207 else
4208 ret = process_detection_event_keyphrase(st_ses, detect_status,
4209 payload, payload_size, &phrase_event);
4210 if (phrase_event)
4211 *event = &phrase_event->common;
4212 } else {
4213 ret = process_detection_event_generic(st_ses, detect_status, payload,
4214 payload_size, event);
4215 }
4216 return ret;
4217}
4218
4219
4220/*
4221 * If the keyword detection session detects before the user verification
4222 * session, signal to process user verification. If the keyword detection
4223 * session rejects before the user verification session, signal to stop
4224 * processing user verification.
4225 */
4226static void handle_vop_pending_detection(st_arm_ss_session_t *ss_session,
4227 unsigned int det_status, unsigned int kw_det_buff_sz)
4228{
4229 if (det_status & KEYWORD_DETECTION_SUCCESS) {
4230 if (kw_det_buff_sz > ss_session->unread_bytes)
4231 ss_session->buff_sz = kw_det_buff_sz;
4232 else
4233 ss_session->buff_sz = ss_session->unread_bytes;
4234
4235 /*
4236 * It is possible that VOP started processing by already consuming
4237 * data from unread_bytes while CNN detects. In this case, it does
4238 * not need to be signaled.
4239 */
4240 if (ss_session->unread_bytes >= ss_session->buff_sz) {
4241 ALOGD("%s: Processing UV due to KW detection success", __func__);
4242 pthread_cond_signal(&ss_session->cond);
4243 }
4244 } else if (det_status & KEYWORD_DETECTION_REJECT) {
4245 ss_session->exit_buffering = true;
4246 ALOGD("%s: Exiting from UV due to KW detection rejection", __func__);
4247 pthread_cond_signal(&ss_session->cond);
4248 }
4249}
4250
4251/*
4252 * If the user verification session rejects before the keyword detection
4253 * session, signal to stop processing keyword detection.
4254 */
4255static void handle_cnn_pending_detection(st_arm_ss_session_t *ss_session,
4256 unsigned int det_status)
4257{
4258 if (det_status & USER_VERIFICATION_REJECT) {
4259 ss_session->exit_buffering = true;
4260 ALOGD("%s: Exiting from KW detection due to UV rejection", __func__);
4261 pthread_cond_signal(&ss_session->cond);
4262 }
4263}
4264
4265/*
4266 * This thread handles detection events from the second stage sessions
4267 * and aggregates them into 1 final decision. It will call the client callback
4268 * or restart the first stage session based on this decision.
4269 */
4270static void *aggregator_thread_loop(void *st_session)
4271{
4272 st_proxy_session_t *st_ses = (st_proxy_session_t *)st_session;
4273 st_session_t *stc_ses = NULL;
4274 recognition_callback_t callback = NULL;
4275 void *cookie = NULL;
4276 struct listnode *node = NULL;
4277 st_arm_second_stage_t *st_sec_stage = NULL;
4278 int status = 0, lock_status = 0;
4279 unsigned int kw_det_buff_sz = 0, det_status = 0;
4280 struct timespec tspec = {0};
4281 struct sound_trigger_recognition_event *event = NULL;
4282 bool capture_requested = false;
Quinn Maled0814de2019-05-29 17:33:22 -07004283 uint64_t callback_time = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004284
4285 ALOGV("%s: Enter", __func__);
4286
4287 /*
4288 * For multi-clients it is expected only one of the clients detection
4289 * happens at a time. Continue processing on a run time detected client
4290 */
4291 pthread_mutex_lock(&st_ses->ss_detections_lock);
4292 while (!st_ses->exit_aggregator_loop) {
4293 det_status = 0;
4294 lock_status = 0;
4295 ALOGV("%s: waiting on cond", __func__);
4296 pthread_cond_wait(&st_ses->ss_detections_cond,
4297 &st_ses->ss_detections_lock);
4298 ALOGV("%s: done waiting on cond", __func__);
4299 if (st_ses->exit_aggregator_loop) {
4300 ALOGV("%s: exit", __func__);
4301 pthread_mutex_unlock(&st_ses->ss_detections_lock);
4302 return NULL;
4303 }
4304 if (!st_ses->det_stc_ses)
4305 continue;
4306 stc_ses = st_ses->det_stc_ses;
4307
4308 list_for_each(node, &stc_ses->second_stage_list) {
4309 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
4310 list_node);
4311
4312 pthread_mutex_lock(&st_sec_stage->ss_session->lock);
4313 det_status |= st_sec_stage->ss_session->det_status;
4314 if (st_sec_stage->ss_session->det_status ==
4315 KEYWORD_DETECTION_SUCCESS)
4316 kw_det_buff_sz = st_sec_stage->ss_session->bytes_processed;
4317 pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
4318 }
4319
4320 list_for_each(node, &stc_ses->second_stage_list) {
4321 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
4322 list_node);
4323
4324 pthread_mutex_lock(&st_sec_stage->ss_session->lock);
4325 if ((st_sec_stage->ss_info->sm_detection_type ==
4326 ST_SM_TYPE_USER_VERIFICATION) &&
4327 (det_status & USER_VERIFICATION_PENDING)) {
4328 handle_vop_pending_detection(st_sec_stage->ss_session,
4329 det_status, kw_det_buff_sz);
4330 } else if ((st_sec_stage->ss_info->sm_detection_type ==
4331 ST_SM_TYPE_KEYWORD_DETECTION) &&
4332 (det_status & KEYWORD_DETECTION_PENDING)) {
4333 handle_cnn_pending_detection(st_sec_stage->ss_session,
4334 det_status);
4335 }
4336 pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
4337 }
4338
4339 if (!IS_SS_DETECTION_PENDING(det_status)) {
4340 pthread_mutex_lock(&st_ses->lock);
4341 /*
4342 * If the client stops before 2nd stage finishes processing, or a
4343 * transition is in progress, the detection event should not be
4344 * handled.
4345 */
4346 if ((st_ses->current_state != buffering_state_fn) ||
4347 (st_ses->exec_mode == ST_EXEC_MODE_NONE)) {
4348 ALOGW("%s: First stage is not in a valid state, continuing",
4349 __func__);
4350 pthread_mutex_unlock(&st_ses->lock);
4351 continue;
4352 }
4353 if (IS_SS_DETECTION_SUCCESS(det_status)) {
4354 clock_gettime(CLOCK_MONOTONIC, &tspec);
4355 st_ses->hw_ses_current->second_stage_det_event_time =
4356 get_current_time_ns();
4357 ATRACE_ASYNC_END("sthal: detection success",
4358 st_ses->sm_handle);
4359
Quinn Male2bfe13b2020-08-27 16:53:51 -07004360 stc_ses->ss_det_count++;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004361 status = process_detection_event(st_ses,
4362 st_ses->det_session_ev->payload.detected.timestamp,
4363 st_ses->det_session_ev->payload.detected.detect_status,
4364 st_ses->det_session_ev->payload.detected.detect_payload,
4365 st_ses->det_session_ev->payload.detected.payload_size,
4366 &event);
4367 if (status || !event) {
4368 ALOGE("%s:[%d] process_detection_event failed err %d",
4369 __func__, st_ses->sm_handle, status);
4370 /*
4371 * Stop buffering if this is not a successful detection and
4372 * LAB is triggered in hw automatically
4373 */
4374 st_ses->hw_ses_current->fptrs->stop_buffering(
4375 st_ses->hw_ses_current);
4376
4377 pthread_mutex_unlock(&st_ses->lock);
4378 if (event) {
4379 free(event);
4380 event = NULL;
4381 }
4382 goto exit;
4383 }
Venkatesh Mangalappalib4243f42019-08-19 15:25:39 -07004384 stc_ses->detection_sent = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004385 callback = stc_ses->callback;
4386 capture_requested = stc_ses->rc_config->capture_requested;
4387 cookie = stc_ses->cookie;
Quinn Maled0814de2019-05-29 17:33:22 -07004388 callback_time = get_current_time_ns();
Quinn Male2bfe13b2020-08-27 16:53:51 -07004389 ALOGD("%s:[c%d] Second stage detection SUCCESS, "
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004390 "calling client callback", __func__, stc_ses->sm_handle);
Quinn Maled0814de2019-05-29 17:33:22 -07004391 ALOGD("%s: Total sthal processing time: %llums", __func__,
4392 (callback_time - st_ses->detection_event_time) /
4393 NSECS_PER_MSEC);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004394 pthread_mutex_unlock(&st_ses->lock);
4395 ATRACE_BEGIN("sthal: client detection callback");
4396 callback(event, cookie);
4397 free(event);
4398 ATRACE_END();
4399
4400 /*
4401 * The client could unload the sound model during the callback,
4402 * which would join this thread and wait for this thread exit
4403 * as part of st_session_deinit() with st_session_lock held. By
4404 * this time, the state is also moved to idle. To avoid
4405 * deadlock, upon return from client callback, try acquiring
4406 * lock only if not in idle state, else exit right away.
4407 */
4408 do {
4409 lock_status = pthread_mutex_trylock(&st_ses->lock);
4410 } while (lock_status && (st_ses->current_state !=
4411 idle_state_fn));
4412
4413 if (st_ses->current_state == idle_state_fn) {
4414 ALOGV("%s:[%d] client unloaded after callback"
4415 ", lock status %d", __func__, st_ses->sm_handle,
4416 lock_status);
4417 if (!lock_status)
4418 pthread_mutex_unlock(&st_ses->lock);
4419 goto exit;
4420 }
4421 /*
4422 * If client has not requested capture data,
4423 * stop hw session buffering here to resume next
4424 * detection
4425 */
4426 if (!capture_requested)
4427 st_ses->hw_ses_current->fptrs->stop_buffering(
4428 st_ses->hw_ses_current);
4429 } else {
4430 ATRACE_ASYNC_END("sthal: detection reject",
4431 st_ses->sm_handle);
Quinn Male2bfe13b2020-08-27 16:53:51 -07004432 stc_ses->ss_rej_count++;
4433 ALOGD("%s: Second stage detection REJECT, count = %d, "
4434 "restarting st_session", __func__, stc_ses->ss_rej_count);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004435 st_ses->hw_ses_current->fptrs->stop_buffering(
4436 st_ses->hw_ses_current);
4437 start_second_stage_for_client(stc_ses);
4438 st_session_ev_t ev = {.ev_id = ST_SES_EV_RESTART,
4439 .stc_ses = stc_ses};
4440 DISPATCH_EVENT(st_ses, ev, status);
4441 }
4442 pthread_mutex_unlock(&st_ses->lock);
4443 } else {
4444 ALOGV("%s: There is a second stage session pending, continuing",
4445 __func__);
4446 }
4447 }
4448exit:
4449 pthread_mutex_unlock(&st_ses->ss_detections_lock);
4450 ALOGV("%s: Exit", __func__);
4451 return NULL;
4452}
4453
4454static void init_det_event_aggregator(st_proxy_session_t *st_ses)
4455{
4456 int status = 0;
4457 pthread_condattr_t attr;
4458
4459 ALOGV("%s", __func__);
4460
4461 st_ses->exit_aggregator_loop = false;
4462 pthread_mutex_init(&st_ses->ss_detections_lock, NULL);
4463 pthread_condattr_init(&attr);
4464 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
4465 pthread_cond_init(&st_ses->ss_detections_cond, &attr);
4466 pthread_condattr_destroy(&attr);
4467 status = pthread_create(&st_ses->aggregator_thread, NULL,
4468 aggregator_thread_loop, st_ses);
4469 if (status) {
4470 ALOGE("%s: Error creating aggregator thread. status = %d",
4471 __func__, status);
4472 } else {
4473 st_ses->aggregator_thread_created = true;
4474 }
4475}
4476
4477static void destroy_det_event_aggregator(st_proxy_session_t *st_ses)
4478{
4479 int status = 0;
4480
4481 ALOGV("%s", __func__);
4482
4483 st_ses->exit_aggregator_loop = true;
4484 pthread_mutex_lock(&st_ses->ss_detections_lock);
4485 pthread_cond_signal(&st_ses->ss_detections_cond);
4486 pthread_mutex_unlock(&st_ses->ss_detections_lock);
4487 status = pthread_join(st_ses->aggregator_thread, NULL);
4488 if (status)
4489 ALOGE("%s: Error joining aggregator thread. status = %d",
4490 __func__, status);
4491 pthread_cond_destroy(&st_ses->ss_detections_cond);
4492 pthread_mutex_destroy(&st_ses->ss_detections_lock);
4493 st_ses->aggregator_thread_created = false;
4494}
4495
Quinn Male58749452020-03-26 17:14:56 -07004496static int init_st_hw_config(st_hw_session_t *hw_ses, uint32_t model_id)
4497{
4498 struct st_hw_ses_config *sthw_cfg = NULL;
4499 int status;
4500
Quinn Malea15c5ff2020-06-18 18:05:20 -07004501 sthw_cfg = get_sthw_cfg_for_model_id(hw_ses, model_id);
4502 if (sthw_cfg) {
4503 ALOGD("%s: Already initialized sthw_cfg with m_id[%d]",
4504 __func__, model_id);
4505 return 0;
4506 }
4507
Quinn Male58749452020-03-26 17:14:56 -07004508 sthw_cfg = calloc(1, sizeof(struct st_hw_ses_config));
4509 if (!sthw_cfg) {
4510 ALOGE("%s: Failed to allocate struct st_hw_ses_config, exiting",
4511 __func__);
4512 return -ENOMEM;
4513 }
4514 sthw_cfg->model_id = model_id;
4515
4516 if (hw_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
4517 sthw_cfg->conf_levels = calloc(1, MAX_MULTI_SM_CONF_LEVELS);
4518 if (!sthw_cfg->conf_levels) {
4519 ALOGE("%s: Failed to allocate conf_levels, exiting",
4520 __func__);
4521 status = -ENOMEM;
4522 goto exit;
4523 }
4524 memset(sthw_cfg->conf_levels, MAX_CONF_LEVEL_VALUE,
4525 MAX_MULTI_SM_CONF_LEVELS);
4526 }
4527
4528 list_add_tail(&hw_ses->sthw_cfg_list,
4529 &sthw_cfg->sthw_cfg_list_node);
4530
4531 return 0;
4532
4533exit:
4534 if (sthw_cfg) {
4535 free(sthw_cfg);
4536 sthw_cfg = NULL;
4537 }
4538 return status;
4539}
4540
4541static int deinit_st_hw_config(st_hw_session_t *hw_ses, uint32_t model_id)
4542{
4543 struct st_hw_ses_config *sthw_cfg = NULL;
4544
4545 sthw_cfg = get_sthw_cfg_for_model_id(hw_ses, model_id);
4546 if (!sthw_cfg) {
4547 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
4548 return -EINVAL;
4549 }
4550
4551 if (hw_ses->f_stage_version == ST_MODULE_TYPE_PDK5 &&
4552 sthw_cfg->conf_levels) {
4553 free(sthw_cfg->conf_levels);
4554 sthw_cfg->conf_levels = NULL;
4555 }
4556
4557 list_remove(&sthw_cfg->sthw_cfg_list_node);
4558 free(sthw_cfg);
4559 sthw_cfg = NULL;
4560
4561 return 0;
4562}
4563
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004564/* This function is called for multi-client */
4565static int handle_load_sm(st_proxy_session_t *st_ses, st_session_t *stc_ses)
4566{
4567 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male049e47e2019-10-29 16:35:32 -07004568 st_proxy_session_state_fn_t curr_state = st_ses->current_state;
Quinn Male58749452020-03-26 17:14:56 -07004569 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
4570 struct st_hw_ses_config *sthw_cfg = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004571 int status = 0;
4572
4573 ALOGV("%s:[c%d-%d]", __func__, stc_ses->sm_handle, st_ses->sm_handle);
4574 if (!stc_ses->phrase_sm) {
4575 ALOGE("%s:[c%d] sound model data is not initialzed", __func__,
4576 stc_ses->sm_handle);
4577 return -EINVAL;
4578 }
4579
4580 if (!is_other_client_attached(st_ses, stc_ses)) {
4581 ALOGE("%s:[c%d] Unexpected without multi-clients", __func__,
4582 stc_ses->sm_handle);
4583 return -EINVAL;
4584 }
4585
4586 if (st_ses->current_state == buffering_state_fn)
4587 hw_ses->fptrs->stop_buffering(hw_ses);
4588
4589 if (st_ses->current_state == active_state_fn ||
4590 st_ses->current_state == detected_state_fn ||
4591 st_ses->current_state == buffering_state_fn) {
4592 status = stop_session(st_ses, hw_ses, false);
4593 if (status)
4594 ALOGE("%s:[%d] stop_session failed %d", __func__, st_ses->sm_handle,
4595 status);
Quinn Male80c1e0d2019-10-21 15:16:54 -07004596 STATE_TRANSITION(st_ses, loaded_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004597 }
4598
Quinn Male58749452020-03-26 17:14:56 -07004599 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
4600 status = hw_ses->fptrs->dereg_sm(hw_ses, 0);
4601 if (status) {
4602 ALOGE("%s:[%d] dereg_sm failed %d", __func__,
4603 st_ses->sm_handle, status);
4604 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004605 }
4606 /* Continue updating sound model resulting in merged model */
4607 status = update_sound_model(stc_ses, true);
4608 if (status) {
4609 ALOGE("%s:[c%d] update_sound_model add failed %d", __func__,
4610 stc_ses->sm_handle, status);
4611 goto exit;
4612 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004613
Quinn Male58749452020-03-26 17:14:56 -07004614 p_info = get_sm_info_for_model_id(st_ses, stc_ses->sm_info.model_id);
4615 if (!p_info) {
4616 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
4617 status = -EINVAL;
4618 goto exit_1;
4619 }
4620
4621 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
4622 sthw_cfg = get_sthw_cfg_for_model_id(hw_ses, 0);
4623 if (!sthw_cfg) {
4624 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
4625 status = -EINVAL;
4626 goto exit_1;
4627 }
4628
4629 sthw_cfg->conf_levels = p_info->sm_info.cf_levels;
4630 sthw_cfg->num_conf_levels = p_info->sm_info.cf_levels_size;
4631 /*
4632 * Sound model merge would have changed the order of merge conf levels,
4633 * which need to be re-updated for all current active clients, if any.
4634 */
4635 status = update_merge_conf_levels_payload_with_active_clients(st_ses);
4636 if (status)
4637 goto exit_1;
4638 } else {
4639 status = init_st_hw_config(hw_ses, stc_ses->sm_info.model_id);
4640 if (status)
4641 goto exit_1;
4642 }
4643 hw_ses->sthw_cfg_updated = true;
4644
4645 status = hw_ses->fptrs->reg_sm(hw_ses, p_info->sm_info.sm_data,
4646 p_info->sm_info.sm_size, p_info->sm_info.model_id);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004647 if (status) {
4648 ALOGE("%s:[%d] reg_sm failed %d", __func__,
4649 st_ses->sm_handle, status);
4650 goto exit_1;
4651 }
4652
Quinn Male049e47e2019-10-29 16:35:32 -07004653 if (curr_state == active_state_fn ||
4654 curr_state == detected_state_fn ||
4655 curr_state == buffering_state_fn) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004656
4657 status = start_session(st_ses, hw_ses, false);
4658 if (status)
4659 goto exit_2;
4660 STATE_TRANSITION(st_ses, active_state_fn);
4661 }
4662
4663 return 0;
4664
4665exit_2:
4666 if (!st_ses->stdev->ssr_offline_received)
Quinn Male58749452020-03-26 17:14:56 -07004667 hw_ses->fptrs->dereg_sm(hw_ses, p_info->sm_info.model_id);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004668
4669exit_1:
4670 if (!st_ses->stdev->ssr_offline_received) {
4671 update_sound_model(stc_ses, false);
Quinn Male58749452020-03-26 17:14:56 -07004672 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM)
4673 update_merge_conf_levels_payload_with_active_clients(st_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004674 }
4675
4676exit:
4677 if (st_ses->stdev->ssr_offline_received) {
Quinn Male58749452020-03-26 17:14:56 -07004678 dereg_all_sm(st_ses, hw_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004679 STATE_TRANSITION(st_ses, ssr_state_fn);
4680 status = 0;
4681 }
4682 return status;
4683}
4684
4685/* This function is called for multi-client */
4686static int handle_unload_sm(st_proxy_session_t *st_ses, st_session_t *stc_ses)
4687{
4688 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male049e47e2019-10-29 16:35:32 -07004689 st_proxy_session_state_fn_t curr_state = st_ses->current_state;
Quinn Male58749452020-03-26 17:14:56 -07004690 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
4691 struct st_hw_ses_config *sthw_cfg = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004692 int status = 0;
4693
4694 ALOGV("%s:[c%d-%d]", __func__, stc_ses->sm_handle, st_ses->sm_handle);
4695
4696 if (!is_other_client_attached(st_ses, stc_ses)) {
4697 ALOGE("%s:[c%d] Unexpected without multi-clients", __func__,
4698 stc_ses->sm_handle);
4699 return -EINVAL;
4700 }
4701
4702 if (st_ses->current_state == buffering_state_fn)
4703 hw_ses->fptrs->stop_buffering(hw_ses);
4704
4705 if (st_ses->current_state == active_state_fn ||
4706 st_ses->current_state == detected_state_fn ||
4707 st_ses->current_state == buffering_state_fn) {
4708 status = stop_session(st_ses, hw_ses, false);
4709 if (status)
4710 ALOGE("%s:[%d] stop_session failed %d", __func__,
4711 st_ses->sm_handle, status);
Quinn Male80c1e0d2019-10-21 15:16:54 -07004712 STATE_TRANSITION(st_ses, loaded_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004713 }
4714
Quinn Male58749452020-03-26 17:14:56 -07004715 status = hw_ses->fptrs->dereg_sm(hw_ses, stc_ses->sm_info.model_id);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004716 if (status)
4717 ALOGE("%s:[%d] dereg_sm failed %d", __func__, st_ses->sm_handle, status);
4718
4719 /* Continue deleting this model */
4720 status = update_sound_model(stc_ses, false);
4721 if (status)
4722 ALOGE("%s:[c%d] update_sound_model delete failed %d", __func__,
4723 stc_ses->sm_handle, status);
4724
Quinn Male58749452020-03-26 17:14:56 -07004725 if (st_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
4726 p_info = get_sm_info_for_model_id(st_ses, 0);
4727 if (!p_info) {
4728 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
4729 status = -EINVAL;
4730 goto exit;
4731 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004732
Quinn Male58749452020-03-26 17:14:56 -07004733 sthw_cfg = get_sthw_cfg_for_model_id(hw_ses, 0);
4734 if (!sthw_cfg) {
4735 ALOGE("%s: Unexpected, no matching sthw_cfg", __func__);
4736 status = -EINVAL;
4737 goto exit;
4738 }
4739
4740 sthw_cfg->conf_levels = p_info->sm_info.cf_levels;
4741 sthw_cfg->num_conf_levels = p_info->sm_info.cf_levels_size;
4742 /*
4743 * Sound model merge would have changed the order of merge conf levels,
4744 * which need to be re-updated for all current active clients, if any.
4745 */
4746 update_merge_conf_levels_payload_with_active_clients(st_ses);
4747
4748 /* Load remaining merged sound model */
4749 status = hw_ses->fptrs->reg_sm(hw_ses, p_info->sm_info.sm_data,
4750 p_info->sm_info.sm_size, 0);
4751 if (status) {
4752 ALOGE("%s:[%d] reg_sm failed %d", __func__,
4753 st_ses->sm_handle, status);
4754 goto exit;
4755 }
4756 } else {
4757 status = deinit_st_hw_config(hw_ses, stc_ses->sm_handle);
4758 if (status)
4759 goto exit;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004760 }
Quinn Male58749452020-03-26 17:14:56 -07004761 hw_ses->sthw_cfg_updated = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004762
Quinn Male049e47e2019-10-29 16:35:32 -07004763 if (curr_state == active_state_fn ||
4764 curr_state == detected_state_fn ||
4765 curr_state == buffering_state_fn) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004766
4767 status = start_session(st_ses, hw_ses, false);
4768 if (status)
4769 goto exit;
4770 STATE_TRANSITION(st_ses, active_state_fn);
4771 }
4772 return 0;
4773
4774exit:
4775 if (st_ses->stdev->ssr_offline_received) {
Quinn Male58749452020-03-26 17:14:56 -07004776 if (st_ses->f_stage_version == ST_MODULE_TYPE_PDK5)
4777 dereg_all_sm(st_ses, hw_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004778 STATE_TRANSITION(st_ses, ssr_state_fn);
4779 status = 0;
4780 }
4781 return status;
4782}
4783
4784static int idle_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07004785{
4786 int status = 0;
4787 int ret = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004788 st_session_t *stc_ses = ev->stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07004789 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male58749452020-03-26 17:14:56 -07004790 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
Harshal Ahire89337992020-07-13 02:38:14 +05304791 struct version_arch_payload version_payload;
Quinn Male2e883752019-03-22 11:28:54 -07004792
4793 /* skip parameter check as this is an internal funciton */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004794 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
4795 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07004796
4797 switch (ev->ev_id) {
4798 case ST_SES_EV_LOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004799 if (!stc_ses->phrase_sm) {
Quinn Male2e883752019-03-22 11:28:54 -07004800 ALOGE("%s: sound model data is not initialzed", __func__);
4801 status = -EINVAL;
4802 break;
4803 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004804 status = update_sound_model(stc_ses, true);
4805 if (status) {
4806 ALOGE("%s:[c%d] update sound model add failed %d", __func__,
4807 stc_ses->sm_handle, status);
4808 status = -EINVAL;
4809 break;
4810 }
Quinn Male2e883752019-03-22 11:28:54 -07004811
Quinn Male58749452020-03-26 17:14:56 -07004812 p_info = get_sm_info_for_model_id(st_ses, stc_ses->sm_info.model_id);
4813 if (!p_info) {
4814 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
4815 status = -EINVAL;
4816 break;
4817 }
4818
4819 status = init_st_hw_config(hw_ses, p_info->sm_info.model_id);
4820 if (status) {
4821 ALOGE("%s:[%d] failed to init sthw_cfg, exiting",
4822 __func__, st_ses->sm_handle);
4823 break;
4824 }
4825
Quinn Male2e883752019-03-22 11:28:54 -07004826 /*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004827 * Do retry to handle a corner case that when ADSP SSR ONLINE is
4828 * received, sometimes ADSP is still not ready to receive cmd from HLOS
4829 * and thus fails, so try more times to recover the session from SSR
4830 * state.
Quinn Male2e883752019-03-22 11:28:54 -07004831 */
4832 for (int i = 0; i < REG_SM_RETRY_CNT; i++) {
Quinn Malea15c5ff2020-06-18 18:05:20 -07004833 if (stc_ses->pending_load)
4834 status = ret = reg_all_sm(st_ses, hw_ses);
4835 else
4836 status = ret = hw_ses->fptrs->reg_sm(hw_ses, p_info->sm_info.sm_data,
4837 p_info->sm_info.sm_size, p_info->sm_info.model_id);
4838
Quinn Male2e883752019-03-22 11:28:54 -07004839 if (ret) {
4840 if (st_ses->stdev->ssr_offline_received) {
Quinn Male2e883752019-03-22 11:28:54 -07004841 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07004842 status = 0;
4843 break;
4844 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004845 ALOGE("%s:[%d] failed to reg sm, err %d, retry cnt %d",
4846 __func__, st_ses->sm_handle, status, i);
Quinn Male2e883752019-03-22 11:28:54 -07004847 usleep(REG_SM_WAIT_TIME_MS * 1000);
4848 }
4849 } else {
4850 break;
4851 }
4852 }
Quinn Male58749452020-03-26 17:14:56 -07004853
Quinn Male2e883752019-03-22 11:28:54 -07004854 if (ret)
4855 break;
4856
Quinn Male2e883752019-03-22 11:28:54 -07004857 STATE_TRANSITION(st_ses, loaded_state_fn);
4858 break;
4859
4860 case ST_SES_EV_SET_EXEC_MODE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004861 stc_ses->exec_mode = ev->payload.exec_mode;
4862 if (ev->payload.exec_mode == st_ses->exec_mode)
4863 break;
4864
Quinn Male2e883752019-03-22 11:28:54 -07004865 st_ses->exec_mode = ev->payload.exec_mode;
4866 if (ST_EXEC_MODE_CPE == st_ses->exec_mode)
4867 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
4868 else if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
4869 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
4870 /* remain in current state */
4871 break;
4872
4873 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004874 stc_ses->paused = true;
Quinn Male2e883752019-03-22 11:28:54 -07004875 break;
4876
4877 case ST_SES_EV_RESUME:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004878 stc_ses->paused = false;
Quinn Male2e883752019-03-22 11:28:54 -07004879 break;
4880
4881 case ST_SES_EV_SSR_OFFLINE:
4882 STATE_TRANSITION(st_ses, ssr_state_fn);
4883 break;
4884
4885 case ST_SES_EV_SEND_CHMIX_COEFF:
4886 status = -EIO;
4887 break;
4888
4889 case ST_SES_EV_GET_PARAM_DATA:
4890 status = -EIO;
4891 break;
4892
4893 case ST_SES_EV_REQUEST_DET:
4894 ALOGE("%s:[%d] Event not supported in this state",
4895 __func__, st_ses->sm_handle);
4896 status = -EINVAL;
4897 break;
Harshal Ahire89337992020-07-13 02:38:14 +05304898 case ST_SES_EV_GET_MODULE_VERSION:
4899 /* Open Dummy LSM session for google hotword during bootup */
Quinn Male2e883752019-03-22 11:28:54 -07004900
Harshal Ahire89337992020-07-13 02:38:14 +05304901 status = hw_ses->fptrs->open_session(hw_ses);
4902 if (status) {
4903 ALOGE("%s: failed to start lsm session with error %d", __func__,
4904 status);
4905 break;
4906 }
4907
4908 status = hw_ses->fptrs->get_module_version(hw_ses, &version_payload,
4909 sizeof(struct version_arch_payload));
4910
4911 if (status) {
4912 ALOGE("%s: failed to get module version %d", __func__,
4913 status);
4914 hw_ses->fptrs->close_session(hw_ses);
4915 break;
4916 }
4917 hw_ses->fptrs->close_session(hw_ses);
4918 snprintf(ev->payload.module_version, SOUND_TRIGGER_MAX_STRING_LEN, "%d, %s",
4919 version_payload.version, version_payload.arch);
4920
4921 break;
Quinn Male2e883752019-03-22 11:28:54 -07004922 default:
4923 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
4924 break;
4925 };
4926
4927 return status;
4928}
4929
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004930static int loaded_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07004931{
4932 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004933 st_session_t *stc_ses = ev->stc_ses;
4934 struct listnode *node = NULL;
4935 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07004936 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
4937 st_hw_session_t *new_hw_ses = NULL;
4938 st_exec_mode_t new_exec_mode = 0;
Quinn Male58749452020-03-26 17:14:56 -07004939 struct st_proxy_ses_sm_info_wrapper *p_info = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07004940
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004941 /* skip parameter check as this is an internal function */
4942 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
4943 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07004944
4945 switch (ev->ev_id) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004946 case ST_SES_EV_LOAD_SM:
4947 /* Valid only in multi-client session usecase */
4948 status = handle_load_sm(st_ses, stc_ses);
Quinn Male2e883752019-03-22 11:28:54 -07004949 break;
4950
4951 case ST_SES_EV_UNLOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004952 if (is_other_client_attached(st_ses, stc_ses)) {
4953 status = handle_unload_sm(st_ses, stc_ses);
4954 break;
Quinn Male2e883752019-03-22 11:28:54 -07004955 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004956
Quinn Male58749452020-03-26 17:14:56 -07004957 status = hw_ses->fptrs->dereg_sm(hw_ses, stc_ses->sm_info.model_id);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004958 if (status)
4959 ALOGE("%s:[%d] dereg_sm failed %d", __func__,
4960 st_ses->sm_handle, status);
4961
4962 status = update_sound_model(stc_ses, false);
4963 if (status)
4964 ALOGE("%s:[c%d] update_sound_model failed %d", __func__,
4965 stc_ses->sm_handle, status);
4966
Quinn Male58749452020-03-26 17:14:56 -07004967 status = deinit_st_hw_config(hw_ses, stc_ses->sm_info.model_id);
4968 if (status)
4969 ALOGE("%s:[c%d] failed to deinit sthw_cfg",
4970 __func__, stc_ses->sm_handle);
4971
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004972 /* since this is a teardown scenario dont fail here */
4973 status = 0;
Quinn Male2e883752019-03-22 11:28:54 -07004974 STATE_TRANSITION(st_ses, idle_state_fn);
4975 break;
4976
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004977 case ST_SES_EV_RESUME:
4978 stc_ses->paused = false;
Quinn Male60ca2022019-08-21 17:10:25 -07004979 if (!is_any_client_in_state(st_ses, ST_STATE_ACTIVE)) {
4980 /*
4981 * When a transition is needed due to lpi mode or barge-in mode,
4982 * call dereg_sm and reg_sm to select the updated lsm_usecase.
4983 */
4984 if (hw_ses->lpi_enable != hw_ses->stdev->lpi_enable ||
4985 (hw_ses->barge_in_mode != hw_ses->stdev->barge_in_mode &&
4986 !hw_ses->stdev->support_dynamic_ec_update)) {
4987
4988 hw_ses->lpi_enable = hw_ses->stdev->lpi_enable;
4989 hw_ses->barge_in_mode = hw_ses->stdev->barge_in_mode;
4990
Quinn Male58749452020-03-26 17:14:56 -07004991 status = dereg_all_sm(st_ses, hw_ses);
Quinn Male60ca2022019-08-21 17:10:25 -07004992 if (status) {
4993 ALOGE("%s:[%d] failed to dereg_sm err %d", __func__,
4994 st_ses->sm_handle, status);
4995 break;
4996 }
4997
Quinn Male58749452020-03-26 17:14:56 -07004998 status = reg_all_sm(st_ses, hw_ses);
Quinn Male60ca2022019-08-21 17:10:25 -07004999 if (status) {
5000 ALOGE("%s:[%d] failed to reg_sm err %d", __func__,
5001 st_ses->sm_handle, status);
Quinn Male58749452020-03-26 17:14:56 -07005002 dereg_all_sm(st_ses, hw_ses);
Quinn Male60ca2022019-08-21 17:10:25 -07005003 STATE_TRANSITION(st_ses, idle_state_fn);
5004 }
5005 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005006 break;
Quinn Male60ca2022019-08-21 17:10:25 -07005007 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005008 /* Fall through */
5009 case ST_SES_EV_START:
5010 case ST_SES_EV_RESTART:
5011 if (ev->ev_id == ST_SES_EV_RESTART)
5012 update_hw_config_on_restart(st_ses, stc_ses);
5013
5014 /*
5015 * During Resume, the first active client will start the hw sesison.
5016 * During Start, check for any paused sessions to delay actual start
5017 * to Resume.
5018 */
5019 if ((ev->ev_id != ST_SES_EV_RESUME) && is_any_client_paused(st_ses))
5020 break;
5021
5022 status = start_session(st_ses, hw_ses, false);
5023 if (status) {
5024 if (st_ses->stdev->ssr_offline_received) {
Quinn Male58749452020-03-26 17:14:56 -07005025 dereg_all_sm(st_ses, hw_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005026 STATE_TRANSITION(st_ses, ssr_state_fn);
5027 status = 0;
5028 } else {
5029 ALOGE("%s:[%d] failed to start session, err %d", __func__,
5030 st_ses->sm_handle, status);
5031 }
5032 break;
5033 }
5034 STATE_TRANSITION(st_ses, active_state_fn);
5035 break;
5036
5037 case ST_SES_EV_STOP:
5038 /*
5039 * Valid in multi-client case.
5040 * Reconfig based off other active clients, if any, so that RESUME
5041 * can apply this reconfig.
5042 */
5043 update_hw_config_on_stop(st_ses, stc_ses);
5044 break;
5045
Quinn Male2e883752019-03-22 11:28:54 -07005046 case ST_SES_EV_SSR_OFFLINE:
Quinn Male2e883752019-03-22 11:28:54 -07005047 /* exec mode can be none if ssr occurs during a transition */
5048 if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
Quinn Male58749452020-03-26 17:14:56 -07005049 dereg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005050 STATE_TRANSITION(st_ses, ssr_state_fn);
5051 break;
5052
5053 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005054 stc_ses->paused = true;
Quinn Male2e883752019-03-22 11:28:54 -07005055 break;
5056
5057 case ST_SES_EV_SET_EXEC_MODE:
5058 new_exec_mode = ev->payload.exec_mode;
5059
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005060 if (new_exec_mode == st_ses->exec_mode) {
5061 stc_ses->exec_mode = st_ses->exec_mode;
5062 break;
Quinn Male2e883752019-03-22 11:28:54 -07005063 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005064
5065 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
5066 st_ses->exec_mode = ST_EXEC_MODE_NONE;
5067 list_for_each(node, &st_ses->clients_list) {
5068 c_ses = node_to_item(node, st_session_t, hw_list_node);
5069 c_ses->exec_mode = ST_EXEC_MODE_NONE;
5070 }
5071 /* unload sm for current hw session */
Quinn Male58749452020-03-26 17:14:56 -07005072 status = hw_ses->fptrs->dereg_sm(hw_ses, 0);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005073 if (status) {
5074 ALOGE("%s:[%d] dereg_sm failed with err %d", __func__,
5075 st_ses->sm_handle, status);
5076 break;
5077 }
5078 }
5079
5080 if (new_exec_mode == ST_EXEC_MODE_NONE)
5081 break;
5082
5083 /* load sm to new hw_ses */
5084 if (ST_EXEC_MODE_CPE == new_exec_mode) {
5085 new_hw_ses = st_ses->hw_ses_cpe;
5086 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
5087 new_hw_ses = st_ses->hw_ses_adsp;
5088 } else {
5089 ALOGE("%s: unknown execution mode %d", __func__,
5090 new_exec_mode);
5091 status = -EINVAL;
5092 break;
5093 }
5094
Quinn Male58749452020-03-26 17:14:56 -07005095 p_info = get_sm_info_for_model_id(st_ses, 0);
5096 if (!p_info) {
5097 ALOGE("%s: Unexpected, no matching sm_info" , __func__);
5098 status = -EINVAL;
5099 break;
5100 }
5101
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005102 status = new_hw_ses->fptrs->reg_sm(new_hw_ses,
Quinn Male58749452020-03-26 17:14:56 -07005103 p_info->sm_info.sm_data, p_info->sm_info.sm_size, 0);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005104 if (status) {
5105 ALOGE("%s:[%d] reg_sm failed with err %d", __func__,
5106 st_ses->sm_handle, status);
5107 break;
5108 }
5109 /* switch hw sessions only if successful*/
5110 list_for_each(node, &st_ses->clients_list) {
5111 c_ses = node_to_item(node, st_session_t, hw_list_node);
5112 c_ses->exec_mode = new_exec_mode;
5113 if (c_ses->state == ST_STATE_ACTIVE) {
5114 dereg_hal_event_session(c_ses);
5115 reg_hal_event_session(c_ses, new_hw_ses);
5116 }
5117 }
5118 st_ses->exec_mode = new_exec_mode;
5119 st_ses->hw_ses_current = new_hw_ses;
5120 /* remain in current state */
Quinn Male2e883752019-03-22 11:28:54 -07005121 break;
5122
5123 case ST_SES_EV_SET_DEVICE:
5124 /*
5125 * This event handling is needed for certain graphs which
5126 * have multiple buffering modules with a single voice wakeup
5127 * module in each usecase.
5128 */
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005129 if (!ev->payload.enable) {
Quinn Male2e883752019-03-22 11:28:54 -07005130 status = hw_ses->fptrs->disable_device(hw_ses, false);
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005131 } else {
Quinn Male2e883752019-03-22 11:28:54 -07005132 status = hw_ses->fptrs->enable_device(hw_ses, false);
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005133 /*
5134 * Device switch might happen during active buffering.
5135 * If any client is active, start hw session.
5136 */
5137 if (is_any_client_in_state(st_ses, ST_STATE_ACTIVE)) {
5138 st_session_ev_t start_ev = {.ev_id = ST_SES_EV_START,
5139 .stc_ses = stc_ses};
5140 DISPATCH_EVENT(st_ses, start_ev, status);
5141 }
5142 }
Quinn Male2e883752019-03-22 11:28:54 -07005143
5144 break;
5145
5146 case ST_SES_EV_READ_PCM:
5147 /*
5148 * set status to failure this will tell AHAL to
5149 * provide zero buffers to client
5150 */
5151 status = -EIO;
5152 break;
5153
5154 case ST_SES_EV_SEND_CHMIX_COEFF:
5155 status = -EIO;
5156 break;
5157
5158 case ST_SES_EV_GET_PARAM_DATA:
5159 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005160 ev->payload.getparam.param, ev->payload.getparam.payload,
5161 ev->payload.getparam.payload_size,
5162 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07005163 break;
5164
5165 case ST_SES_EV_REQUEST_DET:
5166 ALOGE("%s:[%d] Event not supported in this state",
5167 __func__, st_ses->sm_handle);
5168 status = -EINVAL;
5169 break;
5170
5171 default:
5172 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
5173 break;
Quinn Male2e883752019-03-22 11:28:54 -07005174 };
5175
5176 return status;
Quinn Male2e883752019-03-22 11:28:54 -07005177}
5178
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005179static int active_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07005180{
5181 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005182 st_session_t *stc_ses = ev->stc_ses;
5183 struct listnode *node = NULL;
5184 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07005185 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male2e883752019-03-22 11:28:54 -07005186 st_hw_session_t *new_hw_ses = NULL;
5187 st_exec_mode_t new_exec_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005188 st_arm_second_stage_t *st_sec_stage = NULL;
5189 struct sound_trigger_recognition_event *event = NULL;
5190 recognition_callback_t callback = NULL;
5191 void *cookie = NULL;
5192 bool lab_enabled = false, enable_second_stage = false, active = false;
Quinn Male2e883752019-03-22 11:28:54 -07005193
5194 /* skip parameter check as this is an internal funciton */
5195 ALOGD("%s:[%d] handle event id %d", __func__, st_ses->sm_handle, ev->ev_id);
5196
5197 switch (ev->ev_id) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005198 case ST_SES_EV_LOAD_SM:
5199 /* Valid in multi-client usecase */
5200 status = handle_load_sm(st_ses, stc_ses);
5201 break;
5202
5203 case ST_SES_EV_UNLOAD_SM:
5204 /* Valid in multi-client usecase */
5205 status = handle_unload_sm(st_ses, stc_ses);
5206 break;
5207
5208 case ST_SES_EV_RESTART:
5209 /* Valid in multi-client usecase */
5210 update_hw_config_on_restart(st_ses, stc_ses);
5211 /* Fall through */
5212 case ST_SES_EV_START:
5213 /* Valid in multi-client usecase */
5214 status = stop_session(st_ses, hw_ses, false);
5215 if (!status) {
5216 status = start_session(st_ses, hw_ses, false);
5217 if (status)
5218 ALOGE("%s:[%d] start_session failed %d", __func__,
5219 st_ses->sm_handle, status);
5220 } else {
5221 ALOGE("%s:[%d] stop_session failed %d", __func__,
5222 st_ses->sm_handle, status);
5223 }
5224 if (status & st_ses->stdev->ssr_offline_received) {
Quinn Male58749452020-03-26 17:14:56 -07005225 dereg_all_sm(st_ses, hw_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005226 STATE_TRANSITION(st_ses, ssr_state_fn);
5227 status = 0;
5228 }
5229 break;
5230
Quinn Male2e883752019-03-22 11:28:54 -07005231 case ST_SES_EV_SET_EXEC_MODE:
5232 new_exec_mode = ev->payload.exec_mode;
5233
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005234 if (new_exec_mode == st_ses->exec_mode) {
5235 stc_ses->exec_mode = st_ses->exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07005236 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005237 }
Quinn Male2e883752019-03-22 11:28:54 -07005238
5239 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
5240 ALOGV("%s: disable current session", __func__);
5241 st_ses->exec_mode = ST_EXEC_MODE_NONE;
5242 status = stop_session(st_ses, hw_ses, true);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005243 list_for_each(node, &st_ses->clients_list) {
5244 c_ses = node_to_item(node, st_session_t, hw_list_node);
5245 c_ses->exec_mode = ST_EXEC_MODE_NONE;
5246 }
Quinn Male2e883752019-03-22 11:28:54 -07005247 if (status)
5248 break;
5249 }
5250
5251 if (new_exec_mode == ST_EXEC_MODE_NONE)
5252 break;
5253
5254 if (ST_EXEC_MODE_CPE == new_exec_mode) {
5255 new_hw_ses = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07005256 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
5257 new_hw_ses = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07005258 } else {
5259 ALOGE("%s: unknown execution mode %d", __func__,
5260 new_exec_mode);
5261 status = -EINVAL;
5262 break;
5263 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005264 /*
5265 * hw session changed to/from WDSP/ADSP, hence update the
5266 * related config.
5267 * Not applicable for LPI<->non-LPI transtions as hw session
5268 * doesn't change.
5269 */
5270 status = update_hw_config_on_start(stc_ses, new_hw_ses);
5271 if (status) {
5272 ALOGE("%s: Update_hw_config_on_start failed %d",
5273 __func__, status);
5274 break;
5275 }
Quinn Male2e883752019-03-22 11:28:54 -07005276
5277 ALOGV("%s: enable current session", __func__);
5278 status = start_session(st_ses, new_hw_ses, true);
5279 if (status)
5280 break;
5281
5282 /* set new exec mode and current session */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005283 list_for_each(node, &st_ses->clients_list) {
5284 c_ses = node_to_item(node, st_session_t, hw_list_node);
5285 c_ses->exec_mode = new_exec_mode;
5286 if (c_ses->state == ST_STATE_ACTIVE) {
5287 dereg_hal_event_session(c_ses);
5288 reg_hal_event_session(c_ses, new_hw_ses);
5289 }
5290 }
Quinn Male2e883752019-03-22 11:28:54 -07005291 st_ses->exec_mode = new_exec_mode;
5292 st_ses->hw_ses_current = new_hw_ses;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005293
Quinn Male2e883752019-03-22 11:28:54 -07005294 ALOGV("%s: end transition", __func__);
5295 break;
5296
5297 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005298 /*
5299 * For multi-client, the first active pausing client stops the hw
5300 * session and moves to loaded state.
5301 */
5302 stc_ses->paused = true;
5303 if (stc_ses->state != ST_STATE_ACTIVE)
5304 break;
5305
Quinn Male2e883752019-03-22 11:28:54 -07005306 status = stop_session(st_ses, hw_ses, false);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005307
Quinn Male2e883752019-03-22 11:28:54 -07005308 if (status) {
5309 if (st_ses->stdev->ssr_offline_received) {
5310 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male58749452020-03-26 17:14:56 -07005311 dereg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005312 status = 0;
5313 } else {
5314 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
5315 st_ses->sm_handle, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005316 /* Move anyway to loaded state */
5317 STATE_TRANSITION(st_ses, loaded_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07005318 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005319 break;
Quinn Male2e883752019-03-22 11:28:54 -07005320 }
Quinn Male2e883752019-03-22 11:28:54 -07005321 STATE_TRANSITION(st_ses, loaded_state_fn);
5322 break;
5323
Zhou Song5d413d72019-11-13 17:47:24 +08005324 case ST_SES_EV_RESUME:
5325 if (stc_ses->paused == true)
5326 stc_ses->paused = false;
5327 break;
5328
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005329 case ST_SES_EV_STOP:
5330 status = stop_session(st_ses, hw_ses, false);
5331 if (status)
5332 ALOGE("%s:[%d] start_session failed %d", __func__,
5333 st_ses->sm_handle, status);
Quinn Male2e883752019-03-22 11:28:54 -07005334
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005335 /* Continue to reconfig based off other active clients, if any */
5336 active = update_hw_config_on_stop(st_ses, stc_ses);
5337
5338 if (!status) {
5339 if (active) {
5340 ALOGD("%s: client c%d stopped, start %d due to reconfig",
5341 __func__, stc_ses->sm_handle, st_ses->sm_handle);
5342 status = start_session(st_ses, hw_ses, false);
5343 if (status)
5344 ALOGE("%s:[%d] start_session failed %d", __func__,
Quinn Male2e883752019-03-22 11:28:54 -07005345 st_ses->sm_handle, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005346 /* Stay in active state */
Quinn Male2e883752019-03-22 11:28:54 -07005347 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005348 STATE_TRANSITION(st_ses, loaded_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07005349 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005350 }
Quinn Male2e883752019-03-22 11:28:54 -07005351
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005352 if (status) {
5353 if (st_ses->stdev->ssr_offline_received) {
Quinn Male58749452020-03-26 17:14:56 -07005354 dereg_all_sm(st_ses, hw_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005355 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07005356 status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005357 } else {
5358 STATE_TRANSITION(st_ses, loaded_state_fn);
5359 }
5360 }
5361
5362 break;
5363
5364 case ST_SES_EV_DETECTED:
Quinn Maled0814de2019-05-29 17:33:22 -07005365
5366 st_ses->detection_event_time = get_current_time_ns();
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005367 /*
5368 * Find which client is this detection for.
5369 * Note that only one keyword detection can happen at a time.
5370 */
5371 stc_ses = get_detected_client(st_ses,
5372 ev->payload.detected.detect_payload,
5373 ev->payload.detected.payload_size);
5374
5375 if (!stc_ses) {
5376 ALOGW("%s:[%d] Couldn't find a matching client for detection",
5377 __func__, st_ses->sm_handle);
5378 /*
5379 * Though we set higest conf level 100 for inactive client in merged
5380 * sound model, it may be possible it still detects. In case the lab
5381 * is enabled due to other active client, stop hw buffering.
5382 */
5383 if (st_ses->lab_enabled)
5384 hw_ses->fptrs->stop_buffering(hw_ses);
Quinn Male48490df2020-03-25 10:25:42 -07005385 pthread_mutex_unlock(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005386 break;
5387 }
Quinn Male2bfe13b2020-08-27 16:53:51 -07005388 stc_ses->fs_det_count++;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005389 st_ses->det_stc_ses = stc_ses;
5390 st_ses->hw_ses_current->enable_second_stage = false; /* Initialize */
Venkatesh Mangalappalib4243f42019-08-19 15:25:39 -07005391 stc_ses->detection_sent = false;
Quinn Male58749452020-03-26 17:14:56 -07005392 hw_ses->detected_preroll = stc_ses->preroll_duration;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005393
5394 if (list_empty(&stc_ses->second_stage_list) ||
5395 st_ses->detection_requested) {
5396 st_ses->detection_requested = false;
5397 status = process_detection_event(st_ses,
5398 ev->payload.detected.timestamp,
5399 ev->payload.detected.detect_status,
5400 ev->payload.detected.detect_payload,
5401 ev->payload.detected.payload_size,
5402 &event);
5403 if (status || !event) {
5404 ALOGE("%s:[%d] process_detection_event failed err %d", __func__,
5405 st_ses->sm_handle, status);
5406 /*
5407 * Stop buffering if this is not a successful detection and
5408 * LAB is triggered in hw automatically
5409 */
5410 hw_ses->fptrs->stop_buffering(hw_ses);
5411 if (event)
5412 free(event);
Quinn Male48490df2020-03-25 10:25:42 -07005413 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07005414 break;
5415 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005416 } else {
5417 ALOGV("%s:[c%d] second stage enabled, list_empty %d,"
5418 "det_requested %d", __func__, stc_ses->sm_handle,
5419 list_empty(&stc_ses->second_stage_list),
5420 st_ses->detection_requested);
Quinn Male2e883752019-03-22 11:28:54 -07005421
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005422 enable_second_stage = true;
Quinn Male2e883752019-03-22 11:28:54 -07005423 /*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005424 * Before first stage starts buffering, update the second stage info
5425 * to first stage layer for further communication between first and
5426 * second stage layers.
Quinn Male2e883752019-03-22 11:28:54 -07005427 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005428 st_ses->hw_ses_current->enable_second_stage = true;
5429 st_ses->hw_ses_current->second_stage_list =
5430 &(stc_ses->second_stage_list);
Quinn Male2e883752019-03-22 11:28:54 -07005431
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005432 list_for_each(node, &stc_ses->second_stage_list) {
5433 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
5434 list_node);
5435 st_sec_stage->ss_session->st_ses = st_ses;
5436 }
5437 get_first_stage_detection_params(st_ses,
5438 ev->payload.detected.detect_payload,
5439 ev->payload.detected.payload_size);
5440 memcpy(st_ses->det_session_ev, ev, sizeof(st_session_ev_t));
5441 }
5442 /*
5443 * change to new state before invoking user callback, this will
5444 * ensure that if user calls start_recognition immediately from the
5445 * callback it will be handled by one of the two states below
5446 */
5447 if (!status && st_ses->lab_enabled) {
5448 if (stc_ses->rc_config->capture_requested ||
5449 !list_empty(&stc_ses->second_stage_list)) {
Quinn Male2bfe13b2020-08-27 16:53:51 -07005450 if (st_ses->stdev->enable_debug_dumps &&
5451 stc_ses->rc_config->capture_requested) {
Quinn Maleaba13db2019-07-11 15:52:14 -07005452 ST_DBG_FILE_OPEN_WR(st_ses->lab_fp, ST_DEBUG_DUMP_LOCATION,
Quinn Male2bfe13b2020-08-27 16:53:51 -07005453 "lab_capture", "bin", file_cnt);
5454 ALOGD("%s: Voice Request stored in: lab_capture_%d.bin",
5455 __func__, file_cnt);
5456 file_cnt++;
Quinn Maleaba13db2019-07-11 15:52:14 -07005457 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005458 STATE_TRANSITION(st_ses, buffering_state_fn);
5459 lab_enabled = true;
5460 } else {
5461 /*
5462 * for merged model case the client detected may not have
5463 * requested the capture nor enabled the second stage, but the
5464 * hw lab could be enabled due to other client requested capture
5465 * or enabled second stage.
5466 */
5467 ALOGV("%s: stop buffering as c%d doesn't need", __func__,
5468 stc_ses->sm_handle);
5469 hw_ses->fptrs->stop_buffering(hw_ses);
5470 STATE_TRANSITION(st_ses, detected_state_fn);
5471 lab_enabled = false;
5472 }
5473 } else {
5474 STATE_TRANSITION(st_ses, detected_state_fn);
5475 }
5476
5477 if (!stc_ses->callback) {
5478 ALOGE("%s:[c%d] received detection event but no callback",
5479 __func__, stc_ses->sm_handle);
5480 status = -EINVAL;
5481 if (event)
Quinn Male2e883752019-03-22 11:28:54 -07005482 free(event);
Quinn Male48490df2020-03-25 10:25:42 -07005483 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07005484 break;
5485 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005486 /*
5487 * callback to user, assumption is that client does not
5488 * block in the callback waiting for data otherwise will be a deadlock.
5489 * If second stage is enabled, the detection will be sent later when
5490 * second stage successfully detects.
5491 */
5492 if (!enable_second_stage) {
Venkatesh Mangalappalib4243f42019-08-19 15:25:39 -07005493 stc_ses->detection_sent = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005494 callback = stc_ses->callback;
5495 cookie = stc_ses->cookie;
5496 ALOGD("%s:[c%d] invoking the client callback",
5497 __func__, stc_ses->sm_handle);
5498 ATRACE_ASYNC_END("sthal: detection success",
5499 st_ses->sm_handle);
Quinn Male48490df2020-03-25 10:25:42 -07005500 if (!lab_enabled) {
5501 st_session_ev_t deferred_ev = {
5502 .ev_id = ST_SES_EV_DEFERRED_STOP,
5503 .stc_ses = stc_ses
5504 };
5505 DISPATCH_EVENT(st_ses, deferred_ev, status);
5506 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005507 pthread_mutex_unlock(&st_ses->lock);
5508 ATRACE_BEGIN("sthal: client detection callback");
5509 callback(event, cookie);
5510 ATRACE_END();
Quinn Male48490df2020-03-25 10:25:42 -07005511 if (event)
5512 free(event);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005513 } else {
5514 pthread_mutex_unlock(&st_ses->lock);
5515 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005516
5517 /*
5518 * TODO: Add RECOGNITION_STATUS_GET_STATE_RESPONSE to
5519 * the SoundTrigger API header.
5520 */
5521 if (lab_enabled &&
5522 ((ev->payload.detected.detect_status ==
5523 RECOGNITION_STATUS_SUCCESS) ||
5524 (ev->payload.detected.detect_status == 3))) {
5525 /* Cache lab data to internal buffers (blocking call) */
5526 hw_ses->fptrs->process_lab_capture(hw_ses);
5527 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005528 break;
Quinn Male2e883752019-03-22 11:28:54 -07005529
5530 case ST_SES_EV_SSR_OFFLINE:
Quinn Male2e883752019-03-22 11:28:54 -07005531 /* exec mode can be none if ssr occurs during a transition */
5532 if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005533 stop_session(st_ses, hw_ses, true);
5534 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07005535 break;
5536
5537 case ST_SES_EV_SEND_CHMIX_COEFF:
5538 status = hw_ses->fptrs->send_custom_chmix_coeff(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005539 ev->payload.chmix_coeff_str);
Quinn Male2e883752019-03-22 11:28:54 -07005540 break;
5541
5542 case ST_SES_EV_SET_DEVICE:
5543 if (!ev->payload.enable)
5544 status = hw_ses->fptrs->disable_device(hw_ses, true);
5545 else
5546 status = hw_ses->fptrs->enable_device(hw_ses, true);
5547
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005548 if (status && st_ses->stdev->ssr_offline_received) {
5549 STATE_TRANSITION(st_ses, ssr_state_fn);
5550 status = 0;
5551 }
Quinn Male2e883752019-03-22 11:28:54 -07005552 break;
5553
5554 case ST_SES_EV_READ_PCM:
5555 /*
5556 * buffering could have been stopped internally
5557 * and switched to active state ex: transitions.
5558 * set status to failure this will tell AHAL to
5559 * provide zero buffers to client
5560 */
5561 status = -EIO;
5562 break;
5563
5564 case ST_SES_EV_GET_PARAM_DATA:
5565 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005566 ev->payload.getparam.param, ev->payload.getparam.payload,
5567 ev->payload.getparam.payload_size,
5568 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07005569 break;
5570
5571 case ST_SES_EV_REQUEST_DET:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005572 if (!list_empty(&stc_ses->second_stage_list)) {
5573 ALOGE("%s:[%d] Event not supported with second stage enabled",
5574 __func__, st_ses->sm_handle);
5575 status = -EINVAL;
5576 break;
Quinn Male2e883752019-03-22 11:28:54 -07005577 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005578 status = hw_ses->fptrs->send_detection_request(hw_ses);
5579 if (!status)
5580 st_ses->detection_requested = true;
Quinn Male2e883752019-03-22 11:28:54 -07005581 break;
5582
5583 default:
5584 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
5585 break;
Quinn Male2e883752019-03-22 11:28:54 -07005586 };
5587
5588 return status;
5589}
5590
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005591static int detected_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07005592{
5593 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005594 st_exec_mode_t new_exec_mode = ST_EXEC_MODE_NONE;
5595 st_session_t *stc_ses = ev->stc_ses;
5596 struct listnode *node = NULL;
5597 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07005598 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
5599 st_hw_session_t *new_hw_ses = NULL;
5600
5601 /* skip parameter check as this is an internal funciton */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005602 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5603 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005604
5605 switch (ev->ev_id) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005606 case ST_SES_EV_LOAD_SM:
5607 /* Valid event only in multi-client usecase */
5608 /*
5609 * If a detected client deffered stop event is not handled yet,
5610 * handle here before moving out of detected state
5611 */
5612 if (st_ses->det_stc_ses && !st_ses->det_stc_ses->pending_stop) {
5613 ALOGD("%s:[%d] post deferred stop for c%d", __func__,
5614 st_ses->sm_handle, st_ses->det_stc_ses->sm_handle);
5615 status = hw_session_notifier_enqueue(
5616 st_ses->det_stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP,
5617 ST_SES_DEFERRED_STOP_DELAY_MS);
5618 if (!status)
5619 st_ses->det_stc_ses->pending_stop = true;
5620 }
5621 status = handle_load_sm(st_ses, stc_ses);
5622 break;
5623
5624 case ST_SES_EV_UNLOAD_SM:
5625 /* Valid event only in multi-client usecase */
5626 /*
5627 * If a detected client deffered stop event is not handled yet,
5628 * handle here before moving out of detected state
5629 */
5630 if (st_ses->det_stc_ses && !st_ses->det_stc_ses->pending_stop) {
5631 ALOGD("%s:[%d] post deferred stop for client c%d", __func__,
5632 st_ses->sm_handle, st_ses->det_stc_ses->sm_handle);
5633 status = hw_session_notifier_enqueue(
5634 st_ses->det_stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP,
5635 ST_SES_DEFERRED_STOP_DELAY_MS);
5636 if (!status)
5637 st_ses->det_stc_ses->pending_stop = true;
5638 }
5639 status = handle_unload_sm(st_ses, stc_ses);
5640 break;
5641
Quinn Male2e883752019-03-22 11:28:54 -07005642 case ST_SES_EV_START:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005643 /* For multi-client, other loaded client may start */
Quinn Male2e883752019-03-22 11:28:54 -07005644 STATE_TRANSITION(st_ses, active_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005645 DISPATCH_EVENT(st_ses, *ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07005646 break;
5647
5648 case ST_SES_EV_RESTART:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005649 status = restart_session(st_ses, hw_ses);
5650 if (status && !st_ses->stdev->ssr_offline_received)
5651 ALOGE("%s:[%d] failed to start session, err %d", __func__,
5652 st_ses->sm_handle, status);
5653
5654 if (st_ses->stdev->ssr_offline_received) {
5655 stop_session(st_ses, hw_ses, true);
5656 STATE_TRANSITION(st_ses, ssr_state_fn);
5657 status = 0;
5658 } else {
5659 /* Move anyways to allow client unload */
5660 STATE_TRANSITION(st_ses, active_state_fn);
5661 }
Quinn Male2e883752019-03-22 11:28:54 -07005662 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005663
Quinn Male2e883752019-03-22 11:28:54 -07005664 case ST_SES_EV_PAUSE:
Quinn Male2e883752019-03-22 11:28:54 -07005665 case ST_SES_EV_STOP:
5666 /*
5667 * It is possible that the client can issue stop after detection
5668 * callback. This even can be issued internally as part of
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005669 * deferred stop as well. For multi-client, it could be current
5670 * detected client stop or other client stop.
Quinn Male2e883752019-03-22 11:28:54 -07005671 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005672 STATE_TRANSITION(st_ses, active_state_fn);
5673 DISPATCH_EVENT(st_ses, *ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07005674 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005675
Quinn Male2e883752019-03-22 11:28:54 -07005676 case ST_SES_EV_SSR_OFFLINE:
Quinn Male2e883752019-03-22 11:28:54 -07005677 /*
5678 * Ignore return status during SSR handling
5679 * as the ADSP or CPE might be down so these
5680 * calls would fail. Exec mode can be none if
5681 * ssr occurs during a transition.
5682 */
5683 if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005684 stop_session(st_ses, hw_ses, true);
Quinn Male2e883752019-03-22 11:28:54 -07005685 STATE_TRANSITION(st_ses, ssr_state_fn);
5686 break;
5687
5688 case ST_SES_EV_SET_EXEC_MODE:
5689 new_exec_mode = ev->payload.exec_mode;
5690
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005691 if (new_exec_mode == st_ses->exec_mode) {
5692 stc_ses->exec_mode = st_ses->exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07005693 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005694 }
Quinn Male2e883752019-03-22 11:28:54 -07005695
5696 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
5697 st_ses->exec_mode = ST_EXEC_MODE_NONE;
5698 status = stop_session(st_ses, hw_ses, true);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005699 list_for_each(node, &st_ses->clients_list) {
5700 c_ses = node_to_item(node, st_session_t, hw_list_node);
5701 c_ses->exec_mode = new_exec_mode;
5702 }
Quinn Male2e883752019-03-22 11:28:54 -07005703 if (status)
5704 break;
5705 }
5706
5707 if (new_exec_mode == ST_EXEC_MODE_NONE)
5708 break;
5709
5710 /* switch to new hw session */
5711 if (ST_EXEC_MODE_CPE == new_exec_mode) {
5712 new_hw_ses = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07005713 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
5714 new_hw_ses = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07005715 } else {
5716 ALOGE("%s: unknown execution mode %d", __func__,
5717 new_exec_mode);
5718 status = -EINVAL;
5719 break;
5720 }
5721
5722 /*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005723 * hw session changed to/from WDSP/ADSP, hence update the
5724 * related config.
5725 * Not applicable for LPI<->non-LPI transtions as hw session
5726 * doesn't change.
5727 */
5728 status = update_hw_config_on_start(stc_ses, new_hw_ses);
5729 if (status) {
5730 ALOGE("%s: Update_hw_config_on_start failed %d",
5731 __func__, status);
5732 break;
5733 }
5734 /*
Quinn Male2e883752019-03-22 11:28:54 -07005735 * start new hw session and stay in detected state as
5736 * client restart and stop concurrency scenarios are handled
5737 * in this state
5738 */
5739 status = start_session(st_ses, new_hw_ses, true);
5740 if (status)
5741 break;
5742
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005743 list_for_each(node, &st_ses->clients_list) {
5744 c_ses = node_to_item(node, st_session_t, hw_list_node);
5745 c_ses->exec_mode = new_exec_mode;
5746 if (c_ses->state == ST_STATE_ACTIVE) {
5747 dereg_hal_event_session(c_ses);
5748 reg_hal_event_session(c_ses, new_hw_ses);
5749 }
5750 }
Quinn Male2e883752019-03-22 11:28:54 -07005751 st_ses->exec_mode = new_exec_mode;
5752 st_ses->hw_ses_current = new_hw_ses;
5753 break;
5754
5755 case ST_SES_EV_SEND_CHMIX_COEFF:
5756 status = -EINVAL;
5757 break;
5758
5759 case ST_SES_EV_SET_DEVICE:
5760 /*
5761 * set device is a no-op in detected state due to the following reasons
5762 * A set device is a sequence of disable and enable device commands.
5763 * set device sequence is triggered with dev lock held. Therefore there
5764 * cannot be a concurrency with other client issued events.
5765 * As a deferred stop is posted prior to entering detected state,
5766 * one of the two events are possible
5767 * 1) timer expires and stop is issued : this implies stop_session
5768 * 2) timer is cancelled and start is issued by client: this implies
5769 * new device is set as part of start_session
5770 */
5771 break;
5772
5773 case ST_SES_EV_GET_PARAM_DATA:
5774 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005775 ev->payload.getparam.param, ev->payload.getparam.payload,
5776 ev->payload.getparam.payload_size,
5777 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07005778 break;
5779 case ST_SES_EV_DEFERRED_STOP:
5780 ALOGD("%s:[%d] post deferred stop from detected state", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005781 st_ses->sm_handle);
5782 status = hw_session_notifier_enqueue(stc_ses->sm_handle,
5783 ST_SES_EV_DEFERRED_STOP, ST_SES_DEFERRED_STOP_DELAY_MS);
Quinn Male2e883752019-03-22 11:28:54 -07005784 if (!status)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005785 stc_ses->pending_stop = true;
Quinn Male2e883752019-03-22 11:28:54 -07005786 break;
5787 case ST_SES_EV_REQUEST_DET:
5788 ALOGE("%s:[%d] Event not supported in this state",
5789 __func__, st_ses->sm_handle);
5790 status = -EINVAL;
5791 break;
5792 default:
5793 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
5794 break;
Quinn Male2e883752019-03-22 11:28:54 -07005795 };
Quinn Male2e883752019-03-22 11:28:54 -07005796 return status;
5797}
5798
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005799static int buffering_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07005800{
5801 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005802 st_session_t *stc_ses = ev->stc_ses;
5803 struct listnode *node = NULL;
5804 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07005805 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005806 st_exec_mode_t new_exec_mode = ST_EXEC_MODE_NONE;
Quinn Male2e883752019-03-22 11:28:54 -07005807 st_hw_session_t *new_hw_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07005808
5809 /* skip parameter check as this is an internal function */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005810 ALOGVV("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5811 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005812
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005813 switch (ev->ev_id) {
5814 case ST_SES_EV_LOAD_SM:
5815 /* Valid in multi-client usecase */
5816 ALOGD("%s:[c%d-%d] load sm", __func__, stc_ses->sm_handle,
5817 st_ses->sm_handle);
5818
5819 status = handle_load_sm(st_ses, stc_ses);
5820 break;
5821
5822 case ST_SES_EV_UNLOAD_SM:
5823 ALOGD("%s:[c%d-%d] unload sm", __func__, stc_ses->sm_handle,
5824 st_ses->sm_handle);
5825
5826 status = handle_unload_sm(st_ses, stc_ses);
5827 break;
5828
5829 case ST_SES_EV_READ_PCM:
Quinn Male2e883752019-03-22 11:28:54 -07005830 /* Note: this function may block if there is no PCM data ready*/
5831 hw_ses->fptrs->read_pcm(hw_ses, ev->payload.readpcm.out_buff,
5832 ev->payload.readpcm.out_buff_size);
Quinn Male2bfe13b2020-08-27 16:53:51 -07005833 if (st_ses->stdev->enable_debug_dumps &&
5834 stc_ses->rc_config->capture_requested)
Quinn Maleaba13db2019-07-11 15:52:14 -07005835 ST_DBG_FILE_WRITE(st_ses->lab_fp, ev->payload.readpcm.out_buff,
5836 ev->payload.readpcm.out_buff_size);
Quinn Male2e883752019-03-22 11:28:54 -07005837 break;
5838 case ST_SES_EV_END_BUFFERING:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005839 if (stc_ses == st_ses->det_stc_ses) {
5840 hw_ses->fptrs->stop_buffering(hw_ses);
5841 if (!stc_ses->pending_stop) {
5842 ALOGD("%s:[c%d] post deferred stop on buffering end", __func__,
5843 stc_ses->sm_handle);
5844 status = hw_session_notifier_enqueue(stc_ses->sm_handle,
5845 ST_SES_EV_DEFERRED_STOP, ST_SES_DEFERRED_STOP_DELAY_MS);
5846 if (!status)
5847 stc_ses->pending_stop = true;
5848 } else {
5849 ALOGD("%s:[c%d] skip deferred stop on buffering as already set",
5850 __func__, stc_ses->sm_handle);
5851 }
Quinn Male2e883752019-03-22 11:28:54 -07005852 }
5853 break;
Quinn Male2e883752019-03-22 11:28:54 -07005854
Quinn Male48490df2020-03-25 10:25:42 -07005855 case ST_SES_EV_DEFERRED_STOP:
5856 ALOGD("%s:[%d] post internal deferred stop from buffering state",
5857 __func__, st_ses->sm_handle);
5858 status = hw_session_notifier_enqueue(stc_ses->sm_handle,
5859 ST_SES_EV_DEFERRED_STOP, ST_SES_DEFERRED_STOP_DELAY_MS);
5860 if (!status)
5861 stc_ses->pending_stop = true;
5862 break;
5863
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005864 case ST_SES_EV_STOP:
5865 ALOGD("%s:[c%d-%d] handle event STOP", __func__, stc_ses->sm_handle,
5866 st_ses->sm_handle);
5867 if (stc_ses != st_ses->det_stc_ses) {
5868 ALOGD("%s: c%d buffering, delay c%d stop", __func__,
5869 st_ses->det_stc_ses->sm_handle, stc_ses->sm_handle);
5870 update_hw_config_on_stop(st_ses, stc_ses);
5871 break;
5872 }
5873 /* Fall through */
5874 case ST_SES_EV_PAUSE:
5875 hw_ses->fptrs->stop_buffering(hw_ses);
5876 STATE_TRANSITION(st_ses, active_state_fn);
5877 DISPATCH_EVENT(st_ses, *ev, status);
Quinn Male2bfe13b2020-08-27 16:53:51 -07005878 if (st_ses->stdev->enable_debug_dumps &&
5879 stc_ses->rc_config->capture_requested)
Quinn Maleaba13db2019-07-11 15:52:14 -07005880 ST_DBG_FILE_CLOSE(st_ses->lab_fp);
Quinn Male2e883752019-03-22 11:28:54 -07005881 break;
5882
5883 case ST_SES_EV_SET_DEVICE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005884 ALOGD("%s:[c%d-%d] handle SET_DEVICE", __func__, stc_ses->sm_handle,
5885 st_ses->sm_handle);
Quinn Male2e883752019-03-22 11:28:54 -07005886 /*
5887 * Device switch will not wait for buffering to finish. It will instead
Zhou Song271fdfe2020-04-24 16:06:04 +08005888 * interrupt and stop the buffering and transition to the active state.
Quinn Male2e883752019-03-22 11:28:54 -07005889 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005890 hw_ses->fptrs->stop_buffering(hw_ses);
Zhou Song271fdfe2020-04-24 16:06:04 +08005891 STATE_TRANSITION(st_ses, active_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005892 DISPATCH_EVENT(st_ses, *ev, status);
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005893
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005894 /*
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005895 * set_device event can be dispatched with any one of attached
5896 * multi-clients. For current detected client, the App may or may
5897 * not start next detection, so handle the state accordingly.
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005898 */
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005899 if (st_ses->det_stc_ses->pending_stop) {
5900 ALOGD("%s:[c%d] cancel ST_SES_EV_DEFERRED_STOP", __func__,
5901 st_ses->det_stc_ses->sm_handle);
5902 hw_session_notifier_cancel(stc_ses->sm_handle,
5903 ST_SES_EV_DEFERRED_STOP);
5904 stc_ses->pending_stop = false;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005905 }
Zhou Song271fdfe2020-04-24 16:06:04 +08005906 st_ses->det_stc_ses->state = ST_STATE_ACTIVE;
Quinn Male2e883752019-03-22 11:28:54 -07005907 break;
5908
5909 case ST_SES_EV_START:
5910 case ST_SES_EV_RESTART:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005911 ALOGD("%s:[c%d-%d] handle event START/RESTART", __func__,
5912 stc_ses->sm_handle, st_ses->sm_handle);
5913
5914 if (stc_ses != st_ses->det_stc_ses) {
5915 ALOGD("%s: c%d buffering, delay c%d start", __func__,
5916 st_ses->det_stc_ses->sm_handle, stc_ses->sm_handle);
5917 break;
5918 }
Quinn Male2e883752019-03-22 11:28:54 -07005919 /*
5920 * Client starts detection again.
5921 * This implies a previous deferred stop hasn't completed yet as
5922 * stop would have changed state to loaded.
5923 * For a restart event, issue stop buffering and restart the session
5924 * For a start event, stop buffering then stop and start the session
5925 * so that any new parameters take effect.
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005926 * For multi-client case while the detected is buffering,
5927 * the other client stop/start would have been deferred by updating
5928 * the config, and later when current detected client restarts after
5929 * buffreing is completed, check if hw config is updated due to other
5930 * client and stop->start the hw session to apply updated config.
Quinn Male2e883752019-03-22 11:28:54 -07005931 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005932 hw_ses->fptrs->stop_buffering(hw_ses);
5933 if (hw_ses->sthw_cfg_updated || ev->ev_id == ST_SES_EV_START) {
Quinn Male2e883752019-03-22 11:28:54 -07005934 status = stop_session(st_ses, hw_ses, false);
Zhou Songfe0a2a52019-11-12 15:17:59 +08005935 STATE_TRANSITION(st_ses, loaded_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005936 if (status) {
Quinn Male2e883752019-03-22 11:28:54 -07005937 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005938 st_ses->sm_handle, status);
5939 } else {
5940 status = start_session(st_ses, hw_ses, false);
5941 if (status) {
5942 ALOGE("%s:[%d] failed to start session, err %d", __func__,
5943 st_ses->sm_handle, status);
5944 }
Quinn Male2e883752019-03-22 11:28:54 -07005945 }
Quinn Male2e883752019-03-22 11:28:54 -07005946 } else {
5947 status = restart_session(st_ses, hw_ses);
5948 }
5949
5950 if (status) {
5951 if (st_ses->stdev->ssr_offline_received) {
Quinn Male58749452020-03-26 17:14:56 -07005952 dereg_all_sm(st_ses, hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005953 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07005954 status = 0;
5955 } else {
Quinn Male2e883752019-03-22 11:28:54 -07005956 /* move to active anyways to allow unload sm */
5957 STATE_TRANSITION(st_ses, active_state_fn);
5958 }
5959 } else {
Quinn Male2e883752019-03-22 11:28:54 -07005960 STATE_TRANSITION(st_ses, active_state_fn);
5961 }
5962 break;
5963
5964 case ST_SES_EV_SSR_OFFLINE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005965 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5966 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005967 /*
5968 * Ignore return status during SSR handling
5969 * as the ADSP or CPE might be down so these
5970 * calls would fail. Exec mode can be none if
5971 * ssr occurs during a transition.
5972 */
5973 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005974 hw_ses->fptrs->stop_buffering(hw_ses);
5975 stop_session(st_ses, hw_ses, true);
Quinn Male2e883752019-03-22 11:28:54 -07005976 }
5977 STATE_TRANSITION(st_ses, ssr_state_fn);
5978 break;
5979
5980 case ST_SES_EV_SET_EXEC_MODE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005981 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5982 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005983
5984 new_exec_mode = ev->payload.exec_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005985 if (new_exec_mode == st_ses->exec_mode) {
5986 stc_ses->exec_mode = st_ses->exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07005987 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005988 }
Quinn Male2e883752019-03-22 11:28:54 -07005989
5990 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
5991 st_ses->exec_mode = ST_EXEC_MODE_NONE;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005992 status = hw_ses->fptrs->stop_buffering(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005993 if (status) {
5994 ALOGE("%s:[%d] failed to stop_buffering err %d", __func__,
5995 st_ses->sm_handle, status);
5996 break;
5997 }
Quinn Male2e883752019-03-22 11:28:54 -07005998 status = stop_session(st_ses, hw_ses, true);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005999 list_for_each(node, &st_ses->clients_list) {
6000 c_ses = node_to_item(node, st_session_t, hw_list_node);
6001 c_ses->exec_mode = new_exec_mode;
6002 }
Quinn Male2e883752019-03-22 11:28:54 -07006003 if (status) {
6004 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
6005 st_ses->sm_handle, status);
6006 break;
6007 }
6008 }
6009
6010 if (new_exec_mode == ST_EXEC_MODE_NONE)
6011 break;
6012
6013 /* switch to new hw session */
6014 if (ST_EXEC_MODE_CPE == new_exec_mode) {
6015 new_hw_ses = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07006016 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
6017 new_hw_ses = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07006018 } else {
6019 ALOGE("%s: unknown execution mode %d", __func__,
6020 new_exec_mode);
6021 status = -EINVAL;
6022 break;
6023 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006024 /*
6025 * hw session changed to/from WDSP/ADSP, hence update the
6026 * related config.
6027 * Not applicable for LPI<->non-LPI transtions as hw session
6028 * doesn't change.
6029 */
6030 status = update_hw_config_on_start(stc_ses, new_hw_ses);
6031 if (status) {
6032 ALOGE("%s: Update_hw_config_on_start failed %d",
6033 __func__, status);
6034 break;
6035 }
Quinn Male2e883752019-03-22 11:28:54 -07006036 status = start_session(st_ses, new_hw_ses, true);
6037 if (status) {
6038 ALOGE("%s:[%d] failed to start hw ses, err %d", __func__,
6039 st_ses->sm_handle, status);
6040 break;
6041 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006042 list_for_each(node, &st_ses->clients_list) {
6043 c_ses = node_to_item(node, st_session_t, hw_list_node);
6044 c_ses->exec_mode = new_exec_mode;
6045 if (c_ses->state == ST_STATE_ACTIVE) {
6046 dereg_hal_event_session(c_ses);
6047 reg_hal_event_session(c_ses, new_hw_ses);
6048 }
6049 }
Quinn Male2e883752019-03-22 11:28:54 -07006050 st_ses->exec_mode = new_exec_mode;
6051 st_ses->hw_ses_current = new_hw_ses;
6052 STATE_TRANSITION(st_ses, active_state_fn);
6053 break;
6054
6055 case ST_SES_EV_SEND_CHMIX_COEFF:
6056 status = hw_ses->fptrs->send_custom_chmix_coeff(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006057 ev->payload.chmix_coeff_str);
Quinn Male2e883752019-03-22 11:28:54 -07006058 break;
6059
6060 case ST_SES_EV_GET_PARAM_DATA:
6061 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006062 ev->payload.getparam.param, ev->payload.getparam.payload,
6063 ev->payload.getparam.payload_size,
6064 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07006065 break;
6066
6067 case ST_SES_EV_REQUEST_DET:
6068 ALOGE("%s:[%d] Event %d not supported in this state",
6069 __func__, st_ses->sm_handle, ev->ev_id);
6070 status = -EINVAL;
6071 break;
6072
6073 default:
6074 ALOGD("%s:[%d] unhandled event, id %d", __func__, st_ses->sm_handle,
6075 ev->ev_id);
6076 break;
Quinn Male2e883752019-03-22 11:28:54 -07006077 };
6078
6079 return status;
6080}
6081
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006082static int ssr_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07006083{
6084 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006085 st_session_t *stc_ses = ev->stc_ses;
6086 st_session_ev_t load_ev = {.ev_id = ST_SES_EV_LOAD_SM};
6087 st_session_ev_t start_ev = {.ev_id = ST_SES_EV_START};
6088 st_session_ev_t exec_mode_ev = {.ev_id = ST_SES_EV_SET_EXEC_MODE};
6089 bool active = false;
Quinn Male2e883752019-03-22 11:28:54 -07006090
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006091 /* skip parameter check as this is an internal function */
6092 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
6093 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07006094
6095 switch (ev->ev_id) {
6096 case ST_SES_EV_SSR_ONLINE:
6097 ALOGV("%s:[%d] SSR ONLINE received", __func__, st_ses->sm_handle);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006098 /*
6099 * Load and start all clients at once instead of unload/loading
6100 * due to each subsequent client dispatch. It is expected the
6101 * upper layer calls SSR_ONLINE for all clients.
6102 */
6103 stc_ses->pending_load = true;
6104 if (is_any_client_not_pending_load(st_ses))
6105 break;
6106
Quinn Male2e883752019-03-22 11:28:54 -07006107 STATE_TRANSITION(st_ses, idle_state_fn);
6108
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006109 if ((stc_ses->ssr_transit_exec_mode == ST_EXEC_MODE_CPE) ||
6110 (stc_ses->ssr_transit_exec_mode == ST_EXEC_MODE_ADSP)) {
6111 exec_mode_ev.stc_ses = stc_ses;
6112 exec_mode_ev.payload.exec_mode = stc_ses->ssr_transit_exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07006113 DISPATCH_EVENT(st_ses, exec_mode_ev, status);
Quinn Malea15c5ff2020-06-18 18:05:20 -07006114 if (status) {
6115 reset_clients_pending_load(st_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006116 break;
Quinn Malea15c5ff2020-06-18 18:05:20 -07006117 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006118 stc_ses->ssr_transit_exec_mode = ST_EXEC_MODE_NONE;
Quinn Male2e883752019-03-22 11:28:54 -07006119 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006120 active = is_any_client_in_state(st_ses, ST_STATE_ACTIVE);
6121 if (active || is_any_client_in_state(st_ses, ST_STATE_LOADED)) {
6122 load_ev.stc_ses = stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006123 DISPATCH_EVENT(st_ses, load_ev, status);
Quinn Malea15c5ff2020-06-18 18:05:20 -07006124 if (status) {
6125 reset_clients_pending_load(st_ses);
Quinn Male2e883752019-03-22 11:28:54 -07006126 break;
Quinn Malea15c5ff2020-06-18 18:05:20 -07006127 }
Quinn Male2e883752019-03-22 11:28:54 -07006128 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006129 if (active) {
6130 start_ev.stc_ses = stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006131 DISPATCH_EVENT(st_ses, start_ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07006132 }
6133
Quinn Malea15c5ff2020-06-18 18:05:20 -07006134 reset_clients_pending_load(st_ses);
Quinn Male2e883752019-03-22 11:28:54 -07006135 break;
6136
6137 case ST_SES_EV_LOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006138 if (ST_STATE_IDLE == stc_ses->state) {
6139 status = update_sound_model(stc_ses, true);
6140 if (status) {
6141 ALOGE("%s:[c%d] update sound model add failed %d", __func__,
6142 stc_ses->sm_handle, status);
6143 status = -EINVAL;
6144 break;
6145 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006146 stc_ses->state = ST_STATE_LOADED;
Quinn Male2e883752019-03-22 11:28:54 -07006147 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006148 ALOGE("%s: received unexpected event, client state = %d",
6149 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07006150 }
6151 break;
6152
6153 case ST_SES_EV_UNLOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006154 if (ST_STATE_LOADED == stc_ses->state) {
6155 status = update_sound_model(stc_ses, false);
6156 if (status)
6157 ALOGE("%s:[c%d] update sound_model failed %d", __func__,
6158 stc_ses->sm_handle, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006159 stc_ses->state = ST_STATE_IDLE;
Quinn Male2e883752019-03-22 11:28:54 -07006160 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006161 ALOGE("%s: received unexpected event, client state = %d",
6162 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07006163 }
6164 break;
6165
6166 case ST_SES_EV_START:
6167 case ST_SES_EV_RESTART:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006168 if (ST_STATE_LOADED == stc_ses->state) {
6169 if (ev->ev_id == ST_SES_EV_RESTART)
6170 update_hw_config_on_restart(st_ses, stc_ses);
6171 stc_ses->state = ST_STATE_ACTIVE;
Quinn Male2e883752019-03-22 11:28:54 -07006172 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006173 ALOGE("%s: received unexpected event, client state = %d",
6174 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07006175 }
6176 break;
6177
6178 case ST_SES_EV_STOP:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006179 if (ST_STATE_ACTIVE == stc_ses->state) {
6180 update_hw_config_on_stop(st_ses, stc_ses);
6181 stc_ses->state = ST_STATE_LOADED;
Quinn Male2e883752019-03-22 11:28:54 -07006182 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006183 ALOGE("%s: received unexpected event, client state = %d",
6184 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07006185 }
6186 break;
6187
6188 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006189 stc_ses->paused = true;
Quinn Male2e883752019-03-22 11:28:54 -07006190 break;
6191
6192 case ST_SES_EV_RESUME:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006193 stc_ses->paused = false;
Quinn Male2e883752019-03-22 11:28:54 -07006194 break;
6195
6196 case ST_SES_EV_READ_PCM:
6197 status = -EIO;
6198 break;
6199
6200 case ST_SES_EV_SEND_CHMIX_COEFF:
6201 status = -EIO;
6202 break;
6203
6204 case ST_SES_EV_GET_PARAM_DATA:
6205 status = -EIO;
6206 break;
6207
6208 case ST_SES_EV_SET_EXEC_MODE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006209 stc_ses->exec_mode = ev->payload.exec_mode;
6210 if (ev->payload.exec_mode == st_ses->exec_mode)
6211 break;
6212
Quinn Male2e883752019-03-22 11:28:54 -07006213 st_ses->exec_mode = ev->payload.exec_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006214
Quinn Male2e883752019-03-22 11:28:54 -07006215 if (ST_EXEC_MODE_CPE == st_ses->exec_mode)
6216 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
6217 else if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
6218 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
6219 /* remain in current state */
6220 break;
6221
6222 case ST_SES_EV_REQUEST_DET:
6223 ALOGE("%s:[%d] Event not supported in this state",
6224 __func__, st_ses->sm_handle);
6225 status = -EINVAL;
6226 break;
6227
6228 default:
6229 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
6230 break;
6231 };
6232
6233 return status;
6234}
6235
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006236int st_session_load_sm(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006237{
6238 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006239
6240 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006241 return -EINVAL;
6242
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006243 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6244 st_session_loadsm_payload_t payload = { .phrase_sm = stc_ses->phrase_sm };
Quinn Male2e883752019-03-22 11:28:54 -07006245 st_session_ev_t ev = { .ev_id = ST_SES_EV_LOAD_SM,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006246 .payload.loadsm = payload, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006247
6248 pthread_mutex_lock(&st_ses->lock);
6249 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006250 if (!status) {
Quinn Male12f5c6f2019-11-14 17:34:10 -08006251 prepare_second_stage_for_client(stc_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006252 stc_ses->state = ST_STATE_LOADED;
6253 }
Quinn Male2e883752019-03-22 11:28:54 -07006254 pthread_mutex_unlock(&st_ses->lock);
6255
6256 return status;
6257}
6258
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006259int st_session_unload_sm(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006260{
6261 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006262
6263 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006264 return -EINVAL;
6265
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006266 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6267 st_session_ev_t ev = { .ev_id = ST_SES_EV_UNLOAD_SM, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006268
6269 pthread_mutex_lock(&st_ses->lock);
6270 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006271 stop_second_stage_for_client(stc_ses);
6272 stc_ses->state = ST_STATE_IDLE;
Quinn Male2e883752019-03-22 11:28:54 -07006273 pthread_mutex_unlock(&st_ses->lock);
6274
6275 return status;
6276}
6277
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006278int st_session_start(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006279{
6280 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006281
6282 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006283 return -EINVAL;
6284
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006285 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6286 st_session_ev_t ev = { .ev_id = ST_SES_EV_START, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006287
Quinn Male2e883752019-03-22 11:28:54 -07006288 pthread_mutex_lock(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006289 if (stc_ses->pending_stop) {
6290 ALOGV("%s:[c%d] cancel ST_SES_EV_DEFERRED_STOP", __func__,
6291 stc_ses->sm_handle);
6292 hw_session_notifier_cancel(stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP);
6293 stc_ses->pending_stop = false;
6294 }
6295
Quinn Male2e883752019-03-22 11:28:54 -07006296 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006297 if (!status) {
6298 reg_hal_event_session(stc_ses, st_ses->hw_ses_current);
6299 start_second_stage_for_client(stc_ses);
6300 stc_ses->state = ST_STATE_ACTIVE;
6301 }
Quinn Male2e883752019-03-22 11:28:54 -07006302 pthread_mutex_unlock(&st_ses->lock);
6303 return status;
6304}
6305
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006306int st_session_stop(st_session_t *stc_ses)
6307{
6308 int status = 0;
6309
6310 if (!stc_ses || !stc_ses->hw_proxy_ses)
6311 return -EINVAL;
6312
6313 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6314 st_session_ev_t ev = { .ev_id = ST_SES_EV_STOP, .stc_ses = stc_ses };
6315
6316 pthread_mutex_lock(&st_ses->lock);
6317 DISPATCH_EVENT(st_ses, ev, status);
6318 dereg_hal_event_session(stc_ses);
6319 stc_ses->pending_stop = false;
6320 stc_ses->state = ST_STATE_LOADED;
6321 pthread_mutex_unlock(&st_ses->lock);
6322
6323 return status;
6324}
6325
6326int st_session_restart(st_session_t *stc_ses)
6327{
6328 int status = 0;
6329
6330 if (!stc_ses || !stc_ses->hw_proxy_ses)
6331 return -EINVAL;
6332
6333 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6334 st_session_ev_t ev = { .ev_id = ST_SES_EV_RESTART, .stc_ses = stc_ses };
6335
6336 pthread_mutex_lock(&st_ses->lock);
6337 if (stc_ses->pending_stop) {
6338 ALOGV("%s:[c%d] cancel ST_SES_EV_DEFERRED_STOP", __func__,
6339 stc_ses->sm_handle);
6340 hw_session_notifier_cancel(stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP);
6341 stc_ses->pending_stop = false;
6342 }
6343
6344 DISPATCH_EVENT(st_ses, ev, status);
6345 if (!status) {
6346 start_second_stage_for_client(stc_ses);
6347 stc_ses->state = ST_STATE_ACTIVE;
6348 } else {
6349 dereg_hal_event_session(stc_ses);
6350 stc_ses->state = ST_STATE_LOADED;
6351 }
6352 pthread_mutex_unlock(&st_ses->lock);
6353
6354 return status;
6355}
6356
6357int st_session_ssr_offline(st_session_t *stc_ses,
Quinn Male2e883752019-03-22 11:28:54 -07006358 enum ssr_event_status ssr_type)
6359{
6360 int status = 0;
6361
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006362 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006363 return -EINVAL;
6364
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006365 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006366 st_session_ev_t ev = { .ev_id = ST_SES_EV_SSR_OFFLINE,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006367 .payload.ssr = ssr_type, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006368
6369 pthread_mutex_lock(&st_ses->lock);
6370 /*
6371 * In typical usecases, handle SSR only if it occured on the core we are
6372 * currently using. In cases that have an SSR event during transitions,
6373 * the exec_mode can be NONE. For these cases, handle SSR on the core
6374 * which was in use prior to the transition. For example, if the
6375 * ssr_transit_exec_mode is ADSP, then the core prior to the transition
6376 * is CPE, so we handle the CPE SSR event.
6377 *
6378 * On 8909w BG uses CPE mode for detection. So add BG specific
6379 * conditon check to handle SSR event.
6380 */
6381 if (((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
6382 (CPE_STATUS_OFFLINE == ssr_type)) ||
6383 ((ST_EXEC_MODE_ADSP == st_ses->exec_mode) &&
6384 (SND_CARD_STATUS_OFFLINE == ssr_type)) ||
6385 ((ST_EXEC_MODE_NONE == st_ses->exec_mode) &&
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006386 (((ST_EXEC_MODE_CPE == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07006387 (SND_CARD_STATUS_OFFLINE == ssr_type)) ||
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006388 ((ST_EXEC_MODE_ADSP == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07006389 (CPE_STATUS_OFFLINE == ssr_type)))) ||
6390 ((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
6391 (SND_CARD_STATUS_OFFLINE == ssr_type) &&
6392 (st_ses->stdev->bg_kwd)))
6393 DISPATCH_EVENT(st_ses, ev, status);
6394 pthread_mutex_unlock(&st_ses->lock);
6395
6396 return status;
6397}
6398
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006399int st_session_ssr_online(st_session_t *stc_ses,
Quinn Male2e883752019-03-22 11:28:54 -07006400 enum ssr_event_status ssr_type)
6401{
6402 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006403
6404 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006405 return -EINVAL;
6406
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006407 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006408 st_session_ev_t ev = { .ev_id = ST_SES_EV_SSR_ONLINE,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006409 .payload.ssr = ssr_type, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006410
6411 pthread_mutex_lock(&st_ses->lock);
6412 /*
6413 * In typical usecases, handle SSR only if it occured on the core we are
6414 * currently using. In cases that have an SSR event during transitions,
6415 * the exec_mode can be NONE. For these cases, handle SSR on the core
6416 * which was in use prior to the transition. For example, if the
6417 * ssr_transit_exec_mode is ADSP, then the core prior to the transition
6418 * is CPE, so we handle the CPE SSR event.
6419 *
6420 * On 8909w BG uses CPE mode for detection. So add BG specific
6421 * conditon check to handle SSR event.
6422 */
6423 if (((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
6424 (CPE_STATUS_ONLINE == ssr_type)) ||
6425 ((ST_EXEC_MODE_ADSP == st_ses->exec_mode) &&
6426 (SND_CARD_STATUS_ONLINE == ssr_type)) ||
6427 ((ST_EXEC_MODE_NONE == st_ses->exec_mode) &&
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006428 (((ST_EXEC_MODE_CPE == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07006429 (SND_CARD_STATUS_ONLINE == ssr_type)) ||
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006430 ((ST_EXEC_MODE_ADSP == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07006431 (CPE_STATUS_ONLINE == ssr_type)))) ||
6432 ((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
6433 (SND_CARD_STATUS_ONLINE == ssr_type) &&
6434 (st_ses->stdev->bg_kwd)))
6435 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006436
Quinn Male2e883752019-03-22 11:28:54 -07006437 pthread_mutex_unlock(&st_ses->lock);
6438
6439 return status;
6440}
6441
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006442int st_session_pause(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006443{
6444 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006445
6446 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006447 return -EINVAL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006448
6449 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6450 st_session_ev_t ev = { .ev_id = ST_SES_EV_PAUSE, .stc_ses = stc_ses };
6451
Venkatesh Mangalappali47118dc2019-07-29 11:51:52 -07006452 pthread_mutex_lock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006453 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappali47118dc2019-07-29 11:51:52 -07006454 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006455 return status;
6456}
6457
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006458int st_session_resume(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006459{
6460 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006461
6462 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006463 return -EINVAL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006464
6465 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6466 st_session_ev_t ev = { .ev_id = ST_SES_EV_RESUME, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006467
6468 pthread_mutex_lock(&st_ses->lock);
6469 DISPATCH_EVENT(st_ses, ev, status);
6470 pthread_mutex_unlock(&st_ses->lock);
6471 return status;
6472}
6473
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006474int st_session_disable_device(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006475{
6476 int status = 0;
Zhou Songcd3c8e62019-07-16 13:30:19 +08006477 st_session_event_id_t ev_id = ST_SES_EV_SET_DEVICE;
Quinn Male2e883752019-03-22 11:28:54 -07006478
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006479 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006480 return -EINVAL;
6481
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006482 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Zhou Songcd3c8e62019-07-16 13:30:19 +08006483 pthread_mutex_lock(&st_ses->lock);
6484 if (check_gcs_usecase_switch(stc_ses->hw_proxy_ses))
6485 ev_id = ST_SES_EV_PAUSE;
6486
6487 st_session_ev_t ev = {.ev_id = ev_id,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006488 .payload.enable = false, .stc_ses = stc_ses};
6489
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006490 /*
6491 * Avoid dispatching for each attached multi-client, instead
6492 * defer it until last client
6493 */
6494 stc_ses->pending_set_device = true;
6495 if (is_any_client_not_pending_set_device(st_ses)) {
6496 pthread_mutex_unlock(&st_ses->lock);
6497 return status;
6498 }
6499 reset_clients_pending_set_device(st_ses);
6500
6501 DISPATCH_EVENT(st_ses, ev, status);
6502 pthread_mutex_unlock(&st_ses->lock);
6503 return status;
6504}
6505
6506int st_session_enable_device(st_session_t *stc_ses)
6507{
6508 int status = 0;
Zhou Songcd3c8e62019-07-16 13:30:19 +08006509 st_session_event_id_t ev_id = ST_SES_EV_SET_DEVICE;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006510
6511 if (!stc_ses || !stc_ses->hw_proxy_ses)
6512 return -EINVAL;
6513
6514 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Zhou Songcd3c8e62019-07-16 13:30:19 +08006515 pthread_mutex_lock(&st_ses->lock);
6516 if (check_gcs_usecase_switch(stc_ses->hw_proxy_ses))
6517 ev_id = ST_SES_EV_RESUME;
6518
6519 st_session_ev_t ev = { .ev_id = ev_id,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006520 .payload.enable = true, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07006521
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006522 /*
6523 * Avoid dispatching for each attached multi-client, instead
6524 * defer it until last client
6525 */
6526 stc_ses->pending_set_device = true;
6527 if (is_any_client_not_pending_set_device(st_ses)) {
6528 pthread_mutex_unlock(&st_ses->lock);
6529 return status;
6530 }
6531 reset_clients_pending_set_device(st_ses);
6532
Quinn Male2e883752019-03-22 11:28:54 -07006533 DISPATCH_EVENT(st_ses, ev, status);
6534 pthread_mutex_unlock(&st_ses->lock);
6535 return status;
6536}
6537
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006538bool st_session_is_detected(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006539{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006540 bool ret = false;
Quinn Male2e883752019-03-22 11:28:54 -07006541
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006542 if (!stc_ses || !stc_ses->hw_proxy_ses)
6543 return ret;
Quinn Male2e883752019-03-22 11:28:54 -07006544
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006545 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006546
6547 pthread_mutex_lock(&st_ses->lock);
6548 ret = (st_ses->current_state == detected_state_fn) ? true : false;
6549 pthread_mutex_unlock(&st_ses->lock);
6550
6551 return ret;
6552}
6553
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006554bool st_session_is_active(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006555{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006556 bool ret = false;
6557
6558 if (!stc_ses || !stc_ses->hw_proxy_ses)
6559 return ret;
6560
6561 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006562
6563 pthread_mutex_lock(&st_ses->lock);
6564 ret = (st_ses->current_state == active_state_fn) ? true : false;
6565 pthread_mutex_unlock(&st_ses->lock);
6566
6567 return ret;
6568}
6569
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006570bool st_session_is_buffering(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006571{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006572 bool ret = false;
6573
6574 if (!stc_ses || !stc_ses->hw_proxy_ses)
6575 return ret;
6576
6577 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006578
6579 pthread_mutex_lock(&st_ses->lock);
6580 ret = (st_ses->current_state == buffering_state_fn) ? true : false;
6581 pthread_mutex_unlock(&st_ses->lock);
6582
6583 return ret;
6584}
6585
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006586bool st_session_is_ssr_state(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006587{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006588 bool ret = false;
6589
6590 if (!stc_ses || !stc_ses->hw_proxy_ses)
6591 return ret;
6592
6593 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006594
6595 pthread_mutex_lock(&st_ses->lock);
6596 ret = (st_ses->current_state == ssr_state_fn) ? true : false;
6597 pthread_mutex_unlock(&st_ses->lock);
6598
6599 return ret;
6600}
6601
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006602int st_session_read_pcm(st_session_t *stc_ses, uint8_t *buff,
Quinn Male2e883752019-03-22 11:28:54 -07006603 size_t buff_size, size_t *read_size)
6604{
6605 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006606
6607 if (!stc_ses || !stc_ses->hw_proxy_ses || !buff || buff_size == 0 ||
6608 read_size == 0)
Quinn Male2e883752019-03-22 11:28:54 -07006609 return -EINVAL;
6610
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006611 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6612 st_session_readpcm_payload_t payload = {.out_buff = buff,
6613 .out_buff_size = buff_size, .actual_read_size = read_size};
Quinn Male2e883752019-03-22 11:28:54 -07006614
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006615 st_session_ev_t ev = {.ev_id = ST_SES_EV_READ_PCM,
6616 .payload.readpcm = payload, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006617
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006618 /*
6619 * Do not lock when handling this event, this event
6620 * can go in parallel with other events as multiple
6621 * sessions can buffer in parallel.
6622 */
Quinn Male2e883752019-03-22 11:28:54 -07006623 DISPATCH_EVENT(st_ses, ev, status);
6624 return status;
6625}
6626
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006627int st_session_stop_lab(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006628{
6629 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006630
6631 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006632 return -EINVAL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006633
6634 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6635 st_session_ev_t ev = {.ev_id = ST_SES_EV_END_BUFFERING, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006636
6637 pthread_mutex_lock(&st_ses->lock);
6638 DISPATCH_EVENT(st_ses, ev, status);
6639 pthread_mutex_unlock(&st_ses->lock);
6640 return status;
6641}
6642
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006643int st_session_set_exec_mode(st_session_t *stc_ses, st_exec_mode_t exec)
Quinn Male2e883752019-03-22 11:28:54 -07006644{
6645 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006646
6647 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006648 return -EINVAL;
6649
6650 ALOGV("%s: exec mode %d", __func__, exec);
6651
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006652 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6653 st_session_ev_t ev = {.ev_id = ST_SES_EV_SET_EXEC_MODE,
6654 .payload.exec_mode = exec, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006655
6656 pthread_mutex_lock(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006657 if (st_ses->enable_trans)
6658 DISPATCH_EVENT(st_ses, ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07006659 pthread_mutex_unlock(&st_ses->lock);
6660 return status;
6661}
6662
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006663int st_session_update_recongition_config(st_session_t *stc_ses)
6664{
6665
6666 int status = 0;
6667
6668 if (!stc_ses || !stc_ses->hw_proxy_ses)
6669 return -EINVAL;
6670
6671 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6672
6673 pthread_mutex_lock(&st_ses->lock);
6674 status = update_hw_config_on_start(stc_ses, st_ses->hw_ses_current);
6675 pthread_mutex_unlock(&st_ses->lock);
6676 return status;
6677
6678}
6679
6680int st_session_get_preroll(st_session_t *stc_ses)
6681{
6682 int val = 0;
6683
6684 if (!stc_ses || !stc_ses->hw_proxy_ses)
6685 return 0;
6686
6687 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6688
6689 pthread_mutex_lock(&st_ses->lock);
Quinn Male58749452020-03-26 17:14:56 -07006690 val = st_ses->hw_ses_current->max_preroll;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006691 pthread_mutex_unlock(&st_ses->lock);
6692
6693 return val;
6694}
6695
6696int st_session_send_custom_chmix_coeff(st_session_t *stc_ses, char *str)
Quinn Male2e883752019-03-22 11:28:54 -07006697{
6698 int status = 0;
6699
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006700 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006701 return -EINVAL;
6702
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 st_session_ev_t ev = { .ev_id = ST_SES_EV_SEND_CHMIX_COEFF,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006705 .payload.chmix_coeff_str = str, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006706
6707 pthread_mutex_lock(&st_ses->lock);
6708 if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
6709 DISPATCH_EVENT(st_ses, ev, status);
6710 pthread_mutex_unlock(&st_ses->lock);
6711 return status;
6712}
6713
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006714int st_session_get_config(st_session_t *stc_ses, struct pcm_config *config)
Quinn Male2e883752019-03-22 11:28:54 -07006715{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006716 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006717 return -EINVAL;
6718
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006719 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6720
6721 pthread_mutex_lock(&st_ses->lock);
6722 memcpy(config, &st_ses->hw_ses_current->config, sizeof(struct pcm_config));
6723 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006724
6725 return 0;
6726}
6727
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006728int st_session_get_param_data(st_session_t *stc_ses, const char *param,
6729 void *payload, size_t payload_size, size_t *param_data_size)
Quinn Male2e883752019-03-22 11:28:54 -07006730{
6731 int status = 0;
6732
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006733 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006734 return -EINVAL;
6735
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006736 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006737 st_session_getparam_payload_t getparam_payload = { .param = param,
6738 .payload = payload,
6739 .payload_size = payload_size,
6740 .param_data_size = param_data_size};
6741 st_session_ev_t ev = { .ev_id = ST_SES_EV_GET_PARAM_DATA,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006742 .payload.getparam = getparam_payload, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006743
6744 pthread_mutex_lock(&st_ses->lock);
6745 /* Currently get param data supported for ARM & ADSP mode */
6746 if ((ST_EXEC_MODE_ARM == st_ses->exec_mode) ||
6747 (ST_EXEC_MODE_ADSP == st_ses->exec_mode))
6748 DISPATCH_EVENT(st_ses, ev, status);
6749 pthread_mutex_unlock(&st_ses->lock);
6750
6751 return status;
6752}
6753
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006754int st_session_ss_init(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006755{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006756 int status = 0;
6757 struct listnode *node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07006758 st_arm_second_stage_t *st_sec_stage = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006759 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006760
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006761 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07006762 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
6763 status = st_second_stage_module_init(st_sec_stage,
6764 (void *)st_sec_stage->ss_info->lib_name);
6765 if (status) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006766 ALOGE("%s:[c%d] initializing second stage session failed %d",
6767 __func__, stc_ses->sm_handle, status);
Quinn Male2e883752019-03-22 11:28:54 -07006768 goto ss_cleanup;
6769 }
6770 }
6771
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006772 pthread_mutex_lock(&st_ses->lock);
6773 if (st_ses->aggregator_thread_created) {
6774 pthread_mutex_unlock(&st_ses->lock);
6775 return 0;
6776 }
6777 /*
6778 * Aggregator is not maintatined per client as there is only one
6779 * client keyword detection happens at a time in multi-client scenario.
6780 * Instead use single aggregator thread at proxy level, processing the
6781 * second stage for detected client at run time.
6782 */
6783 init_det_event_aggregator(st_ses);
6784
Quinn Male2e883752019-03-22 11:28:54 -07006785 st_ses->det_session_ev = calloc(1, sizeof(st_session_ev_t));
6786 if (!st_ses->det_session_ev) {
6787 ALOGE("%s: Failed to allocate st_session_ev_t, exiting", __func__);
6788 status = -ENOMEM;
6789 goto ss_cleanup;
6790 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006791 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006792 return 0;
6793
6794ss_cleanup:
6795 destroy_det_event_aggregator(st_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006796 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07006797 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
6798 st_second_stage_module_deinit(st_sec_stage);
6799 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006800 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006801 return status;
6802}
6803
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006804int st_session_ss_deinit(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006805{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006806 struct listnode *node = NULL;
6807 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006808 st_arm_second_stage_t *st_sec_stage = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006809 st_session_t *c_ses = NULL;
6810 bool aggregator_needed = false;
Quinn Male2e883752019-03-22 11:28:54 -07006811
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006812 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07006813 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
6814 st_second_stage_module_deinit(st_sec_stage);
6815 }
6816
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006817 pthread_mutex_lock(&st_ses->lock);
6818 if (!st_ses->aggregator_thread_created) {
6819 pthread_mutex_unlock(&st_ses->lock);
6820 return 0;
6821 }
6822 /* If other client has second stage enabled, keep the aggregator */
6823 list_for_each(node, &st_ses->clients_list) {
6824 c_ses = node_to_item(node, st_session_t, hw_list_node);
6825 if (c_ses != stc_ses && !list_empty(&c_ses->second_stage_list)) {
6826 aggregator_needed = true;
6827 break;
6828 }
6829 }
6830 if (aggregator_needed) {
6831 pthread_mutex_unlock(&st_ses->lock);
6832 return 0;
6833 }
6834
6835 destroy_det_event_aggregator(st_ses);
6836
Quinn Male2e883752019-03-22 11:28:54 -07006837 if (st_ses->det_session_ev)
6838 free(st_ses->det_session_ev);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006839 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006840
6841 return 0;
6842}
6843
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006844int st_session_request_detection(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006845{
6846 int status = 0;
6847
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006848 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006849 return -EINVAL;
6850
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006851 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6852 st_session_ev_t ev = {.ev_id = ST_SES_EV_REQUEST_DET, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006853
6854 /* lock to serialize event handling */
6855 pthread_mutex_lock(&st_ses->lock);
6856 DISPATCH_EVENT(st_ses, ev, status);
6857 pthread_mutex_unlock(&st_ses->lock);
6858 return status;
6859}
6860
Harshal Ahire89337992020-07-13 02:38:14 +05306861int st_session_get_module_version(st_session_t *stc_ses, char version[])
6862{
6863 int status = 0;
6864
6865 if (!stc_ses || !stc_ses->hw_proxy_ses)
6866 return -EINVAL;
6867
6868 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6869 st_session_ev_t ev = { .ev_id = ST_SES_EV_GET_MODULE_VERSION, .stc_ses = stc_ses,
6870 .payload.module_version = version};
6871
6872 pthread_mutex_lock(&st_ses->lock);
6873 DISPATCH_EVENT(st_ses, ev, status);
6874 pthread_mutex_unlock(&st_ses->lock);
6875 return status;
6876}
6877
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006878int st_session_init(st_session_t *stc_ses, struct sound_trigger_device *stdev,
Quinn Male2e883752019-03-22 11:28:54 -07006879 st_exec_mode_t exec_mode, sound_model_handle_t sm_handle)
6880{
6881 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006882 struct st_vendor_info *v_info = NULL;
6883 st_proxy_session_t *st_ses = NULL;
6884 struct listnode *node = NULL;
6885 struct st_session *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07006886 pthread_mutexattr_t attr;
6887
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006888 if (!stc_ses || !stdev)
6889 return -EINVAL;
Quinn Male2e883752019-03-22 11:28:54 -07006890
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006891 st_ses = calloc(1, sizeof(st_proxy_session_t));
6892 if (!st_ses) {
6893 ALOGE("%s: hw_proxy_ses allocation failed", __func__);
6894 return -ENOMEM;
6895 }
6896 st_ses->stdev = stc_ses->stdev = stdev;
6897 v_info = stc_ses->vendor_uuid_info;
Quinn Male2e883752019-03-22 11:28:54 -07006898
6899 if (v_info && (EXEC_MODE_CFG_DYNAMIC == v_info->exec_mode_cfg)) {
6900 st_ses->enable_trans = true;
Quinn Male2e883752019-03-22 11:28:54 -07006901 /* alloc and init cpe session*/
Quinn Male9a345522020-03-12 17:49:25 -07006902 st_ses->hw_ses_cpe =
6903 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
6904 if (!st_ses->hw_ses_cpe) {
6905 status = -ENOMEM;
6906 goto cleanup;
Quinn Male2e883752019-03-22 11:28:54 -07006907 }
Quinn Male9a345522020-03-12 17:49:25 -07006908 status = st_hw_sess_gcs_init(st_ses->hw_ses_cpe, hw_sess_cb,
6909 (void *)st_ses, ST_EXEC_MODE_CPE, v_info, sm_handle, stdev);
6910 if (status) {
6911 ALOGE("%s: initializing gcs hw session failed %d", __func__,
6912 status);
6913 goto cleanup;
6914 }
6915
6916 /* alloc and init adsp session*/
6917 st_ses->hw_ses_adsp =
6918 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
6919 if (!st_ses->hw_ses_adsp) {
6920 st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
6921 status = -ENOMEM;
6922 goto cleanup;
6923 }
6924
6925 status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
6926 (void *)st_ses, ST_EXEC_MODE_ADSP, v_info, sm_handle, stdev);
6927 if (status) {
6928 ALOGE("%s: initializing lsm session failed", __func__);
6929 st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
6930 goto cleanup;
6931 }
6932
Quinn Male2e883752019-03-22 11:28:54 -07006933 /* set current hw_session */
6934 if (exec_mode == ST_EXEC_MODE_CPE)
6935 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
6936 else if (exec_mode == ST_EXEC_MODE_ADSP)
6937 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07006938 } else if (v_info && (EXEC_MODE_CFG_CPE == v_info->exec_mode_cfg)) {
6939 st_ses->enable_trans = false;
Quinn Male9a345522020-03-12 17:49:25 -07006940
6941 ALOGD("%s: initializing gcs hw session", __func__);
6942 st_ses->hw_ses_cpe =
6943 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
6944 if (!st_ses->hw_ses_cpe) {
6945 status = -ENOMEM;
6946 goto cleanup;
Quinn Male2e883752019-03-22 11:28:54 -07006947 }
Quinn Male9a345522020-03-12 17:49:25 -07006948 status = st_hw_sess_gcs_init(st_ses->hw_ses_cpe, hw_sess_cb,
6949 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6950 if (status) {
6951 ALOGE("%s: initializing gcs hw session failed %d",
6952 __func__, status);
6953 goto cleanup;
6954 }
6955
Quinn Male2e883752019-03-22 11:28:54 -07006956 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07006957 } else if (v_info && (EXEC_MODE_CFG_APE == v_info->exec_mode_cfg)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006958 /*
6959 * Check for merge sound model support and return the existing hw
6960 * session. If any other clients have already created it.
6961 */
Quinn Male58749452020-03-26 17:14:56 -07006962 if (v_info->merge_fs_soundmodels &&
6963 stc_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006964 if (!v_info->is_qcva_uuid) {
Quinn Male58749452020-03-26 17:14:56 -07006965 ALOGE("%s: merge sound model not supported for non SVA engines",
6966 __func__);
6967 status = -ENOSYS;
6968 goto cleanup;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006969 }
6970 list_for_each(node, &stdev->sound_model_list) {
6971 c_ses = node_to_item(node, st_session_t, list_node);
6972 if ((c_ses != stc_ses) &&
6973 c_ses->vendor_uuid_info->is_qcva_uuid &&
Quinn Male58749452020-03-26 17:14:56 -07006974 c_ses->vendor_uuid_info->merge_fs_soundmodels &&
6975 c_ses->f_stage_version == ST_MODULE_TYPE_GMM) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006976 stc_ses->hw_proxy_ses = c_ses->hw_proxy_ses;
6977 list_add_tail(&stc_ses->hw_proxy_ses->clients_list,
6978 &stc_ses->hw_list_node);
Quinn Male58749452020-03-26 17:14:56 -07006979 ALOGD("%s: another client attached, merge SM: h%d <-- c%d",
6980 __func__, stc_ses->hw_proxy_ses->sm_handle, sm_handle);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006981 free(st_ses);
6982 st_ses = NULL;
6983 break;
6984 }
6985 }
Quinn Male58749452020-03-26 17:14:56 -07006986 } else if (stc_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
6987 if (!v_info->is_qcva_uuid) {
6988 ALOGE("%s: multi sound model not supported for non SVA engines",
6989 __func__);
6990 status = -ENOSYS;
6991 goto cleanup;
6992 }
6993 list_for_each(node, &stdev->sound_model_list) {
6994 c_ses = node_to_item(node, st_session_t, list_node);
6995 if ((c_ses != stc_ses) &&
6996 c_ses->vendor_uuid_info->is_qcva_uuid &&
6997 c_ses->f_stage_version == ST_MODULE_TYPE_PDK5) {
6998 stc_ses->hw_proxy_ses = c_ses->hw_proxy_ses;
6999 list_add_tail(&stc_ses->hw_proxy_ses->clients_list,
7000 &stc_ses->hw_list_node);
7001 ALOGD("%s: another client attached, multi SM: h%d <-- c%d",
7002 __func__, stc_ses->hw_proxy_ses->sm_handle, sm_handle);
7003 free(st_ses);
7004 st_ses = NULL;
7005 break;
7006 }
7007 }
7008 }
7009 if (st_ses) { /* If no other client exist */
7010 st_ses->hw_ses_adsp =
7011 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
7012 if (!st_ses->hw_ses_adsp) {
7013 status = -ENOMEM;
7014 goto cleanup;
7015 }
7016 status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
7017 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
7018 if (status) {
7019 ALOGE("%s: initializing lsm hw session failed %d",
7020 __func__, status);
7021 goto cleanup;
7022 }
7023 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
7024 st_ses->f_stage_version = stc_ses->f_stage_version;
7025 st_ses->hw_ses_current->f_stage_version = stc_ses->f_stage_version;
7026 }
Quinn Male2e883752019-03-22 11:28:54 -07007027 } else if (v_info && (EXEC_MODE_CFG_ARM == v_info->exec_mode_cfg)) {
7028 st_ses->enable_trans = false;
7029 st_ses->hw_ses_arm = calloc(1, sizeof(st_hw_session_pcm_t));
7030 if (!st_ses->hw_ses_arm) {
7031 status = -ENOMEM;
7032 goto cleanup;
7033 }
7034 status = st_hw_sess_pcm_init(st_ses->hw_ses_arm, hw_sess_cb,
7035 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
7036 if (status) {
7037 ALOGE("%s: initializing pcm hw session failed %d",
7038 __func__, status);
7039 goto cleanup;
7040 }
7041 st_ses->hw_ses_current = st_ses->hw_ses_arm;
7042 } else if (!v_info) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007043 st_ses->hw_ses_cpe =
7044 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
Quinn Male2e883752019-03-22 11:28:54 -07007045 if (!st_ses->hw_ses_cpe) {
7046 status = -ENOMEM;
7047 goto cleanup;
7048 }
7049 status = st_hw_sess_lsm_init(st_ses->hw_ses_cpe, hw_sess_cb,
7050 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
7051 if (status) {
7052 ALOGE("%s: initializing lsm hw session failed %d",
7053 __func__, status);
7054 goto cleanup;
7055 }
7056 }
7057
7058 pthread_mutexattr_init(&attr);
7059 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007060 pthread_mutex_init(&stc_ses->lock, (const pthread_mutexattr_t *)&attr);
Quinn Male2e883752019-03-22 11:28:54 -07007061
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007062 stc_ses->exec_mode = exec_mode;
7063 stc_ses->sm_handle = sm_handle;
7064 stc_ses->ssr_transit_exec_mode = ST_EXEC_MODE_NONE;
7065 stc_ses->client_req_det_mode = ST_DET_UNKNOWN_MODE;
7066 stc_ses->state = ST_STATE_IDLE;
Quinn Male2e883752019-03-22 11:28:54 -07007067
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007068 if (st_ses) { /* Could get freed if other client exists */
Quinn Male23026702019-07-19 10:51:16 -07007069 st_ses->vendor_uuid_info = v_info;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007070 st_ses->exec_mode = exec_mode;
7071 st_ses->sm_handle = sm_handle;
7072 st_ses->lab_fp = NULL;
7073 pthread_mutex_init(&st_ses->lock, (const pthread_mutexattr_t *)&attr);
Quinn Male2e883752019-03-22 11:28:54 -07007074
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007075 stc_ses->hw_proxy_ses = st_ses;
Quinn Male58749452020-03-26 17:14:56 -07007076 list_init(&st_ses->sm_info_list);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007077 list_init(&st_ses->clients_list);
7078 list_add_tail(&st_ses->clients_list, &stc_ses->hw_list_node);
7079 ALOGD("%s: client attached: h%d <-- c%d", __func__,
7080 st_ses->sm_handle, sm_handle);
7081
7082 if (!stdev->ssr_offline_received) {
7083 STATE_TRANSITION(st_ses, idle_state_fn);
7084 } else {
7085 STATE_TRANSITION(st_ses, ssr_state_fn);
7086 status = 0;
7087 }
7088 }
Quinn Male2e883752019-03-22 11:28:54 -07007089 return status;
7090
7091cleanup:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007092 if (st_ses) {
7093 if (st_ses->hw_ses_cpe)
7094 free(st_ses->hw_ses_cpe);
7095 if (st_ses->hw_ses_adsp)
7096 free(st_ses->hw_ses_adsp);
7097 free(st_ses);
7098 }
Quinn Male2e883752019-03-22 11:28:54 -07007099 return status;
7100}
7101
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007102int st_session_deinit(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07007103{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007104 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
7105
7106 pthread_mutex_lock(&st_ses->lock);
7107 list_remove(&stc_ses->hw_list_node);
7108 ALOGV("%s: client detatched: h%d <-- c%d", __func__, st_ses->sm_handle,
7109 stc_ses->sm_handle);
7110 if (stc_ses == st_ses->det_stc_ses)
7111 st_ses->det_stc_ses = NULL;
7112
7113 if (!list_empty(&st_ses->clients_list)) {
7114 pthread_mutex_unlock(&st_ses->lock);
7115 return 0;
7116 }
Quinn Male2e883752019-03-22 11:28:54 -07007117 /* deinit cpe session */
7118 if (st_ses->hw_ses_cpe) {
Quinn Male9a345522020-03-12 17:49:25 -07007119 st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007120 free(st_ses->hw_ses_cpe);
Quinn Male2e883752019-03-22 11:28:54 -07007121 st_ses->hw_ses_cpe = NULL;
7122 }
Quinn Male2e883752019-03-22 11:28:54 -07007123 /* deinit adsp session */
7124 if (st_ses->hw_ses_adsp) {
7125 st_hw_sess_lsm_deinit(st_ses->hw_ses_adsp);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007126 free(st_ses->hw_ses_adsp);
Quinn Male2e883752019-03-22 11:28:54 -07007127 st_ses->hw_ses_adsp = NULL;
7128 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007129 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07007130 pthread_mutex_destroy(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07007131 free(stc_ses->hw_proxy_ses);
7132 stc_ses->hw_proxy_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07007133
7134 return 0;
7135}