blob: 9b6d5c6d06609f510af8be72e4c35fc0ff83d9b0 [file] [log] [blame]
Quinn Male2e883752019-03-22 11:28:54 -07001/* st_session.c
2 *
3 * This file contains the state machine for a single sound trigger
4 * user session. This state machine implements logic for handling all user
5 * interactions, detectinos, SSR and Audio Concurencies.
6 *
Zhou Song388d0342020-02-16 16:31:05 +08007 * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
Quinn Male2e883752019-03-22 11:28:54 -07008 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
11 * met:
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * * Neither the name of The Linux Foundation nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
32 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34#define LOG_TAG "sound_trigger_hw"
35#define ATRACE_TAG (ATRACE_TAG_HAL)
36/* #define LOG_NDEBUG 0 */
37#define LOG_NDDEBUG 0
38
39#include <errno.h>
40#include <pthread.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <cutils/log.h>
44#include <cutils/trace.h>
45#include "st_session.h"
46#include "st_hw_session.h"
47#include "st_hw_session_lsm.h"
48#include "st_hw_session_gcs.h"
49#include "sound_trigger_hw.h"
50#include "st_hw_session_pcm.h"
51#include "st_hw_extn.h"
52#include "st_hw_common.h"
53#include "st_second_stage.h"
54
55#ifdef LINUX_ENABLED
56#define ST_SES_DEFERRED_STOP_DELAY_MS 0
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -070057#define ST_SES_DEFERRED_STOP_SS_DELAY_MS 0
Quinn Male2e883752019-03-22 11:28:54 -070058#else
59#define ST_SES_DEFERRED_STOP_DELAY_MS 1000
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -070060#define ST_SES_DEFERRED_STOP_SS_DELAY_MS 250
Quinn Male2e883752019-03-22 11:28:54 -070061#endif
62
63#define IS_SS_DETECTION_PENDING(det)\
64 (det & (KEYWORD_DETECTION_PENDING | USER_VERIFICATION_PENDING))
65#define IS_SS_DETECTION_SUCCESS(det)\
66 !(det & (KEYWORD_DETECTION_REJECT | USER_VERIFICATION_REJECT))
67
Dallas Delaneyf5132c72019-07-01 15:09:06 -070068#define IS_KEYWORD_DETECTION_MODEL(sm_id) (sm_id & ST_SM_ID_SVA_KWD)
69
70#define IS_USER_VERIFICATION_MODEL(sm_id) (sm_id & ST_SM_ID_SVA_VOP)
71
72#define IS_SECOND_STAGE_MODEL(sm_id)\
73 ((sm_id & ST_SM_ID_SVA_KWD) || (sm_id & ST_SM_ID_SVA_VOP))
74
75#define IS_MATCHING_SS_MODEL(usecase_sm_id, levels_sm_id)\
76 ((usecase_sm_id & levels_sm_id) ||\
77 ((usecase_sm_id & ST_SM_ID_SVA_RNN) && (levels_sm_id & ST_SM_ID_SVA_CNN)))
78
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -070079#define STATE_TRANSITION(st_session, new_state_fn)\
80do {\
81 if (st_session->current_state != new_state_fn) {\
82 st_session->current_state = new_state_fn;\
83 ALOGD("session[%d]: %s ---> %s", st_session->sm_handle, __func__, \
84 #new_state_fn);\
85 }\
86} while(0)
87
88#define DISPATCH_EVENT(st_session, event, status)\
89do {\
90 status = st_session->current_state(st_session, &event);\
91} while (0)
92
93#define REG_SM_RETRY_CNT 5
94#define REG_SM_WAIT_TIME_MS 100
95
96#define MAX_CONF_LEVEL_VALUE (100)
97#define MAX_KW_USERS_NAME_LEN (2 * MAX_STRING_LEN)
98
Quinn Male2e883752019-03-22 11:28:54 -070099/* below enum used in cleanup in error scenarios */
100enum hw_session_err_mask {
101 HW_SES_ERR_MASK_DEVICE_SET = 0x1,
102 HW_SES_ERR_MASK_REG_SM = 0x2,
103 HW_SES_ERR_MASK_REG_SM_PARAM = 0x4,
104 HW_SES_ERR_MASK_STARTED = 0x8,
105 HW_SES_ERR_MASK_BUFFERING = 0x10,
106};
107
Quinn Male2e883752019-03-22 11:28:54 -0700108typedef struct st_session_loadsm_payload {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700109 struct sound_trigger_phrase_sound_model *phrase_sm;
Quinn Male2e883752019-03-22 11:28:54 -0700110} st_session_loadsm_payload_t;
111
112typedef struct st_session_start_payload {
113 void *config;
114 size_t config_size;
115 recognition_callback_t callback;
116 void *cookie;
117} st_session_start_payload_t;
118
119typedef struct st_session_read_pcm_payload {
120 void *out_buff;
121 size_t out_buff_size;
122 size_t *actual_read_size;
123} st_session_readpcm_payload_t;
124
125typedef struct st_session_get_param_payload {
126 const char *param;
127 void *payload;
128 size_t payload_size;
129 size_t *param_data_size;
130} st_session_getparam_payload_t;
131
132struct st_session_ev {
133 st_session_event_id_t ev_id;
134 union {
135 st_session_loadsm_payload_t loadsm;
136 st_session_start_payload_t start;
137 st_hw_sess_detected_ev_t detected;
138 st_exec_mode_t exec_mode;
139 st_session_readpcm_payload_t readpcm;
140 enum ssr_event_status ssr;
141 char *chmix_coeff_str;
142 bool enable;
143 st_session_getparam_payload_t getparam;
144 } payload;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700145 st_session_t *stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -0700146};
147
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700148static int idle_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
149static int loaded_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
150static int active_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
151static int detected_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
152static int buffering_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
153static int ssr_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
154
155static inline int process_detection_event
156(
157 st_proxy_session_t *st_ses, uint64_t timestamp, int detect_status,
158 void *payload, size_t payload_size,
159 struct sound_trigger_recognition_event **event
160);
161
Quinn Male3d7d9d42019-05-20 13:35:01 -0700162ST_DBG_DECLARE(static int file_cnt = 0);
Quinn Male2e883752019-03-22 11:28:54 -0700163
164void hw_sess_cb(st_hw_sess_event_t *hw_event, void *cookie)
165{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700166 st_proxy_session_t *st_ses = (st_proxy_session_t *)cookie;
Quinn Male2e883752019-03-22 11:28:54 -0700167 int status = 0;
168 int lock_status = 0;
169
170 if (!hw_event || !cookie) {
171 ALOGE("%s: received NULL params", __func__);
172 return;
173 }
174
175 switch (hw_event->event_id) {
176 case ST_HW_SESS_EVENT_DETECTED:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700177 {
178 st_session_ev_t ev;
179 ev.ev_id = ST_SES_EV_DETECTED;
180 ev.payload.detected = hw_event->payload.detected;
Quinn Male2e883752019-03-22 11:28:54 -0700181
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700182 do {
183 lock_status = pthread_mutex_trylock(&st_ses->lock);
184 } while (lock_status && !st_ses->device_disabled &&
185 (st_ses->exec_mode != ST_EXEC_MODE_NONE) &&
186 (st_ses->current_state != ssr_state_fn));
Quinn Male2e883752019-03-22 11:28:54 -0700187
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700188 if (st_ses->device_disabled) {
189 ALOGV("%s:[%d] device switch in progress, ignore event",
190 __func__, st_ses->sm_handle);
191 } else if (st_ses->exec_mode == ST_EXEC_MODE_NONE) {
192 ALOGV("%s:[%d] transition in progress, ignore event",
193 __func__, st_ses->sm_handle);
194 } else if (st_ses->current_state == ssr_state_fn) {
195 ALOGV("%s:[%d] SSR handling in progress, ignore event",
196 __func__, st_ses->sm_handle);
197 } else if (!lock_status) {
Quinn Male2e883752019-03-22 11:28:54 -0700198 /*
199 * TODO: Add RECOGNITION_STATUS_GET_STATE_RESPONSE to
200 * the SoundTrigger API header.
201 */
202 if (st_ses->detection_requested)
203 ev.payload.detected.detect_status = 3;
204
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700205 DISPATCH_EVENT(st_ses, ev, status);
Quinn Male2e883752019-03-22 11:28:54 -0700206 }
207
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700208 if (!lock_status)
209 pthread_mutex_unlock(&st_ses->lock);
210 break;
211 }
212
Quinn Male2e883752019-03-22 11:28:54 -0700213 default:
214 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
215 break;
216 };
217
218}
219
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700220static inline void free_array_ptrs(char **arr, unsigned int arr_len)
221{
222 int i = 0;
223
224 if (!arr)
225 return;
226
227 for (i = 0; i < arr_len; i++) {
228 if (arr[i]) {
229 free(arr[i]);
230 arr[i] = NULL;
231 }
232 }
233 free(arr);
234 arr = NULL;
235}
236
237static inline void alloc_array_ptrs(char ***arr, unsigned int arr_len,
238 unsigned int elem_len)
239{
240 char **str_arr = NULL;
241 int i = 0;
242
243 str_arr = (char **) calloc(arr_len, sizeof(char *));
244
245 if (!str_arr) {
246 *arr = NULL;
247 return;
248 }
249
250 for (i = 0; i < arr_len; i++) {
251 str_arr[i] = (char *) calloc(elem_len, sizeof(char));
252 if (str_arr[i] == NULL) {
253 free_array_ptrs(str_arr, i);
254 *arr = NULL;
255 return;
256 }
257 }
258 *arr = str_arr;
259 ALOGV("%s: string array %p", __func__, *arr);
260 for (i = 0; i < arr_len; i++)
261 ALOGV("%s: string array[%d] %p", __func__, i, (*arr)[i]);
262}
263
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700264static int merge_sound_models(struct sound_trigger_device *stdev,
265 unsigned int num_models, listen_model_type *in_models[],
266 listen_model_type *out_model)
267{
268 listen_status_enum sm_ret = 0;
269 int status = 0;
270
271 ALOGV("%s: num_models to merge %d", __func__, num_models);
272
273 if (!stdev->smlib_handle) {
274 ALOGE("%s: NULL sound model lib handle", __func__);
275 return -ENOSYS;
276 }
277
278 sm_ret = stdev->smlib_getMergedModelSize(num_models, in_models,
279 &out_model->size);
280 if ((sm_ret != kSucess) || !out_model->size) {
281 ALOGE("%s: smlib_getMergedModelSize failed, err %d, size %d", __func__,
282 sm_ret, out_model->size);
283 return -EINVAL;
284 }
285 ALOGD("%s: merge sound model size %d", __func__, out_model->size);
286
287 out_model->data = calloc(1, out_model->size * sizeof(char));
288 if (!out_model->data) {
289 ALOGE("%s: Merged sound model allocation failed", __func__);
290 return -ENOMEM;
291 }
292
293 sm_ret = stdev->smlib_mergeModels(num_models, in_models, out_model);
294 if (sm_ret != kSucess) {
295 ALOGE("%s: smlib_mergeModels failed, err %d", __func__, sm_ret);
296 status = -EINVAL;
297 goto cleanup;
298 }
299 if (!out_model->data || !out_model->size) {
300 ALOGE("%s: MergeModels returned NULL data or size %d", __func__,
301 out_model->size);
302 status = -EINVAL;
303 goto cleanup;
304 }
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -0700305 if (stdev->enable_debug_dumps) {
306 ST_DBG_DECLARE(FILE *sm_fd = NULL; static int sm_cnt = 0);
307 ST_DBG_FILE_OPEN_WR(sm_fd, ST_DEBUG_DUMP_LOCATION,
308 "st_smlib_output_merged_sm", "bin", sm_cnt++);
309 ST_DBG_FILE_WRITE(sm_fd, out_model->data, out_model->size);
310 ST_DBG_FILE_CLOSE(sm_fd);
311 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700312 ALOGV("%s: Exit", __func__);
313 return 0;
314
315cleanup:
316 if (out_model->data) {
317 free(out_model->data);
318 out_model->data = NULL;
319 out_model->size = 0;
320 }
321 return status;
322}
323
324static int delete_from_merged_sound_model(struct sound_trigger_device *stdev,
325 char **keyphrases, unsigned int num_keyphrases,
326 listen_model_type *in_model, listen_model_type *out_model)
327{
328 listen_model_type merge_model = {0};
329 listen_status_enum sm_ret = 0;
330 unsigned int out_model_sz = 0;
331 int status = 0, i = 0;
332
333 out_model->data = NULL;
334 out_model->size = 0;
335 merge_model.data = in_model->data;
336 merge_model.size = in_model->size;
337
338 for (i = 0; i < num_keyphrases; i++) {
339 sm_ret = stdev->smlib_getSizeAfterDeleting(&merge_model, keyphrases[i],
340 NULL, &out_model_sz);
341 if (sm_ret != kSucess) {
342 ALOGE("%s: smlib_getSizeAfterDeleting failed %d", __func__, sm_ret);
343 status = -EINVAL;
344 goto cleanup;
345 }
346 if (out_model_sz >= in_model->size) {
347 ALOGE("%s: unexpected, smlib_getSizeAfterDeleting returned size %d"
348 "not less than merged model size %d", __func__,
349 out_model_sz, in_model->size);
350 status = -EINVAL;
351 goto cleanup;
352 }
353 ALOGV("%s: Size after deleting kw[%d] = %d", __func__, i, out_model_sz);
354 if (!out_model->data) {
355 /* Valid if deleting multiple keyphrases one after other */
356 free (out_model->data);
357 out_model->size = 0;
358 }
359 out_model->data = calloc(1, out_model_sz * sizeof(char));
360 if (!out_model->data) {
361 ALOGE("%s: Merge sound model allocation failed, size %d ", __func__,
362 out_model_sz);
363 status = -ENOMEM;
364 goto cleanup;
365 }
366 out_model->size = out_model_sz;
367
368 sm_ret = stdev->smlib_deleteFromModel(&merge_model, keyphrases[i],
369 NULL, out_model);
370 if (sm_ret != kSucess) {
371 ALOGE("%s: smlib_getSizeAfterDeleting failed %d", __func__, sm_ret);
372 status = -EINVAL;
373 goto cleanup;
374 }
375 if (out_model->size != out_model_sz) {
376 ALOGE("%s: unexpected, out_model size %d != expected size %d",
377 __func__, out_model->size, out_model_sz);
378 status = -EINVAL;
379 goto cleanup;
380 }
381 /* Used if deleting multiple keyphrases one after other */
382 merge_model.data = out_model->data;
383 merge_model.size = out_model->size;
384 }
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -0700385 if (stdev->enable_debug_dumps && out_model->data && out_model->size) {
386 ST_DBG_DECLARE(FILE *sm_fd = NULL; static int sm_cnt = 0);
387 ST_DBG_FILE_OPEN_WR(sm_fd, ST_DEBUG_DUMP_LOCATION,
388 "st_smlib_output_deleted_sm", "bin", sm_cnt++);
389 ST_DBG_FILE_WRITE(sm_fd, out_model->data, out_model->size);
390 ST_DBG_FILE_CLOSE(sm_fd);
391 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700392 return 0;
393
394cleanup:
395 if (out_model->data) {
396 free(out_model->data);
397 out_model->data = NULL;
398 }
399 return status;
400}
401
402static void release_sound_model_info(struct sound_model_info *sm_info)
403{
404 ALOGV("%s", __func__);
405
406 if (sm_info->cf_levels) {
407 free(sm_info->cf_levels);
408 sm_info->cf_levels = NULL;
409 sm_info->det_cf_levels = NULL;
410 }
411 free_array_ptrs(sm_info->keyphrases, sm_info->num_keyphrases);
412 sm_info->keyphrases = NULL;
413
414 free_array_ptrs(sm_info->users, sm_info->num_users);
415 sm_info->users = NULL;
416
417 free_array_ptrs(sm_info->cf_levels_kw_users, sm_info->cf_levels_size);
418 sm_info->cf_levels_kw_users = NULL;
419}
420
421static inline void stdbg_print_sound_model_header(
422 listen_sound_model_header *smh)
423{
424 int i = 0, j = 0;
425
426 ALOGV("%s", __func__);
427 ALOGV("numKeywords = %d", smh->numKeywords);
428 ALOGV("numUsers = %d", smh->numUsers);
429 ALOGV("numActiveUserKeywordPairs = %d", smh->numActiveUserKeywordPairs);
430 ALOGV("isStripped = %d", smh->isStripped);
431 ALOGV("model_indicator = %d", smh->model_indicator);
432
433 for (i = 0; i < smh->numKeywords; i++) {
434 ALOGV("kw-%d langPerKw = %d", i, smh->langPerKw[i]);
435 ALOGV("kw-%d numUsersSetPerKw = %d", i, smh->numUsersSetPerKw[i]);
436 ALOGV("kw-%d isUserDefinedKeyword = %d", i,
437 smh->isUserDefinedKeyword[i]);
438 }
439 if (smh->userKeywordPairFlags) {
440 for (i = 0; i < smh->numUsers; i++) {
441 for (j = 0; j < smh->numKeywords; j++)
442 ALOGV("userKeywordPairFlags[%d][%d] = %d", i, j,
443 smh->userKeywordPairFlags[i][j]);
444 }
445 }
446}
447
448static int query_sound_model(struct sound_trigger_device *stdev,
449 struct sound_model_info *sm_info, unsigned char *sm_data,
450 unsigned int sm_size)
451{
452 listen_sound_model_header sm_header = {0};
453 listen_model_type model = {0};
454 listen_status_enum sm_ret = 0;
455 int status = 0, i = 0, j = 0, k = 0;
456 uint16_t tmp = 0;
457
458 ALOGV("%s: enter sm_size %d", __func__, sm_size);
459
460 if (!stdev->smlib_handle) {
461 ALOGE("%s: NULL sound model lib handle", __func__);
462 return -ENOSYS;
463 }
464
465 model.data = sm_data;
466 model.size = sm_size;
467
468 sm_ret = stdev->smlib_getSoundModelHeader(&model, &sm_header);
469 if (sm_ret != kSucess) {
470 ALOGE("%s: smlib_getSoundModelHeader failed, err %d ", __func__, sm_ret);
471 return -EINVAL;
472 }
473 if (sm_header.numKeywords == 0) {
474 ALOGE("%s: num keywords zero!!", __func__);
475 return -EINVAL;
476 }
477 if (sm_header.numActiveUserKeywordPairs < sm_header.numUsers) {
478 ALOGE("%s: smlib activeUserKwPairs(%d) < total users (%d)", __func__,
479 sm_header.numActiveUserKeywordPairs, sm_header.numUsers);
480 goto cleanup;
481 }
482 if (sm_header.numUsers && !sm_header.userKeywordPairFlags) {
483 ALOGE("%s: userKeywordPairFlags is NULL, numUsers (%d)", __func__,
484 sm_header.numUsers);
485 goto cleanup;
486 }
487 stdbg_print_sound_model_header(&sm_header);
488
489 /* MAX_STRING_LEN is part of listen sound model header file */
490 alloc_array_ptrs(&sm_info->keyphrases, sm_header.numKeywords,
491 MAX_STRING_LEN);
492 if (!sm_info->keyphrases) {
493 ALOGE("%s: keyphrases allocation failed", __func__);
494 status = -ENOMEM;
495 goto cleanup;
496 }
497 sm_info->num_keyphrases = sm_header.numKeywords;
498 sm_info->num_users = sm_header.numUsers;
499
500 tmp = sm_header.numKeywords;
Zhou Songdeddfcc2019-06-18 22:25:03 +0800501 ALOGV("%s: stdb: model.data %pK, model.size %d", __func__, model.data,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700502 model.size);
503 sm_ret = stdev->smlib_getKeywordPhrases(&model, &tmp, sm_info->keyphrases);
504 if (sm_ret) {
505 ALOGE("%s: smlib_getKeywordPhrases failed, err %d ", __func__, sm_ret);
506 goto cleanup;
507 }
508 if (tmp != sm_header.numKeywords) {
509 ALOGE("%s: smlib_getkeywordPhrases(%d) != sml header (%d)", __func__,
510 tmp, sm_header.numKeywords);
511 goto cleanup;
512 }
513 for (i = 0; i < sm_header.numKeywords; i++)
514 ALOGV("%s: keyphrases names = %s", __func__, sm_info->keyphrases[i]);
515
516 if (sm_header.numUsers) {
517 alloc_array_ptrs(&sm_info->users, sm_header.numUsers, MAX_STRING_LEN);
518 if (!sm_info->users) {
519 ALOGE("%s: users allocation failed", __func__);
520 status = -ENOMEM;
521 goto cleanup;
522 }
523
524 tmp = sm_header.numUsers;
525 sm_ret = stdev->smlib_getUserNames(&model, &tmp, sm_info->users);
526 if (sm_ret) {
527 ALOGE("%s: smlib_getUserNames failed, err %d ", __func__, sm_ret);
528 goto cleanup;
529 }
530 if (tmp != sm_header.numUsers) {
531 ALOGE("%s: smlib_getUserNames(%d) != sml header (%d)", __func__,
532 tmp, sm_header.numUsers);
533 status = -EINVAL;
534 goto cleanup;
535 }
536 for (i = 0; i < sm_header.numUsers; i++)
537 ALOGV("%s: users names = %s", __func__, sm_info->users[i]);
538 }
539
540 sm_info->cf_levels_size = sm_header.numKeywords +
541 sm_header.numActiveUserKeywordPairs;
542 alloc_array_ptrs(&sm_info->cf_levels_kw_users, sm_info->cf_levels_size,
543 MAX_KW_USERS_NAME_LEN);
544 if (!sm_info->cf_levels_kw_users) {
545 ALOGE("%s: cf_levels_kw_users allocation failed", __func__);
546 status = -ENOMEM;
547 goto cleanup;
548 }
549
550 /* Used later for mapping client to/from merged DSP confidence levels */
551 sm_info->cf_levels = calloc(1, 2 * sm_info->cf_levels_size);
552 if (!sm_info->cf_levels) {
553 ALOGE("%s: cf_levels allocation failed", __func__);
554 status = -ENOMEM;
555 goto cleanup;
556 }
557 /*
558 * Used for updating detection confidence level values from DSP merged
559 * detection conf levels
560 */
561 sm_info->det_cf_levels = sm_info->cf_levels + sm_info->cf_levels_size;
562
563 /*
564 * Used for conf level setting to DSP. Reset the conf value to max value,
565 * so that the keyword of a loaded and in-active model in a merged model
566 * doesn't detect.
567 */
568 memset(sm_info->cf_levels, MAX_CONF_LEVEL_VALUE, sm_info->cf_levels_size);
569
570 /*
571 * Derive the confidence level payload for keyword and user pairs.
572 * Store the user-keyword pair names in an array that will be used for
573 * mapping the DSP detection and confidence levels to the client.
574 */
575 char **kw_names = sm_info->cf_levels_kw_users;
576 char **ukw_names = &sm_info->cf_levels_kw_users[sm_header.numKeywords];
577 int ukw_idx = 0;
578
579 for (i = 0; i < sm_header.numKeywords; i++) {
580 strlcpy(kw_names[i], sm_info->keyphrases[i], MAX_KW_USERS_NAME_LEN);
581 if (!sm_header.numUsersSetPerKw)
582 continue;
583 for (j = 0, k = 0; j < sm_header.numUsers; j++) {
584 if (k >= sm_header.numUsersSetPerKw[i])
585 break;
586 if (sm_header.userKeywordPairFlags[j][i]) {
587 strlcpy(ukw_names[ukw_idx], sm_info->users[j],
588 MAX_KW_USERS_NAME_LEN);
589 strlcat(ukw_names[ukw_idx], sm_info->keyphrases[i],
590 MAX_KW_USERS_NAME_LEN);
591 ukw_idx++;
592 k++;
593 }
594 }
595 }
596 for (i = 0; i < sm_info->cf_levels_size; i++)
597 ALOGV("%s: cf_levels_kw_users = %s", __func__,
598 sm_info->cf_levels_kw_users[i]);
599
600 sm_ret = stdev->smlib_releaseSoundModelHeader(&sm_header);
601 if (sm_ret != kSucess) {
602 ALOGE("%s: smlib_releaseSoundModelHeader failed, err %d ", __func__,
603 sm_ret);
604 status = -EINVAL;
605 goto cleanup_1;
606 }
607 ALOGV("%s: exit", __func__);
608 return 0;
609
610cleanup:
611 sm_ret = stdev->smlib_releaseSoundModelHeader(&sm_header);
612 if (sm_ret != kSucess)
613 ALOGE("%s: smlib_releaseSoundModelHeader failed, err %d ", __func__,
614 sm_ret);
615
616cleanup_1:
617 release_sound_model_info(sm_info);
618
619 return status;
620}
621
622static int add_sound_model(st_session_t *stc_ses, unsigned char *sm_data,
623 unsigned int sm_size)
624{
625 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
626 struct listnode *node = NULL;
627 st_session_t *c_ses = NULL;
628 listen_model_type **in_models = NULL;
629 listen_model_type out_model = {0};
630 struct sound_model_info sm_info = {0};
631 int status = 0, num_models = 0;
632
633 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
634 if (stc_ses->sm_info.sm_data) {
635 ALOGD("%s:[c%d] Already added", __func__, stc_ses->sm_handle);
636 return 0;
637 }
638 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels) {
639 stc_ses->sm_info.sm_data = sm_data;
640 stc_ses->sm_info.sm_size = sm_size;
641 st_ses->sm_info.sm_data = sm_data;
642 st_ses->sm_info.sm_size = sm_size;
643 st_ses->sm_info.sm_type = stc_ses->sm_type;
644 ALOGD("%s:[c%d] no merge", __func__, stc_ses->sm_handle);
645 return 0;
646 }
647 /* get sound model header information for client model */
648 status = query_sound_model(st_ses->stdev, &stc_ses->sm_info,
649 sm_data, sm_size);
650 if (status)
651 return status;
652
653 stc_ses->sm_info.sm_data = sm_data;
654 stc_ses->sm_info.sm_size = sm_size;
Zhou Songdeddfcc2019-06-18 22:25:03 +0800655 ALOGV("%s: stc_ses %pK - sm_data %pK, sm_size %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700656 stc_ses, stc_ses->sm_info.sm_data,
657 stc_ses->sm_info.sm_size);
658
659 /* Check for remaining client sound models to merge */
660 list_for_each(node, &st_ses->clients_list) {
661 c_ses = node_to_item(node, st_session_t, hw_list_node);
662 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data)
663 num_models++;
664 }
665 if (!num_models) {
666 if (st_ses->sm_info.sm_merged && st_ses->sm_info.sm_data) {
667 free(st_ses->sm_info.sm_data);
668 }
669 /* Only one current client model, just re-use it */
670 st_ses->recognition_mode = stc_ses->recognition_mode;
671 stc_ses->sm_info.sm_type = stc_ses->sm_type;
672 st_ses->sm_info = stc_ses->sm_info;
673 st_ses->sm_info.sm_merged = false;
674 ALOGD("%s: re-use single client c%d model, size %d", __func__,
675 stc_ses->sm_handle, stc_ses->sm_info.sm_size);
676 return 0;
677 }
678 ALOGV("%s: num existing models %d", __func__, num_models);
679 /*
680 * Merge this client model with already existing merged model due to other
681 * clients models.
682 */
683 if (!st_ses->sm_info.sm_data) {
684 if (num_models == 1) {
685 /*
686 * Its not a merged model yet, but proxy ses sm_data is valid and
687 * must be pointing to client sm_data
688 */
689 ALOGE("%s: Unexpected, sm_info.sm_data NULL, num current"
690 "models %d", __func__, num_models);
691 status = -EINVAL;
692 goto cleanup;
693 } else if (!st_ses->sm_info.sm_merged) {
694 ALOGE("%s: Unexpected, no pre-existing merged model, num current"
695 "models %d", __func__, num_models);
696 status = -EINVAL;
697 goto cleanup;
698 }
699 }
700
701 /* Merge this client model with remaining clients models */
702 num_models = 2;/* re-use */
703 alloc_array_ptrs((char***)&in_models, num_models, sizeof(listen_model_type));
704 if (!in_models) {
705 ALOGE("%s: in_models allocation failed", __func__);
706 status = -ENOMEM;
707 goto cleanup;
708 }
709 /* Add existing model */
710 in_models[0]->data = st_ses->sm_info.sm_data;
711 in_models[0]->size = st_ses->sm_info.sm_size;
712 /* Add this client model */
713 in_models[1]->data = sm_data;
714 in_models[1]->size = sm_size;
715
716 status = merge_sound_models(st_ses->stdev, 2, in_models, &out_model);
717 if (status)
718 goto cleanup;
719
720 sm_info.sm_data = out_model.data;
721 sm_info.sm_size = out_model.size;
722 sm_info.sm_merged = true;
723
724 status = query_sound_model(st_ses->stdev, &sm_info,
725 out_model.data, out_model.size);
726 if (status)
727 goto cleanup;
728
729 if (out_model.size < st_ses->sm_info.sm_size) {
730 ALOGE("%s: Unexpected, merged model sz %d < current sz %d",
731 __func__, out_model.size, st_ses->sm_info.sm_size);
732 release_sound_model_info(&sm_info);
733 status = -EINVAL;
734 goto cleanup;
735 }
736 free_array_ptrs((char **)in_models, num_models);
737 in_models = NULL;
738
739 /* Update the new merged model */
740 if (st_ses->sm_info.sm_merged && st_ses->sm_info.sm_data) {
741 release_sound_model_info(&st_ses->sm_info);
742 free(st_ses->sm_info.sm_data);
743 }
744 ALOGD("%s: Updated sound model: current size %d, new size %d", __func__,
745 st_ses->sm_info.sm_size, out_model.size);
746 st_ses->sm_info = sm_info;
747
748 /*
749 * If any of the clients has user identificaiton enabled, underlying
750 * hw session has to operate with user identification enabled.
751 */
752 if (stc_ses->recognition_mode & RECOGNITION_MODE_USER_IDENTIFICATION)
753 st_ses->recognition_mode |= stc_ses->recognition_mode;
754
755 return 0;
756
757cleanup:
758 release_sound_model_info(&stc_ses->sm_info);
759 stc_ses->sm_info.sm_data = NULL;
760
761 if (out_model.data)
762 free(out_model.data);
763
764 if (in_models)
765 free_array_ptrs((char **)in_models, num_models);
766
767 return status;
768}
769
770static int delete_sound_model(st_session_t *stc_ses)
771{
772 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
773 struct listnode *node = NULL;
774 st_session_t *c_ses = NULL, *c_ses_rem = NULL;
775 listen_model_type in_model = {0};
776 listen_model_type out_model = {0};
777 struct sound_model_info sm_info = {0};
778 int status = 0, num_models = 0;
779 unsigned int rec_mode = RECOGNITION_MODE_VOICE_TRIGGER;
780
781 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
782 if (!stc_ses->sm_info.sm_data) {
783 ALOGD("%s:[c%d] Already deleted", __func__, stc_ses->sm_handle);
784 return 0;
785 }
786 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels) {
787 /*
788 * As it directly points to client model, just set as NULL
789 * without freeing
790 */
791 st_ses->sm_info.sm_data = NULL;
792 stc_ses->sm_info.sm_data = NULL;
793 ALOGD("%s:[c%d] no merge", __func__, stc_ses->sm_handle);
794 return 0;
795 }
796
Zhou Songdeddfcc2019-06-18 22:25:03 +0800797 ALOGV("%s: stc_ses %pK - sm_data %pK, sm_size %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700798 stc_ses, stc_ses->sm_info.sm_data,
799 stc_ses->sm_info.sm_size);
800
801 /* Check for remaining clients sound models to merge */
802 list_for_each(node, &st_ses->clients_list) {
803 c_ses = node_to_item(node, st_session_t, hw_list_node);
804 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data) {
805 c_ses_rem = c_ses;
806 num_models++;
807 }
808 }
809 if (num_models == 0) {
810 ALOGD("%s: No remaining models", __func__);
811 /* Delete current client model */
812 release_sound_model_info(&stc_ses->sm_info);
813 stc_ses->sm_info.sm_data = NULL;
814 return 0;
815 }
816
817 if (num_models == 1) {
818 ALOGD("%s: reuse only remaining client model, size %d", __func__,
819 c_ses_rem->sm_info.sm_size);
820 /* If only one remaining client model exists, re-use it */
821 if (st_ses->sm_info.sm_merged) {
822 release_sound_model_info(&st_ses->sm_info);
823 if (st_ses->sm_info.sm_data)
824 free(st_ses->sm_info.sm_data);
825 }
826 st_ses->sm_info = c_ses_rem->sm_info;
827 st_ses->sm_info.sm_merged = false;
828 st_ses->hw_ses_current->sthw_cfg.conf_levels =
829 st_ses->sm_info.cf_levels;
830 st_ses->hw_ses_current->sthw_cfg.num_conf_levels =
831 st_ses->sm_info.cf_levels_size;
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -0700832 st_ses->recognition_mode = c_ses_rem->recognition_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700833 /* Delete current client model */
834 release_sound_model_info(&stc_ses->sm_info);
835 stc_ses->sm_info.sm_data = NULL;
836 return 0;
837 }
838 /* Update overall recogniton mode from remaining clients */
839 list_for_each(node, &st_ses->clients_list) {
840 c_ses = node_to_item(node, st_session_t, hw_list_node);
841 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data) {
Venkatesh Mangalappalia934ec92019-10-01 13:46:25 -0700842 if (c_ses->recognition_mode & RECOGNITION_MODE_USER_IDENTIFICATION)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700843 rec_mode |= RECOGNITION_MODE_USER_IDENTIFICATION;
844 }
845 }
846
847 /*
848 * Delete this client model with already existing merged model due to other
849 * clients models.
850 */
851 if (!st_ses->sm_info.sm_merged || !st_ses->sm_info.sm_data) {
852 ALOGE("%s: Unexpected, no pre-existing merged model to delete from,"
853 "num current models %d", __func__, num_models);
854 goto cleanup;
855 }
856
857 /* Existing merged model from which the current client model to be deleted */
858 in_model.data = st_ses->sm_info.sm_data;
859 in_model.size = st_ses->sm_info.sm_size;
860
861 status = delete_from_merged_sound_model(st_ses->stdev,
862 stc_ses->sm_info.keyphrases, stc_ses->sm_info.num_keyphrases,
863 &in_model, &out_model);
864
865 if (status)
866 goto cleanup;
867
868 sm_info.sm_data = out_model.data;
869 sm_info.sm_size = out_model.size;
870 sm_info.sm_merged = true;
871
872 /* Update existing merged model info with new merged model */
873 status = query_sound_model(st_ses->stdev, &sm_info, out_model.data,
874 out_model.size);
875 if (status)
876 goto cleanup;
877
878 if (out_model.size > st_ses->sm_info.sm_size) {
879 ALOGE("%s: Unexpected, merged model sz %d > current sz %d",
880 __func__, out_model.size, st_ses->sm_info.sm_size);
881 release_sound_model_info(&sm_info);
882 status = -EINVAL;
883 goto cleanup;
884 }
885
886 if (st_ses->sm_info.sm_merged && st_ses->sm_info.sm_data) {
887 release_sound_model_info(&st_ses->sm_info);
888 free(st_ses->sm_info.sm_data);
889 }
890
891 ALOGD("%s: Updated sound model: current size %d, new size %d", __func__,
892 st_ses->sm_info.sm_size, out_model.size);
893 st_ses->sm_info = sm_info;
894 /*
895 * If any of the remaining clients has user identificaiton enabled,
896 * underlying hw session has to operate with user identificaiton enabled.
897 */
898 st_ses->recognition_mode = rec_mode;
899
900 /* Release current client model */
901 release_sound_model_info(&stc_ses->sm_info);
902 stc_ses->sm_info.sm_data = NULL;
903
904 return 0;
905
906cleanup:
907 release_sound_model_info(&stc_ses->sm_info);
908 stc_ses->sm_info.sm_data = NULL;
909
910 if (out_model.data)
911 free(out_model.data);
912
913 return status;
914}
915
916static int update_sound_model(st_session_t *stc_ses, bool add)
917{
918 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
919 struct sound_trigger_phrase_sound_model *phrase_sm = stc_ses->phrase_sm;
920 struct sound_trigger_sound_model *common_sm =
921 (struct sound_trigger_sound_model*)stc_ses->phrase_sm;
922 unsigned char *sm_data = NULL;
923 unsigned int sm_size = 0;
924 int status = 0;
925
926 ALOGV("%s: Enter", __func__);
927
928 if (stc_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
929 sm_data = (unsigned char*)phrase_sm + phrase_sm->common.data_offset;
930 sm_size = phrase_sm->common.data_size;
931 } else {
932 sm_data = (unsigned char*)common_sm + common_sm->data_offset;
933 sm_size = common_sm->data_size;
934 }
935
936 pthread_mutex_lock(&st_ses->lock);
937 if (add)
938 status = add_sound_model(stc_ses, sm_data, sm_size);
939 else
940 status = delete_sound_model(stc_ses);
941 pthread_mutex_unlock(&st_ses->lock);
942
943 ALOGV("%s: Exit", __func__);
944 return status;
945}
946
947static int update_merge_conf_levels_payload(st_proxy_session_t *st_ses,
948 struct sound_model_info *src_sm_info, unsigned char *src,
949 unsigned int src_size, bool set)
950{
951 int i = 0, j = 0;
952
953 if (!st_ses || !src) {
954 ALOGE("%s: NULL pointer", __func__);
955 return -EINVAL;
956 }
957
958 if (!st_ses->sm_info.sm_merged)
959 return 0;
960
961 if (src_size > st_ses->sm_info.cf_levels_size) {
962 ALOGE("%s:[%d] Unexpected, client conf levels %d > "
963 "merged conf levels %d", __func__, st_ses->sm_handle,
964 src_size, st_ses->sm_info.cf_levels_size);
965 return -EINVAL;
966 }
967
968 for (i = 0; i < src_size; i++)
969 ALOGV("%s: src cf_levels[%d]=%d", __func__, i, src[i]);
970
971 /* Populate DSP merged sound model conf levels */
972 for (i = 0; i < src_size; i++) {
973 for (j = 0; j < st_ses->sm_info.cf_levels_size; j++) {
974 if (!strcmp(st_ses->sm_info.cf_levels_kw_users[j],
975 src_sm_info->cf_levels_kw_users[i])) {
976 if (set) {
977 st_ses->sm_info.cf_levels[j] = src[i];
978 ALOGV("%s: set: sm_info.cf_levels[%d]=%d", __func__,
979 j, st_ses->sm_info.cf_levels[j]);
980 } else {
981 st_ses->sm_info.cf_levels[j] = MAX_CONF_LEVEL_VALUE;
982 ALOGV("%s: reset: sm_info.cf_levels[%d]=%d", __func__,
983 j, st_ses->sm_info.cf_levels[j]);
984 }
985 }
986 }
987 }
988 return 0;
989}
990
991static int update_merge_conf_levels_payload_with_active_clients(
992 st_proxy_session_t *st_ses)
993{
994 int status = 0;
995 struct listnode *node = NULL;
996 st_session_t *c_ses = NULL;
997
998 list_for_each(node, &st_ses->clients_list) {
999 c_ses = node_to_item(node, st_session_t, hw_list_node);
1000 if (c_ses->state == ST_STATE_ACTIVE) {
1001 ALOGV("%s: update merge conf levels with other active"
1002 "client %d ", __func__, c_ses->sm_handle);
1003 status = update_merge_conf_levels_payload(st_ses,
1004 &c_ses->sm_info, c_ses->sm_info.cf_levels,
1005 c_ses->sm_info.cf_levels_size, true);
1006 if (status)
1007 return status;
1008 }
1009 }
1010 return status;
1011}
1012
1013static void check_and_extract_det_conf_levels_payload(
1014 st_proxy_session_t *st_ses,
1015 unsigned char *src, unsigned int src_size,
1016 unsigned char **dst, unsigned int *dst_size)
1017{
1018 st_session_t *stc_ses = st_ses->det_stc_ses;
1019 int i = 0, j = 0;
1020
1021 *dst = src;
1022 *dst_size = src_size;
1023
1024 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
1025 !st_ses->sm_info.sm_merged) {
1026 ALOGV("%s:[%d] not merged", __func__, st_ses->sm_handle);
1027 return;
1028 }
1029
1030 if (src_size < st_ses->sm_info.cf_levels_size) {
1031 ALOGE("%s:[%d] Unexpected, detection conf payload size %d < %d",
1032 __func__, st_ses->sm_handle, src_size,
1033 st_ses->sm_info.cf_levels_size);
1034 return;
1035 }
1036
1037 /* Reset any cached previous detection values */
1038 memset(stc_ses->sm_info.det_cf_levels, 0, stc_ses->sm_info.cf_levels_size);
1039
1040 /* Extract the client conf level values from DSP payload */
1041 for(i = 0; i < st_ses->sm_info.cf_levels_size; i++) {
1042 if (!src[i])
1043 continue;
1044 for(j = 0; j < stc_ses->sm_info.cf_levels_size; j++) {
1045 if (!strcmp(stc_ses->sm_info.cf_levels_kw_users[j],
1046 st_ses->sm_info.cf_levels_kw_users[i])) {
1047 stc_ses->sm_info.det_cf_levels[j] = src[i];
1048 }
1049 }
1050 }
1051 for (i = 0; i < stc_ses->sm_info.cf_levels_size; i++)
1052 ALOGD("%s: c%d det_cf_levels[%d]=%d", __func__, stc_ses->sm_handle, i,
1053 stc_ses->sm_info.det_cf_levels[i]);
1054
1055 *dst = stc_ses->sm_info.det_cf_levels;
1056 *dst_size = stc_ses->sm_info.cf_levels_size;
1057}
1058
1059static inline bool check_for_multi_clients(st_proxy_session_t *st_ses)
1060{
1061 struct listnode *node = NULL;
1062 int cnt = 0;
1063
1064 list_for_each(node, &st_ses->clients_list) {
1065 if (++cnt > 1)
1066 return true;
1067 }
1068 return false;
1069}
1070
1071static inline bool is_other_client_attached(st_proxy_session_t *st_ses,
1072 st_session_t *stc_ses)
1073{
1074 struct listnode *node = NULL;
1075 st_session_t *c_ses = NULL;
1076
1077 list_for_each(node, &st_ses->clients_list) {
1078 c_ses = node_to_item(node, st_session_t, hw_list_node);
1079 if (c_ses != stc_ses)
1080 return true;
1081 }
1082 return false;
1083}
1084
1085static inline void reset_clients_pending_load(st_proxy_session_t *st_ses)
1086{
1087 struct listnode *node = NULL;
1088 st_session_t *c_ses = NULL;
1089
1090 list_for_each(node, &st_ses->clients_list) {
1091 c_ses = node_to_item(node, st_session_t, hw_list_node);
1092 c_ses->pending_load = false;
1093 }
1094}
1095
1096static inline int is_any_client_not_pending_load(st_proxy_session_t *st_ses)
1097{
1098 struct listnode *node = NULL;
1099 st_session_t *c_ses = NULL;
1100
1101 list_for_each(node, &st_ses->clients_list) {
1102 c_ses = node_to_item(node, st_session_t, hw_list_node);
1103 if (!c_ses->pending_load)
1104 return true;
1105 }
1106 return false;
1107}
1108
1109static inline int is_any_client_not_pending_set_device(
1110 st_proxy_session_t *st_ses)
1111{
1112 struct listnode *node = NULL;
1113 st_session_t *c_ses = NULL;
1114
1115 list_for_each(node, &st_ses->clients_list) {
1116 c_ses = node_to_item(node, st_session_t, hw_list_node);
1117 if (!c_ses->pending_set_device)
1118 return true;
1119 }
1120 return false;
1121}
1122
1123static inline void reset_clients_pending_set_device(st_proxy_session_t *st_ses)
1124{
1125 struct listnode *node = NULL;
1126 st_session_t *c_ses = NULL;
1127
1128 list_for_each(node, &st_ses->clients_list) {
1129 c_ses = node_to_item(node, st_session_t, hw_list_node);
1130 c_ses->pending_set_device = false;
1131 }
1132}
1133
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001134static inline bool is_any_client_paused(st_proxy_session_t *st_ses)
1135{
1136 struct listnode *node = NULL;
1137 st_session_t *c_ses = NULL;
1138
1139 list_for_each(node, &st_ses->clients_list) {
1140 c_ses = node_to_item(node, st_session_t, hw_list_node);
1141 if (c_ses->paused)
1142 return true;
1143 }
1144 return false;
1145}
1146
1147static inline bool is_any_client_in_state(st_proxy_session_t *st_ses,
1148 enum client_states_t state)
1149{
1150 struct listnode *node = NULL;
1151 st_session_t *c_ses = NULL;
1152
1153 list_for_each(node, &st_ses->clients_list) {
1154 c_ses = node_to_item(node, st_session_t, hw_list_node);
1155 if (c_ses->state == state)
1156 return true;
1157 }
1158 return false;
1159}
1160
1161static void update_hw_config_on_restart(st_proxy_session_t *st_ses,
1162 st_session_t *stc_ses)
1163{
1164 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
1165 struct st_hw_ses_config *sthw_cfg = &hw_ses->sthw_cfg;
1166 struct listnode *node = NULL;
1167 st_session_t *c_ses = NULL;
1168 int hb_sz = 0, pr_sz = 0;
1169 bool enable_lab = false;
1170
1171 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
1172 !st_ses->sm_info.sm_merged)
1173 return;
1174
1175 /*
1176 * Adjust history buffer and preroll durations to highest of
1177 * all clients, including current restarting client.
1178 * If any of the clients requested capture or enabled the
1179 * second stage, the underlying hw session buffering needs to be
1180 * enabled.
1181 */
1182 list_for_each(node, &st_ses->clients_list) {
1183 c_ses = node_to_item(node, st_session_t, hw_list_node);
1184 if ((c_ses == stc_ses) || (c_ses->state == ST_STATE_ACTIVE)) {
1185 if (hb_sz < c_ses->hist_buf_duration)
1186 hb_sz = c_ses->hist_buf_duration;
1187 if (pr_sz < c_ses->preroll_duration)
1188 pr_sz = c_ses->preroll_duration;
1189 if (!enable_lab)
1190 enable_lab = (c_ses->rc_config &&
1191 c_ses->rc_config->capture_requested) ||
1192 !list_empty(&c_ses->second_stage_list);
1193 }
1194 }
1195
1196 sthw_cfg->client_req_hist_buf = hb_sz;
1197 sthw_cfg->client_req_preroll = pr_sz;
1198 st_ses->lab_enabled = enable_lab;
1199
1200 update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
1201 stc_ses->sm_info.cf_levels,
1202 stc_ses->sm_info.cf_levels_size,
1203 true);
1204 hw_ses->sthw_cfg_updated = true;
1205
1206 ALOGV("%s:[%d] lab_enabled %d, hb_sz %d, pr_sz %d", __func__,
1207 st_ses->sm_handle, st_ses->lab_enabled,
1208 sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
1209}
1210
1211static bool update_hw_config_on_stop(st_proxy_session_t *st_ses,
1212 st_session_t *stc_ses)
1213{
1214 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
1215 struct st_hw_ses_config *sthw_cfg = &hw_ses->sthw_cfg;
1216 struct listnode *node = NULL;
1217 st_session_t *c_ses = NULL;
1218 int hb_sz = 0, pr_sz = 0;
1219 bool active = false, enable_lab = false;
1220
Quinn Male014bae12019-07-15 18:28:12 -07001221 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001222 if (sthw_cfg->conf_levels) {
1223 ALOGV("%s: free hw conf_levels", __func__);
1224 free(sthw_cfg->conf_levels);
1225 sthw_cfg->conf_levels = NULL;
1226 }
1227 return false;
1228 }
1229 /*
1230 * Adjust history buffer and preroll durations to highest of
1231 * remaining clients.
1232 * If any of the remaining clients requested capture or enabled the
1233 * second stage, the underlying hw session buffering needs to be
1234 * enabled.
1235 */
1236 list_for_each(node, &st_ses->clients_list) {
1237 c_ses = node_to_item(node, st_session_t, hw_list_node);
1238 if ((c_ses != stc_ses) && (c_ses->state == ST_STATE_ACTIVE)) {
1239 active = true;
1240 if (hb_sz < c_ses->hist_buf_duration)
1241 hb_sz = c_ses->hist_buf_duration;
1242 if (pr_sz < c_ses->preroll_duration)
1243 pr_sz = c_ses->preroll_duration;
1244 if (!enable_lab)
1245 enable_lab = c_ses->rc_config->capture_requested ||
1246 !list_empty(&c_ses->second_stage_list);
1247 }
1248 }
1249 if (!active) {
1250 sthw_cfg->client_req_hist_buf = 0;
1251 sthw_cfg->client_req_preroll = 0;
1252 st_ses->lab_enabled = 0;
1253 sthw_cfg->custom_data = NULL;
1254 sthw_cfg->custom_data_size = 0;
1255 hw_ses->sthw_cfg_updated = true;
1256 ALOGV("%s:[%d] no active client hw cfg is reset", __func__,
1257 st_ses->sm_handle);
1258 return false;
1259 }
1260
1261 sthw_cfg->client_req_hist_buf = hb_sz;
1262 sthw_cfg->client_req_preroll = pr_sz;
1263 st_ses->lab_enabled = enable_lab;
1264
1265 update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
1266 stc_ses->sm_info.cf_levels,
1267 stc_ses->sm_info.cf_levels_size,
1268 false);
1269 hw_ses->sthw_cfg_updated = true;
1270
1271 ALOGV("%s:[%d] lab_enabled %d, hb_sz %d, pr_sz %d", __func__,
1272 st_ses->sm_handle, st_ses->lab_enabled,
1273 sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
1274
1275 return active;
1276}
1277
1278static void get_conf_levels_from_dsp_payload(st_proxy_session_t *st_ses,
1279 unsigned char *payload, unsigned int payload_size,
1280 unsigned char **conf_levels, unsigned int *conf_levels_size)
1281{
1282 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
1283 uint32_t key_id = 0, key_payload_size = 0;
1284 unsigned int i = 0;
1285
1286 if (hw_ses->is_generic_event) {
1287 while (i < payload_size) {
1288 key_id = *(uint32_t *)payload;
1289 key_payload_size = *((uint32_t *)payload + 1);
1290
1291 if (key_id == KEY_ID_CONFIDENCE_LEVELS) {
1292 *conf_levels = payload + (4 * sizeof(uint32_t));
1293 *conf_levels_size = *((uint32_t *)payload + 3);;
1294 ALOGV("%s: generic_event: DSP num conf levels %d", __func__,
1295 *conf_levels_size);
1296 break;
1297 }
1298 i += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
1299 payload += i;
1300 }
1301 } else {
1302 if ((st_ses->exec_mode == ST_EXEC_MODE_CPE) && st_ses->stdev->is_gcs) {
1303 *conf_levels = payload + 2;
1304 *conf_levels_size = payload_size - 2;
1305 } else {
1306 *conf_levels = payload;
1307 *conf_levels_size = payload_size;
1308 }
1309 }
1310}
1311
1312st_session_t* get_detected_client(st_proxy_session_t *st_ses,
1313 unsigned char *payload, unsigned int payload_size)
1314{
1315 struct listnode *node = NULL;
1316 st_session_t *c_ses = NULL;
1317 unsigned char *conf_levels = NULL;
1318 unsigned int conf_levels_size = 0;
1319 int i = 0, j = 0;
1320
1321 if (list_empty(&st_ses->clients_list)) {
1322 ALOGE("%s:[%d] no clients attached!!", __func__, st_ses->sm_handle);
1323 return NULL;
1324 }
1325 /*
1326 * If only single client exist, this detection is not for merged
1327 * sound model, hence return this as only available client
1328 */
1329 if (!check_for_multi_clients(st_ses)) {
1330 ALOGV("%s:[%d] single client detection", __func__, st_ses->sm_handle);
1331 node = list_head(&st_ses->clients_list);
1332 c_ses = node_to_item(node, st_session_t, hw_list_node);
1333 if (c_ses->state == ST_STATE_ACTIVE) {
1334 ALOGD("%s: detected c%d", __func__, c_ses->sm_handle);
1335 return c_ses;
1336 } else {
1337 ALOGE("%s: detected c%d is not active", __func__, c_ses->sm_handle);
1338 return NULL;
1339 }
1340 }
1341
1342 get_conf_levels_from_dsp_payload(st_ses, payload, payload_size,
1343 &conf_levels, &conf_levels_size);
1344 if (!conf_levels) {
1345 ALOGE("%s:[%d] no conf levels payload found!!", __func__,
1346 st_ses->sm_handle);
1347 return NULL;
1348 }
1349 if (conf_levels_size < st_ses->sm_info.num_keyphrases) {
1350 ALOGE("%s:[%d] detection conf levels size %d < num of keywords %d",
1351 __func__, st_ses->sm_handle, conf_levels_size,
1352 st_ses->sm_info.num_keyphrases);
1353 return NULL;
1354 }
1355
1356 /*
1357 * The DSP payload contains the keyword conf levels from the beginning.
1358 * Only one keyword conf level is expected to be non-zero from keyword
1359 * detection. Find non-zero conf level up to number of keyphrases and if
1360 * one is found, match it to the corresponding keyphrase from list of
1361 * clients to obtain the detected client.
1362 */
1363 for (i = 0; i < st_ses->sm_info.num_keyphrases; i++) {
1364 if (!conf_levels[i])
1365 continue;
1366 list_for_each(node, &st_ses->clients_list) {
1367 c_ses = node_to_item(node, st_session_t, hw_list_node);
1368 for (j = 0; j < c_ses->sm_info.num_keyphrases; j++) {
1369 if (!strcmp(st_ses->sm_info.keyphrases[i],
1370 c_ses->sm_info.keyphrases[j])) {
1371 if (c_ses->state == ST_STATE_ACTIVE) {
1372 ALOGV("%s: detected c%d", __func__, c_ses->sm_handle);
1373 return c_ses;
1374 } else {
1375 ALOGE("%s: detected c%d is not active", __func__,
1376 c_ses->sm_handle);
1377 return NULL;
1378 }
1379 }
1380 }
1381 }
1382 }
1383 return c_ses;
1384}
1385
1386static int fill_conf_levels_payload_from_rc_config
1387(
1388 const struct sound_trigger_phrase_sound_model *phrase_sm,
1389 const struct sound_trigger_recognition_config *rc_config,
1390 unsigned char *conf_levels,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001391 unsigned int total_num_users
1392)
1393{
1394 int status = 0;
1395 unsigned int user_level, user_id;
1396 unsigned int i = 0, j = 0;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001397 unsigned int num_conf_levels = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001398 unsigned char *user_id_tracker;
1399
Zhou Songdeddfcc2019-06-18 22:25:03 +08001400 if (!phrase_sm || !rc_config || !conf_levels) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001401 ALOGE("%s: ERROR. Invalid inputs",__func__);
1402 return -EINVAL;
1403 }
1404
Zhou Songdeddfcc2019-06-18 22:25:03 +08001405 if ((UINT32_MAX - total_num_users) > rc_config->num_phrases)
1406 num_conf_levels = total_num_users + rc_config->num_phrases;
1407
1408 if (!num_conf_levels) {
1409 ALOGE("%s: ERROR. Invalid num_conf_levels input", __func__);
1410 return -EINVAL;
1411 }
1412
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001413 /* Example: Say the recognition structure has 3 keywords with users
1414 * |kid|
1415 * [0] k1 |uid|
1416 * [3] u1 - 1st trainer
1417 * [4] u2 - 4th trainer
1418 * [6] u3 - 3rd trainer
1419 * [1] k2
1420 * [5] u2 - 2nd trainer
1421 * [7] u3 - 5th trainer
1422 * [2] k3
1423 * [8] u4 - 6th trainer
1424 *
1425 * Output confidence level array will be
1426 * [k1, k2, k3, u1k1, u2k1, u2k2, u3k1, u3k2, u4k3]
1427 */
1428
1429 user_id_tracker = calloc(1, num_conf_levels);
1430 if (!user_id_tracker) {
1431 ALOGE("%s: failed to allocate user_id_tracker", __func__);
1432 return -ENOMEM;
1433 }
1434
1435 for (i = 0; i < rc_config->num_phrases; i++) {
1436 ALOGV("%s: [%d] kw level %d", __func__, i,
1437 rc_config->phrases[i].confidence_level);
1438 for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
1439 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
1440 rc_config->phrases[i].levels[j].user_id,
1441 rc_config->phrases[i].levels[j].level);
1442 }
1443 }
1444
1445 for (i = 0; i < rc_config->num_phrases; i++) {
Zhou Songdeddfcc2019-06-18 22:25:03 +08001446 if (i < num_conf_levels) {
1447 conf_levels[i] = rc_config->phrases[i].confidence_level;
1448 } else {
1449 ALOGE("%s: ERROR. Invalid number of phrases", __func__);
1450 status = -EINVAL;
1451 goto exit;
1452 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001453 for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
1454 user_level = rc_config->phrases[i].levels[j].level;
1455 user_id = rc_config->phrases[i].levels[j].user_id;
1456 if ((user_id < rc_config->num_phrases) ||
1457 (user_id >= num_conf_levels)) {
1458 ALOGE("%s: ERROR. Invalid params user id %d>%d",
1459 __func__, user_id, total_num_users);
1460 status = -EINVAL;
1461 goto exit;
1462 } else {
1463 if (user_id_tracker[user_id] == 1) {
1464 ALOGE("%s: ERROR. Duplicate user id %d",
1465 __func__, user_id);
1466 status = -EINVAL;
1467 goto exit;
1468 }
1469 conf_levels[user_id] = (user_level < 100) ? user_level: 100;
1470 user_id_tracker[user_id] = 1;
1471 ALOGV("%s: user_conf_levels[%d] = %d", __func__,
1472 user_id, conf_levels[user_id]);
1473 }
1474 }
1475 }
1476
1477exit:
1478 free(user_id_tracker);
1479 return status;
1480}
1481
1482int generate_conf_levels_payload_from_rc_config
1483(
1484 const struct sound_trigger_phrase_sound_model *phrase_sm,
1485 const struct sound_trigger_recognition_config *rc_config,
1486 unsigned char **out_payload,
1487 unsigned int *out_payload_size
1488)
1489{
1490 int status = 0;
1491 unsigned int total_num_users = 0, num_conf_levels = 0;
1492 unsigned int i = 0, j = 0;
1493 unsigned char *conf_levels = NULL;
1494
1495 if (!phrase_sm || !rc_config || !out_payload || !out_payload_size) {
1496 ALOGE("%s: ERROR. Invalid inputs",__func__);
1497 status = -EINVAL;
1498 goto exit;
1499 }
1500 *out_payload = NULL;
1501 *out_payload_size = 0;
1502
1503 if((rc_config->num_phrases == 0) ||
1504 (rc_config->num_phrases > phrase_sm->num_phrases)) {
1505 ALOGE("%s: ERROR. Invalid phrases %d!=%d",__func__,
1506 rc_config->num_phrases, phrase_sm->num_phrases);
1507 status = -EINVAL;
1508 goto exit;
1509 }
1510 for (i = 0; i < rc_config->num_phrases; i++) {
1511 for (j = 0; j < rc_config->phrases[i].num_levels; j++)
1512 total_num_users++;
1513 }
1514
1515 num_conf_levels = total_num_users + rc_config->num_phrases;
1516 conf_levels = calloc(1, num_conf_levels);
1517 if (!conf_levels) {
1518 ALOGE("%s: ERROR. conf levels alloc failed",__func__);
1519 status = -ENOMEM;
1520 goto exit;
1521 }
1522
1523 status = fill_conf_levels_payload_from_rc_config(phrase_sm, rc_config,
Zhou Songdeddfcc2019-06-18 22:25:03 +08001524 conf_levels, total_num_users);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001525 if (status) {
1526 ALOGE("%s: fill config payload failed, error %d", __func__, status);
1527 goto exit;
1528 }
1529
1530 *out_payload = conf_levels;
1531 *out_payload_size = num_conf_levels;
1532
1533 return status;
1534
1535exit:
1536 if (conf_levels)
1537 free(conf_levels);
1538 return status;
1539}
1540
1541int generate_conf_levels_payload_from_rc_config_v2
1542(
1543 const struct sound_trigger_phrase_sound_model *phrase_sm,
1544 const struct sound_trigger_recognition_config *rc_config,
1545 unsigned char **out_payload,
1546 unsigned int *out_payload_size
1547)
1548{
1549 int status = 0;
1550 unsigned int total_num_users = 0, num_conf_levels = 0;
1551 unsigned char *conf_levels = NULL;
1552 unsigned int i = 0, j = 0;
1553
1554 ALOGV("%s: Enter...", __func__);
1555
1556 if (!phrase_sm || !rc_config || !out_payload || !out_payload_size) {
1557 ALOGE("%s: ERROR. Invalid inputs",__func__);
1558 status = -EINVAL;
1559 goto exit;
1560 }
1561 *out_payload = NULL;
1562 *out_payload_size = 0;
1563
1564 if((rc_config->num_phrases == 0) ||
1565 (rc_config->num_phrases > phrase_sm->num_phrases)) {
1566 ALOGE("%s: ERROR. Invalid phrases %d!=%d",__func__,
1567 rc_config->num_phrases, phrase_sm->num_phrases);
1568 status = -EINVAL;
1569 goto exit;
1570 }
1571 for (i = 0; i < rc_config->num_phrases; i++) {
1572 for (j = 0; j < rc_config->phrases[i].num_levels; j++)
1573 total_num_users++;
1574 }
1575
1576 num_conf_levels = total_num_users + rc_config->num_phrases;
1577 /*
1578 * allocate dsp payload w/additional 2 bytes for minor_version and
1579 * num_active_models and additional num_conf_levels for KW enable
1580 * fields
1581 */
1582 conf_levels = calloc(1, 2 + 2 * num_conf_levels);
1583 if (!conf_levels) {
1584 ALOGE("%s: ERROR. conf levels alloc failed",__func__);
1585 status = -ENOMEM;
1586 goto exit;
1587 }
1588
1589 conf_levels[0] = 1; /* minor version */
1590 conf_levels[1] = num_conf_levels; /* num_active_models */
1591 status = fill_conf_levels_payload_from_rc_config(phrase_sm, rc_config,
Zhou Songdeddfcc2019-06-18 22:25:03 +08001592 conf_levels + 2, total_num_users);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001593 if (status) {
1594 ALOGE("%s: fill config payload failed, error %d", __func__, status);
1595 goto exit;
1596 }
1597
1598 /*
1599 * set KW enable fields to 1 for now
1600 * TODO: set appropriately based on what client is passing in rc_config
1601 */
1602 memset(&conf_levels[num_conf_levels + 2], 0x1, num_conf_levels);
1603 ALOGV("%s: here", __func__);
1604 *out_payload = conf_levels;
1605 /* add size of minor version and num_active_models */
1606 *out_payload_size = 2 + 2 * num_conf_levels;
1607 return status;
1608
1609exit:
1610 if (conf_levels)
1611 free(conf_levels);
1612 return status;
1613}
1614
1615static int fill_sound_trigger_recognition_config_payload
1616(
1617 const void *sm_levels_generic,
1618 unsigned char *conf_levels,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001619 unsigned int total_num_users,
1620 uint32_t version
1621)
1622{
1623 int status = 0;
1624 unsigned int user_level = 0, user_id = 0;
1625 unsigned int i = 0, j = 0;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001626 unsigned int num_conf_levels = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001627 unsigned char *user_id_tracker = NULL;
1628 struct st_sound_model_conf_levels *sm_levels = NULL;
1629 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
1630
1631 /* Example: Say the recognition structure has 3 keywords with users
1632 * |kid|
1633 * [0] k1 |uid|
1634 * [3] u1 - 1st trainer
1635 * [4] u2 - 4th trainer
1636 * [6] u3 - 3rd trainer
1637 * [1] k2
1638 * [5] u2 - 2nd trainer
1639 * [7] u3 - 5th trainer
1640 * [2] k3
1641 * [8] u4 - 6th trainer
1642 *
1643 * Output confidence level array will be
1644 * [k1, k2, k3, u1k1, u2k1, u2k2, u3k1, u3k2, u4k3]
1645 */
1646
1647 if (version != CONF_LEVELS_INTF_VERSION_0002) {
1648 sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001649 if (!sm_levels || !conf_levels) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001650 ALOGE("%s: ERROR. Invalid inputs", __func__);
1651 return -EINVAL;
1652 }
Zhou Songdeddfcc2019-06-18 22:25:03 +08001653
1654 if ((UINT32_MAX - total_num_users) > sm_levels->num_kw_levels)
1655 num_conf_levels = total_num_users + sm_levels->num_kw_levels;
1656
1657 if (!num_conf_levels) {
1658 ALOGE("%s: ERROR. Invalid num_conf_levels input", __func__);
1659 return -EINVAL;
1660 }
1661
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001662 user_id_tracker = calloc(1, num_conf_levels);
1663 if (!user_id_tracker) {
1664 ALOGE("%s: failed to allocate user_id_tracker", __func__);
1665 return -ENOMEM;
1666 }
1667
1668 for (i = 0; i < sm_levels->num_kw_levels; i++) {
1669 ALOGV("%s: [%d] kw level %d", __func__, i,
1670 sm_levels->kw_levels[i].kw_level);
1671 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++) {
1672 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
1673 sm_levels->kw_levels[i].user_levels[j].user_id,
1674 sm_levels->kw_levels[i].user_levels[j].level);
1675 }
1676 }
1677
1678 for (i = 0; i < sm_levels->num_kw_levels; i++) {
Zhou Songdeddfcc2019-06-18 22:25:03 +08001679 if (i < num_conf_levels) {
1680 conf_levels[i] = sm_levels->kw_levels[i].kw_level;
1681 } else {
1682 ALOGE("%s: ERROR. Invalid numver of kw levels", __func__);
1683 status = -EINVAL;
1684 goto exit;
1685 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001686 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++) {
1687 user_level = sm_levels->kw_levels[i].user_levels[j].level;
1688 user_id = sm_levels->kw_levels[i].user_levels[j].user_id;
1689 if ((user_id < sm_levels->num_kw_levels) ||
1690 (user_id >= num_conf_levels)) {
1691 ALOGE("%s: ERROR. Invalid params user id %d>%d",
1692 __func__, user_id, total_num_users);
1693 status = -EINVAL;
1694 goto exit;
1695 } else {
1696 if (user_id_tracker[user_id] == 1) {
1697 ALOGE("%s: ERROR. Duplicate user id %d",
1698 __func__, user_id);
1699 status = -EINVAL;
1700 goto exit;
1701 }
1702 conf_levels[user_id] = (user_level < 100) ?
1703 user_level: 100;
1704 user_id_tracker[user_id] = 1;
1705 ALOGV("%s: user_conf_levels[%d] = %d", __func__,
1706 user_id, conf_levels[user_id]);
1707 }
1708 }
1709 }
1710 } else {
1711 sm_levels_v2 =
1712 (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001713 if (!sm_levels_v2 || !conf_levels) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001714 ALOGE("%s: ERROR. Invalid inputs", __func__);
1715 return -EINVAL;
1716 }
Zhou Songdeddfcc2019-06-18 22:25:03 +08001717
1718 if ((UINT32_MAX - total_num_users) > sm_levels_v2->num_kw_levels)
1719 num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
1720
1721 if (!num_conf_levels) {
1722 ALOGE("%s: ERROR. Invalid num_conf_levels input", __func__);
1723 return -EINVAL;
1724 }
1725
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001726 user_id_tracker = calloc(1, num_conf_levels);
1727 if (!user_id_tracker) {
1728 ALOGE("%s: failed to allocate user_id_tracker", __func__);
1729 return -ENOMEM;
1730 }
1731
1732 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
1733 ALOGV("%s: [%d] kw level %d", __func__, i,
1734 sm_levels_v2->kw_levels[i].kw_level);
1735 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++) {
1736 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
1737 sm_levels_v2->kw_levels[i].user_levels[j].user_id,
1738 sm_levels_v2->kw_levels[i].user_levels[j].level);
1739 }
1740 }
1741
1742 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
Zhou Songdeddfcc2019-06-18 22:25:03 +08001743 if (i < num_conf_levels) {
1744 conf_levels[i] = sm_levels_v2->kw_levels[i].kw_level;
1745 } else {
1746 ALOGE("%s: ERROR. Invalid numver of kw levels", __func__);
1747 status = -EINVAL;
1748 goto exit;
1749 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001750 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++) {
1751 user_level = sm_levels_v2->kw_levels[i].user_levels[j].level;
1752 user_id = sm_levels_v2->kw_levels[i].user_levels[j].user_id;
1753 if ((user_id < sm_levels_v2->num_kw_levels) ||
1754 (user_id >= num_conf_levels)) {
1755 ALOGE("%s: ERROR. Invalid params user id %d>%d",
1756 __func__, user_id, total_num_users);
1757 status = -EINVAL;
1758 goto exit;
1759 } else {
1760 if (user_id_tracker[user_id] == 1) {
1761 ALOGE("%s: ERROR. Duplicate user id %d",
1762 __func__, user_id);
1763 status = -EINVAL;
1764 goto exit;
1765 }
1766 conf_levels[user_id] = (user_level < 100) ?
1767 user_level: 100;
1768 user_id_tracker[user_id] = 1;
1769 ALOGV("%s: user_conf_levels[%d] = %d", __func__,
1770 user_id, conf_levels[user_id]);
1771 }
1772 }
1773 }
1774 }
1775
1776exit:
1777 free(user_id_tracker);
1778 return status;
1779}
1780
1781static int generate_sound_trigger_recognition_config_payload
1782(
1783 const void *sm_levels_generic,
1784 unsigned char **out_payload,
1785 unsigned int *out_payload_size,
1786 uint32_t version
1787)
1788{
1789 int status = 0;
1790 unsigned int total_num_users = 0, num_conf_levels = 0;
1791 unsigned char *conf_levels = NULL;
1792 unsigned int i = 0, j = 0;
1793 struct st_sound_model_conf_levels *sm_levels = NULL;
1794 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
1795
1796 ALOGV("%s: Enter...", __func__);
1797
1798 if (version != CONF_LEVELS_INTF_VERSION_0002) {
1799 sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
1800 if (!sm_levels || !out_payload || !out_payload_size) {
1801 ALOGE("%s: ERROR. Invalid inputs", __func__);
1802 status = -EINVAL;
1803 goto exit;
1804 }
1805 *out_payload = NULL;
1806 *out_payload_size = 0;
1807
1808 if (sm_levels->num_kw_levels == 0) {
1809 ALOGE("%s: ERROR. No confidence levels present", __func__);
1810 status = -EINVAL;
1811 goto exit;
1812 }
1813 for (i = 0; i < sm_levels->num_kw_levels; i++) {
1814 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++)
1815 total_num_users++;
1816 }
1817
1818 num_conf_levels = total_num_users + sm_levels->num_kw_levels;
1819 conf_levels = calloc(1, num_conf_levels);
1820 if (!conf_levels) {
1821 ALOGE("%s: ERROR. conf levels alloc failed", __func__);
1822 status = -ENOMEM;
1823 goto exit;
1824 }
1825 } else {
1826 sm_levels_v2 =
1827 (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
1828 if (!sm_levels_v2 || !out_payload || !out_payload_size) {
1829 ALOGE("%s: ERROR. Invalid inputs", __func__);
1830 status = -EINVAL;
1831 goto exit;
1832 }
1833 *out_payload = NULL;
1834 *out_payload_size = 0;
1835
1836 if (sm_levels_v2->num_kw_levels == 0) {
1837 ALOGE("%s: ERROR. No confidence levels present", __func__);
1838 status = -EINVAL;
1839 goto exit;
1840 }
1841 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
1842 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++)
1843 total_num_users++;
1844 }
1845
1846 num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
1847 conf_levels = calloc(1, num_conf_levels);
1848 if (!conf_levels) {
1849 ALOGE("%s: ERROR. conf levels alloc failed", __func__);
1850 status = -ENOMEM;
1851 goto exit;
1852 }
1853 }
1854
1855 status = fill_sound_trigger_recognition_config_payload(sm_levels_generic,
Zhou Songdeddfcc2019-06-18 22:25:03 +08001856 conf_levels, total_num_users, version);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001857 if (status) {
1858 ALOGE("%s: fill config payload failed, error %d", __func__, status);
1859 goto exit;
1860 }
1861
1862 *out_payload = conf_levels;
1863 *out_payload_size = num_conf_levels;
1864
1865 return status;
1866
1867exit:
1868 if (conf_levels)
1869 free(conf_levels);
1870
1871 return status;
1872}
1873
1874static int generate_sound_trigger_recognition_config_payload_v2
1875(
1876 const void *sm_levels_generic,
1877 unsigned char **out_payload,
1878 unsigned int *out_payload_size,
1879 uint32_t version
1880)
1881{
1882 int status = 0;
1883 unsigned int total_num_users = 0, num_conf_levels = 0;
1884 unsigned char *conf_levels = NULL;
1885 unsigned int i = 0, j = 0;
1886 struct st_sound_model_conf_levels *sm_levels = NULL;
1887 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
1888
1889 ALOGV("%s: Enter...", __func__);
1890
1891 if (version != CONF_LEVELS_INTF_VERSION_0002) {
1892 sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
1893 if (!sm_levels || !out_payload || !out_payload_size) {
1894 ALOGE("%s: ERROR. Invalid inputs", __func__);
1895 status = -EINVAL;
1896 goto exit;
1897 }
1898 *out_payload = NULL;
1899 *out_payload_size = 0;
1900
1901 if (sm_levels->num_kw_levels == 0) {
1902 ALOGE("%s: ERROR. No confidence levels present", __func__);
1903 status = -EINVAL;
1904 goto exit;
1905 }
1906 for (i = 0; i < sm_levels->num_kw_levels; i++) {
1907 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++)
1908 total_num_users++;
1909 }
1910
1911 num_conf_levels = total_num_users + sm_levels->num_kw_levels;
1912 } else {
1913 sm_levels_v2 =
1914 (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
1915 if (!sm_levels_v2 || !out_payload || !out_payload_size) {
1916 ALOGE("%s: ERROR. Invalid inputs", __func__);
1917 status = -EINVAL;
1918 goto exit;
1919 }
1920 *out_payload = NULL;
1921 *out_payload_size = 0;
1922
1923 if (sm_levels_v2->num_kw_levels == 0) {
1924 ALOGE("%s: ERROR. No confidence levels present", __func__);
1925 status = -EINVAL;
1926 goto exit;
1927 }
1928 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
1929 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++)
1930 total_num_users++;
1931 }
1932 num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
1933 }
1934
1935 /*
1936 * allocate dsp payload w/additional 2 bytes for minor_version and
1937 * num_active_models and additional num_conf_levels for KW enable
1938 * fields
1939 */
1940 conf_levels = calloc(1, 2 + 2 * num_conf_levels);
1941 if (!conf_levels) {
1942 ALOGE("%s: ERROR. conf levels alloc failed", __func__);
1943 status = -ENOMEM;
1944 goto exit;
1945 }
1946
1947 conf_levels[0] = 1; /* minor version */
1948 conf_levels[1] = num_conf_levels; /* num_active_models */
1949 status = fill_sound_trigger_recognition_config_payload(sm_levels_generic,
Zhou Songdeddfcc2019-06-18 22:25:03 +08001950 conf_levels + 2, total_num_users, version);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001951 if (status) {
1952 ALOGE("%s: fill config payload failed, error %d", __func__, status);
1953 goto exit;
1954 }
1955
1956 /* set KW enable fields to 1 for now
1957 * TODO set appropriately based on what client is passing in rc_config
1958 */
1959 memset(&conf_levels[num_conf_levels + 2], 0x1, num_conf_levels);
1960 ALOGV("%s: here", __func__);
1961 *out_payload = conf_levels;
1962 /* add size of minor version and num_active_models */
1963 *out_payload_size = 2 + 2 * num_conf_levels;
1964
1965 return status;
1966
1967exit:
1968 if (conf_levels)
1969 free(conf_levels);
1970
1971 return status;
1972}
1973
1974static int parse_rc_config_key_conf_levels
1975(
1976 st_session_t *stc_ses,
1977 st_hw_session_t *st_hw_ses,
1978 void *opaque_conf_levels,
1979 unsigned char **out_conf_levels,
1980 unsigned int *out_num_conf_levels
1981)
1982{
1983 struct st_confidence_levels_info *conf_levels = NULL;
1984 struct st_confidence_levels_info_v2 *conf_levels_v2 = NULL;
1985 struct st_sound_model_conf_levels *sm_levels = NULL;
1986 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
1987 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
1988 struct listnode *node = NULL;
1989 st_lsm_ss_config_t *ss_cfg = NULL;
1990 st_arm_second_stage_t *st_sec_stage = NULL;
1991 int status = 0;
1992 uint32_t i = 0;
1993 bool gmm_conf_found = false;
1994 uint8_t confidence_level = 0;
1995 int32_t confidence_level_v2 = 0;
1996 bool arm_second_stage = !list_empty(&stc_ses->second_stage_list);
1997 bool adsp_second_stage = (st_hw_ses == st_ses->hw_ses_adsp &&
1998 !list_empty(&st_hw_ses->lsm_ss_cfg_list));
1999
2000 if (arm_second_stage || adsp_second_stage) {
2001 if (stc_ses->rc_config->num_phrases > 1) {
2002 ALOGE("%s: Multi keyword is unsupported with 2nd stage detection",
2003 __func__);
2004 return -EINVAL;
2005 }
2006
2007 if (stc_ses->rc_config->phrases[0].num_levels > 1) {
2008 ALOGE("%s: Multi user is unsupported with 2nd stage detection",
2009 __func__);
2010 return -EINVAL;
2011 }
2012 }
2013
2014 if (stc_ses->st_conf_levels) {
2015 free(stc_ses->st_conf_levels);
2016 stc_ses->st_conf_levels = NULL;
2017 }
2018
2019 if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002) {
2020 conf_levels = (struct st_confidence_levels_info *)
2021 ((char *)opaque_conf_levels + sizeof(struct st_param_header));
2022
2023 stc_ses->st_conf_levels =
2024 calloc(1, sizeof(struct st_confidence_levels_info));
2025 if (!stc_ses->st_conf_levels) {
2026 ALOGE("%s: failed to alloc st_conf_levels", __func__);
2027 return -ENOMEM;
2028 }
2029 /* Cache to use during detection event processing */
2030 memcpy(stc_ses->st_conf_levels, (char *)conf_levels,
2031 sizeof(struct st_confidence_levels_info));
2032
2033 for (i = 0; i < conf_levels->num_sound_models; i++) {
2034 sm_levels = &conf_levels->conf_levels[i];
2035 if (sm_levels->sm_id == ST_SM_ID_SVA_GMM) {
2036 if ((st_ses->stdev->is_gcs) && (st_hw_ses == st_ses->hw_ses_cpe))
2037 status =
2038 generate_sound_trigger_recognition_config_payload_v2(
2039 (void *)sm_levels, out_conf_levels, out_num_conf_levels,
2040 stc_ses->conf_levels_intf_version);
2041 else
2042 status =
2043 generate_sound_trigger_recognition_config_payload(
2044 (void *)sm_levels, out_conf_levels, out_num_conf_levels,
2045 stc_ses->conf_levels_intf_version);
2046 gmm_conf_found = true;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002047 } else if (IS_SECOND_STAGE_MODEL(sm_levels->sm_id)) {
2048 confidence_level = IS_KEYWORD_DETECTION_MODEL(sm_levels->sm_id) ?
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002049 sm_levels->kw_levels[0].kw_level:
2050 sm_levels->kw_levels[0].user_levels[0].level;
2051 if (arm_second_stage) {
2052 list_for_each(node, &stc_ses->second_stage_list) {
2053 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
2054 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002055 if (IS_MATCHING_SS_MODEL(st_sec_stage->ss_info->sm_id,
2056 sm_levels->sm_id))
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002057 st_sec_stage->ss_session->confidence_threshold =
2058 confidence_level;
2059 }
2060 } else if (adsp_second_stage) {
2061 list_for_each(node, &st_hw_ses->lsm_ss_cfg_list) {
2062 ss_cfg = node_to_item(node, st_lsm_ss_config_t,
2063 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002064 if (IS_MATCHING_SS_MODEL(ss_cfg->ss_info->sm_id,
2065 sm_levels->sm_id))
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002066 ss_cfg->confidence_threshold = confidence_level;
2067 }
2068 }
2069 } else {
2070 ALOGE("%s: Unsupported sm id (%d), exiting", __func__,
2071 sm_levels->sm_id);
2072 status = -EINVAL;
2073 break;
2074 }
2075 }
2076 } else {
2077 conf_levels_v2 = (struct st_confidence_levels_info_v2 *)
2078 ((char *)opaque_conf_levels + sizeof(struct st_param_header));
2079
2080 stc_ses->st_conf_levels =
2081 calloc(1, sizeof(struct st_confidence_levels_info_v2));
2082 if (!stc_ses->st_conf_levels) {
2083 ALOGE("%s: failed to alloc st_conf_levels", __func__);
2084 return -ENOMEM;
2085 }
2086 /* Cache to use during detection event processing */
2087 memcpy(stc_ses->st_conf_levels, (char *)conf_levels_v2,
2088 sizeof(struct st_confidence_levels_info_v2));
2089
2090 for (i = 0; i < conf_levels_v2->num_sound_models; i++) {
2091 sm_levels_v2 = &conf_levels_v2->conf_levels[i];
2092 if (sm_levels_v2->sm_id == ST_SM_ID_SVA_GMM) {
2093 if ((st_ses->stdev->is_gcs) &&
2094 (st_hw_ses == st_ses->hw_ses_cpe))
2095 status =
2096 generate_sound_trigger_recognition_config_payload_v2(
2097 (void *)sm_levels_v2, out_conf_levels, out_num_conf_levels,
2098 stc_ses->conf_levels_intf_version);
2099 else
2100 status =
2101 generate_sound_trigger_recognition_config_payload(
2102 (void *)sm_levels_v2, out_conf_levels,
2103 out_num_conf_levels, stc_ses->conf_levels_intf_version);
2104 gmm_conf_found = true;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002105 } else if (IS_SECOND_STAGE_MODEL(sm_levels_v2->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002106 confidence_level_v2 =
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002107 (IS_KEYWORD_DETECTION_MODEL(sm_levels_v2->sm_id)) ?
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002108 sm_levels_v2->kw_levels[0].kw_level:
2109 sm_levels_v2->kw_levels[0].user_levels[0].level;
2110 if (arm_second_stage) {
2111 list_for_each(node, &stc_ses->second_stage_list) {
2112 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
2113 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002114 if (IS_MATCHING_SS_MODEL(st_sec_stage->ss_info->sm_id,
2115 sm_levels_v2->sm_id))
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002116 st_sec_stage->ss_session->confidence_threshold =
2117 confidence_level_v2;
2118 }
2119 } else if (adsp_second_stage) {
2120 list_for_each(node, &st_hw_ses->lsm_ss_cfg_list) {
2121 ss_cfg = node_to_item(node, st_lsm_ss_config_t,
2122 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002123 if (IS_MATCHING_SS_MODEL(ss_cfg->ss_info->sm_id,
2124 sm_levels_v2->sm_id))
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002125 ss_cfg->confidence_threshold = confidence_level_v2;
2126 }
2127 }
2128 } else {
2129 ALOGE("%s: Unsupported sm id (%d), exiting", __func__,
2130 sm_levels_v2->sm_id);
2131 status = -EINVAL;
2132 break;
2133 }
2134 }
2135 }
2136
2137 if (!gmm_conf_found) {
2138 ALOGE("%s: Did not receive GMM confidence threshold, error!", __func__);
2139 status = -EINVAL;
2140 }
2141
2142 if (status && stc_ses->st_conf_levels) {
2143 free(stc_ses->st_conf_levels);
2144 stc_ses->st_conf_levels = NULL;
2145 }
2146 return status;
2147}
2148
2149static int update_hw_config_on_start(st_session_t *stc_ses,
2150 st_hw_session_t *st_hw_ses)
2151{
2152 struct st_param_header *param_hdr = NULL;
2153 struct st_hist_buffer_info *hist_buf = NULL;
2154 struct st_det_perf_mode_info *det_perf_mode = NULL;
2155 struct sound_trigger_recognition_config *rc_config = stc_ses->rc_config;
2156 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
2157 struct st_vendor_info *v_info = NULL;
2158 struct st_hw_ses_config *sthw_cfg = NULL;
2159 unsigned char *conf_levels = NULL;
2160 unsigned int num_conf_levels = 0;
2161 uint8_t *opaque_ptr = NULL;
2162 unsigned int opaque_size = 0, conf_levels_payload_size = 0;
2163 int status = 0;
2164 bool enable_lab = false;
2165
Quinn Maleaba13db2019-07-11 15:52:14 -07002166 if (st_ses->stdev->enable_debug_dumps) {
2167 ST_DBG_DECLARE(FILE *rc_opaque_fd = NULL;
2168 static int rc_opaque_cnt = 0);
2169 ST_DBG_FILE_OPEN_WR(rc_opaque_fd, ST_DEBUG_DUMP_LOCATION,
2170 "rc_config_opaque_data", "bin", rc_opaque_cnt++);
2171 ST_DBG_FILE_WRITE(rc_opaque_fd,
2172 (uint8_t *)rc_config + rc_config->data_offset,
2173 rc_config->data_size);
2174 ST_DBG_FILE_CLOSE(rc_opaque_fd);
2175 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002176
2177 if (!st_hw_ses) {
2178 ALOGE("%s: NULL hw session !!!", __func__);
2179 return -EINVAL;
2180 }
2181
2182 v_info = st_hw_ses->vendor_uuid_info;
2183
2184 if ((rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
2185 v_info->is_qcva_uuid) {
2186 stc_ses->client_req_det_mode = ST_DET_UNKNOWN_MODE;
2187
2188 opaque_ptr = (uint8_t *)rc_config + rc_config->data_offset;
2189 while (opaque_size < rc_config->data_size) {
2190 param_hdr = (struct st_param_header *)opaque_ptr;
2191 ALOGV("%s: key %d, payload size %d", __func__,
2192 param_hdr->key_id, param_hdr->payload_size);
2193
2194 switch(param_hdr->key_id) {
2195 case ST_PARAM_KEY_CONFIDENCE_LEVELS:
2196 stc_ses->conf_levels_intf_version =
2197 *(uint32_t *)(opaque_ptr + sizeof(struct st_param_header));
2198
2199 if (stc_ses->conf_levels_intf_version !=
2200 CONF_LEVELS_INTF_VERSION_0002) {
2201 conf_levels_payload_size =
2202 sizeof(struct st_confidence_levels_info);
2203 } else {
2204 conf_levels_payload_size =
2205 sizeof(struct st_confidence_levels_info_v2);
2206 }
2207 if (param_hdr->payload_size != conf_levels_payload_size) {
2208 ALOGE("%s: Conf level format error, exiting", __func__);
2209 return -EINVAL;
2210 }
2211 status = parse_rc_config_key_conf_levels(stc_ses, st_hw_ses,
2212 opaque_ptr, &conf_levels, &num_conf_levels);
2213 opaque_size += sizeof(struct st_param_header) +
2214 conf_levels_payload_size;
2215 opaque_ptr += sizeof(struct st_param_header) +
2216 conf_levels_payload_size;
2217 if (status) {
2218 ALOGE("%s: parsing conf levels failed(status=%d)",
2219 __func__, status);
2220 return -EINVAL;
2221 }
2222 break;
2223 case ST_PARAM_KEY_HISTORY_BUFFER_CONFIG:
2224 if (param_hdr->payload_size !=
2225 sizeof(struct st_hist_buffer_info)) {
2226 ALOGE("%s: History buffer config format error, exiting",
2227 __func__);
2228 return -EINVAL;
2229 }
2230 hist_buf = (struct st_hist_buffer_info *)(opaque_ptr +
2231 sizeof(struct st_param_header));
2232 stc_ses->hist_buf_duration =
2233 hist_buf->hist_buffer_duration_msec;
2234 stc_ses->preroll_duration = hist_buf->pre_roll_duration_msec;
2235 ALOGV("%s: recognition config history buf len = %d, "
2236 "preroll len = %d, minor version = %d",
2237 __func__, hist_buf->hist_buffer_duration_msec,
2238 hist_buf->pre_roll_duration_msec, hist_buf->version);
2239 opaque_size += sizeof(struct st_param_header) +
2240 sizeof(struct st_hist_buffer_info);
2241 opaque_ptr += sizeof(struct st_param_header) +
2242 sizeof(struct st_hist_buffer_info);
2243 break;
2244 case ST_PARAM_KEY_DETECTION_PERF_MODE:
2245 if (param_hdr->payload_size !=
2246 sizeof(struct st_det_perf_mode_info)) {
2247 ALOGE("%s: Opaque data format error, exiting", __func__);
2248 return -EINVAL;
2249 }
2250 det_perf_mode = (struct st_det_perf_mode_info *)(opaque_ptr +
2251 sizeof(struct st_param_header));
2252 ALOGV("set perf mode to %d", det_perf_mode->mode);
2253 stc_ses->client_req_det_mode = det_perf_mode->mode;
2254 opaque_size += sizeof(struct st_param_header) +
2255 sizeof(struct st_det_perf_mode_info);
2256 opaque_ptr += sizeof(struct st_param_header) +
2257 sizeof(struct st_det_perf_mode_info);
2258 break;
2259 default:
2260 ALOGE("%s: Unsupported opaque data key id, exiting", __func__);
2261 return -EINVAL;
2262 }
2263 }
2264 } else if (stc_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
2265 struct sound_trigger_phrase_sound_model *phrase_sm = stc_ses->phrase_sm;
2266
2267 ALOGV("%s: num_phrases=%d, id=%d", __func__,
2268 rc_config->num_phrases, rc_config->phrases[0].id);
2269
2270 if (st_ses->vendor_uuid_info->is_qcva_uuid ||
2271 st_ses->vendor_uuid_info->is_qcmd_uuid) {
2272 if (st_ses->stdev->is_gcs && st_hw_ses == st_ses->hw_ses_cpe)
2273 status = generate_conf_levels_payload_from_rc_config_v2(
2274 phrase_sm, rc_config, &conf_levels, &num_conf_levels);
2275 else
2276 status = generate_conf_levels_payload_from_rc_config(
2277 phrase_sm, rc_config, &conf_levels, &num_conf_levels);
2278 if (status || !conf_levels) {
2279 ALOGE("%s: failed to get conf levels from lib handle",
2280 __func__);
2281 return status;
2282 }
2283 } else {
2284 ALOGD("%s: No smlib, opaque data would be sent as is", __func__);
2285 }
2286 }
2287
2288 sthw_cfg = &st_hw_ses->sthw_cfg;
2289 enable_lab = stc_ses->rc_config->capture_requested ||
2290 !list_empty(&stc_ses->second_stage_list);
2291
2292 if (v_info->merge_fs_soundmodels) {
2293 /* merge_fs_soundmodels is true only for QC SVA UUID */
2294
2295 /*
2296 * Note:
2297 * For ADSP case, the generated conf levles size must be equal to
2298 * SML queried conf levels.
2299 * For WDSP gcs case, there is additional payload for KW enable
2300 * fields in generated conf_levels. If merge sound model is supported
2301 * on WDSP case, update logic here accordingly.
2302 */
2303 if (num_conf_levels != stc_ses->sm_info.cf_levels_size) {
2304 ALOGE("%s: Unexpected, client cf levels %d != sm_info cf levels %d",
2305 __func__, num_conf_levels, stc_ses->sm_info.cf_levels_size);
2306 return -EINVAL;
2307 }
2308
2309 /*
2310 * If any of the active clients requested capture or enabled the
2311 * second stage, the underlying hw session buffering needs to
2312 * be enabled. Ignore if it is already enabled.
2313 */
2314 if (!st_ses->lab_enabled && enable_lab)
2315 st_ses->lab_enabled = true;
2316
2317 /* Aggregate DSP configuration for highest client configuration */
2318
2319 /* SVA2.0 sound models */
2320 if (!stc_ses->hist_buf_duration &&
2321 stc_ses->rc_config->capture_requested &&
2322 (stc_ses->rc_config->data_size > 0)) {
2323 stc_ses->hist_buf_duration = st_ses->vendor_uuid_info->kw_duration;
2324 stc_ses->preroll_duration = 0;
2325 }
2326
2327 if (stc_ses->hist_buf_duration > sthw_cfg->client_req_hist_buf)
2328 sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
2329 if (stc_ses->preroll_duration > sthw_cfg->client_req_preroll)
2330 sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
2331
2332 ALOGV("%s: client hb_sz %d pr_sz %d, sthw lab %d hb_sz %d "
2333 "pr_sz %d", __func__, stc_ses->hist_buf_duration,
2334 stc_ses->preroll_duration, st_ses->lab_enabled,
2335 sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
2336
2337 /* Cache it to use when client restarts without config update or
2338 * during only one remaining client model as there won't be a
2339 * merged model yet.
2340 */
2341 memcpy(stc_ses->sm_info.cf_levels, conf_levels,
2342 stc_ses->sm_info.cf_levels_size);
2343
2344 status = update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
2345 conf_levels, num_conf_levels, true);
2346 free(conf_levels); /* Merged model conf levels will be used further */
2347 if (status)
2348 return status;
2349
2350 sthw_cfg->conf_levels = st_ses->sm_info.cf_levels;
2351 sthw_cfg->num_conf_levels = st_ses->sm_info.cf_levels_size;
2352 st_hw_ses->sthw_cfg_updated = true;
2353
2354 /*
2355 * Merging further unknown custom data is not needed, as
2356 * SVA doesn't support unkown custom data. if required in future,
2357 * handle here.
2358 * For now just copy the the current client data which is same
2359 * across SVA engines.
Quinn Male9a56b0d2019-07-25 11:52:28 -07002360 * Update the custom data for the case in which one client session
2361 * does not have custom data and another one does.
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002362 */
Quinn Male9a56b0d2019-07-25 11:52:28 -07002363 if (rc_config->data_size > sthw_cfg->custom_data_size) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002364 sthw_cfg->custom_data = (char *)rc_config + rc_config->data_offset;
Quinn Male9a56b0d2019-07-25 11:52:28 -07002365 sthw_cfg->custom_data_size = rc_config->data_size;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002366 }
2367
2368 } else {
2369 st_ses->recognition_mode = stc_ses->recognition_mode;
2370 st_ses->lab_enabled = enable_lab;
2371
2372 sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
2373 sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
2374
2375 if (sthw_cfg->conf_levels)
2376 free(sthw_cfg->conf_levels);
2377 sthw_cfg->conf_levels = conf_levels;
2378 sthw_cfg->num_conf_levels = num_conf_levels;
2379
2380 sthw_cfg->custom_data = (char *)rc_config + rc_config->data_offset;
2381 sthw_cfg->custom_data_size = rc_config->data_size;
2382 }
2383 ALOGD("%s:[%d] lab enabled %d", __func__, st_ses->sm_handle,
2384 st_ses->lab_enabled);
2385
2386 return status;
2387}
2388
2389static void do_hw_sess_cleanup(st_proxy_session_t *st_ses,
2390 st_hw_session_t *hw_ses, enum hw_session_err_mask err)
Quinn Male2e883752019-03-22 11:28:54 -07002391{
2392 if (err & HW_SES_ERR_MASK_BUFFERING)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002393 hw_ses->fptrs->stop_buffering(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002394
2395 if (err & HW_SES_ERR_MASK_STARTED) {
2396 hw_ses->fptrs->stop(hw_ses);
2397 st_ses->hw_session_started = false;
2398 }
2399
2400 if (err & HW_SES_ERR_MASK_REG_SM_PARAM)
2401 hw_ses->fptrs->dereg_sm_params(hw_ses);
2402
2403 if (err & HW_SES_ERR_MASK_DEVICE_SET)
2404 hw_ses->fptrs->set_device(hw_ses, false);
2405
2406 if (err & HW_SES_ERR_MASK_REG_SM)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002407 hw_ses->fptrs->dereg_sm(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002408}
2409
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002410static void reg_hal_event_session(st_session_t *stc_ses,
2411 st_hw_session_t *hw_ses)
Quinn Male2e883752019-03-22 11:28:54 -07002412{
2413 struct sound_trigger_event_info event_info;
2414 /* Pass the pcm information to audio hal for capturing LAB */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002415 if ((stc_ses->rc_config &&
2416 stc_ses->rc_config->capture_requested) &&
2417 stc_ses->stdev->audio_hal_cb) {
2418 ALOGD("%s:[c%d] ST_EVENT_SESSION_REGISTER capture_handle %d",
2419 __func__, stc_ses->sm_handle, stc_ses->capture_handle);
2420 event_info.st_ses.p_ses = (void *)stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07002421 event_info.st_ses.config = hw_ses->config;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002422 event_info.st_ses.capture_handle = stc_ses->capture_handle;
Quinn Male2e883752019-03-22 11:28:54 -07002423 /*
2424 * set pcm to NULL as this version of st_hal doesn't pass pcm to
2425 * audio HAL
2426 */
2427 event_info.st_ses.pcm = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002428 stc_ses->stdev->audio_hal_cb(ST_EVENT_SESSION_REGISTER, &event_info);
Quinn Male2e883752019-03-22 11:28:54 -07002429 }
2430}
2431
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002432static void dereg_hal_event_session(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07002433{
2434 struct sound_trigger_event_info event_info;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002435 /* Indicate to audio hal that to stop reading LAB data */
2436 if ((stc_ses->rc_config &&
2437 stc_ses->rc_config->capture_requested) &&
2438 stc_ses->stdev->audio_hal_cb) {
2439 ALOGD("%s:[c%d] ST_EVENT_SESSION_DEREGISTER capture_handle %d",
2440 __func__, stc_ses->sm_handle, stc_ses->capture_handle);
2441 event_info.st_ses.p_ses = (void *)stc_ses;
2442 event_info.st_ses.capture_handle = stc_ses->capture_handle;
Quinn Male2e883752019-03-22 11:28:54 -07002443 event_info.st_ses.pcm = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002444 stc_ses->stdev->audio_hal_cb(ST_EVENT_SESSION_DEREGISTER, &event_info);
Quinn Male2e883752019-03-22 11:28:54 -07002445 }
2446}
2447
Zhou Songcd3c8e62019-07-16 13:30:19 +08002448static bool check_gcs_usecase_switch
2449(
2450 st_proxy_session_t *st_ses
2451)
2452{
2453 struct st_vendor_info *v_info = NULL;
2454 st_hw_session_t *p_ses = NULL;
2455 st_hw_session_gcs_t *p_gcs_ses = NULL;
2456 int st_device = 0;
2457 unsigned int device_acdb_id = 0;
2458 int capture_device;
2459
2460 if (!st_ses || st_ses->exec_mode != ST_EXEC_MODE_CPE) {
2461 ALOGE("%s: Invalid session or non CPE session!", __func__);
2462 return false;
2463 }
2464
2465 p_ses = st_ses->hw_ses_cpe;
2466 p_gcs_ses = (st_hw_session_gcs_t *)p_ses;
2467 v_info = p_ses->vendor_uuid_info;
2468
2469 if (list_empty(&v_info->gcs_usecase_list)) {
2470 ALOGE("%s: gcs usecase not available", __func__);
2471 return false;
2472 }
2473
2474 /* check if need to switch gcs usecase for new capture device */
2475 capture_device = platform_stdev_get_capture_device(p_ses->stdev->platform);
2476 st_device = platform_stdev_get_device(p_ses->stdev->platform,
2477 v_info, capture_device, p_ses->exec_mode);
2478 device_acdb_id = platform_stdev_get_acdb_id(st_device,
2479 p_ses->exec_mode);
2480 if (platform_stdev_get_xml_version(p_ses->stdev->platform) >=
2481 PLATFORM_XML_VERSION_0x0102) {
2482 int i = 0;
2483 while ((i < MAX_GCS_USECASE_ACDB_IDS) &&
2484 p_gcs_ses->gcs_usecase->acdb_ids[i]) {
2485 if (p_gcs_ses->gcs_usecase->acdb_ids[i] == device_acdb_id)
2486 return false;
2487 i++;
2488 }
2489 ALOGD("%s: gcs usecase doesn't match for new device", __func__);
2490 return true;
2491 } else {
2492 return false;
2493 }
2494}
2495
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002496static int start_hw_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
2497 bool load_sm)
Quinn Male2e883752019-03-22 11:28:54 -07002498{
2499 int status = 0, err = 0;
Zhou Songcd3c8e62019-07-16 13:30:19 +08002500 bool do_unload = false;
Quinn Male2e883752019-03-22 11:28:54 -07002501
2502 /*
Quinn Male3d7d9d42019-05-20 13:35:01 -07002503 * It is possible the BE LPI mode has been updated, but not the FE mode.
2504 * DSP requires both FE and BE to be in the same mode for any configuration
2505 * changes between LPI and non-LPI switch, so update the FE mode to the
Quinn Malecc1affd2019-07-18 16:13:31 -07002506 * same as BE mode by re-opening LSM session. This is also used for
2507 * other transition usecases which require dereg_sm and reg_sm.
Quinn Male2e883752019-03-22 11:28:54 -07002508 */
Quinn Malecc1affd2019-07-18 16:13:31 -07002509 if (hw_ses->lpi_enable != hw_ses->stdev->lpi_enable ||
2510 (hw_ses->barge_in_mode != hw_ses->stdev->barge_in_mode &&
2511 !hw_ses->stdev->support_dynamic_ec_update)) {
Quinn Male3d7d9d42019-05-20 13:35:01 -07002512 hw_ses->lpi_enable = hw_ses->stdev->lpi_enable;
Quinn Malecc1affd2019-07-18 16:13:31 -07002513 hw_ses->barge_in_mode = hw_ses->stdev->barge_in_mode;
Zhou Songcd3c8e62019-07-16 13:30:19 +08002514 do_unload = true;
Zhou Song388d0342020-02-16 16:31:05 +08002515 platform_stdev_reset_backend_cfg(hw_ses->stdev->platform);
Zhou Songcd3c8e62019-07-16 13:30:19 +08002516 }
2517
2518 /*
2519 * For gcs sessions, uid may be changed for new capture device,
2520 * in this case, sm must be dereg and reg again.
2521 */
2522 if (check_gcs_usecase_switch(st_ses))
2523 do_unload = true;
2524
2525 if (do_unload) {
Quinn Male2e883752019-03-22 11:28:54 -07002526 if (!load_sm) {
2527 load_sm = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002528 status = hw_ses->fptrs->dereg_sm(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002529 if (status)
2530 ALOGW("%s:[%d] failed to dereg_sm err %d", __func__,
2531 st_ses->sm_handle, status);
2532 }
2533 }
2534
2535 if (load_sm) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002536 status = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_info.sm_data,
2537 st_ses->sm_info.sm_size, st_ses->sm_info.sm_type);
Quinn Male2e883752019-03-22 11:28:54 -07002538 if (status) {
2539 ALOGE("%s:[%d] failed to reg_sm err %d", __func__,
2540 st_ses->sm_handle, status);
2541 goto cleanup;
2542 }
2543 err |= HW_SES_ERR_MASK_REG_SM;
2544 }
2545
2546 status = hw_ses->fptrs->set_device(hw_ses, true);
2547 if (status) {
2548 ALOGE("%s:[%d] failed to set_device err %d", __func__,
2549 st_ses->sm_handle, status);
2550 goto cleanup;
2551 }
2552 err |= HW_SES_ERR_MASK_DEVICE_SET;
2553
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002554 status = hw_ses->fptrs->reg_sm_params(hw_ses, st_ses->recognition_mode,
2555 st_ses->lab_enabled, st_ses->rc_config, st_ses->sm_info.sm_type,
2556 st_ses->sm_info.sm_data);
Quinn Male2e883752019-03-22 11:28:54 -07002557 if (status) {
2558 ALOGE("%s:[%d] failed to reg_sm_params err %d", __func__,
2559 st_ses->sm_handle, status);
2560 goto cleanup;
2561 }
2562 err |= HW_SES_ERR_MASK_REG_SM_PARAM;
2563
2564 status = hw_ses->fptrs->start(hw_ses);
2565 if (status) {
2566 ALOGE("%s:[%d] failed to start err %d", __func__,
2567 st_ses->sm_handle, status);
2568 goto cleanup;
2569 }
2570 err |= HW_SES_ERR_MASK_STARTED;
2571
2572 st_ses->hw_session_started = true;
2573 return status;
2574
2575cleanup:
2576 do_hw_sess_cleanup(st_ses, hw_ses, err);
2577 return status;
2578}
2579
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002580static int stop_hw_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
2581 bool unload_sm)
Quinn Male2e883752019-03-22 11:28:54 -07002582{
2583 int status = 0;
2584 int rc = 0;
2585
2586 status = hw_ses->fptrs->stop(hw_ses);
2587 if (status) {
2588 ALOGE("%s:[%d] failed to stop err %d", __func__,
2589 st_ses->sm_handle, status);
2590 rc = status;
2591 }
2592
2593 status = hw_ses->fptrs->dereg_sm_params(hw_ses);
2594 if (status) {
2595 ALOGE("%s:[%d] failed to dereg_sm_params err %d", __func__,
2596 st_ses->sm_handle, status);
2597 rc = status;
2598 }
2599
2600 status = hw_ses->fptrs->set_device(hw_ses, false);
2601 if (status) {
2602 ALOGE("%s:[%d] failed to set_device err %d", __func__,
2603 st_ses->sm_handle, status);
2604 rc = status;
2605 }
2606 if (unload_sm) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002607 status = hw_ses->fptrs->dereg_sm(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002608 if (status) {
2609 ALOGE("%s:[%d] failed to dereg_sm, err %d", __func__,
2610 st_ses->sm_handle, status);
2611 rc = status;
2612 }
2613 }
2614
2615 /* This must be set to false irrespective as the above calls may
2616 * return error (esp for SSR)
2617 */
2618 st_ses->hw_session_started = false;
2619 return rc;
2620}
2621
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002622static int start_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
2623 bool load_sm)
Quinn Male2e883752019-03-22 11:28:54 -07002624{
2625 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002626
Quinn Male2e883752019-03-22 11:28:54 -07002627 if (st_ses->hw_session_started) {
2628 ALOGE("%s:[%d] already started", __func__, st_ses->sm_handle);
2629 return -1;
2630 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002631
Quinn Male2e883752019-03-22 11:28:54 -07002632 status = start_hw_session(st_ses, hw_ses, load_sm);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002633 hw_ses->sthw_cfg_updated = false;
2634
Quinn Male2e883752019-03-22 11:28:54 -07002635 return status;
2636}
2637
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002638static int restart_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses)
Quinn Male2e883752019-03-22 11:28:54 -07002639{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002640 int status = 0;
2641
2642 status = hw_ses->fptrs->restart(hw_ses, st_ses->recognition_mode,
2643 st_ses->rc_config, st_ses->sm_info.sm_type,
2644 st_ses->sm_info.sm_data);
Quinn Male2e883752019-03-22 11:28:54 -07002645 if (status == 0) {
2646 st_ses->hw_session_started = true;
2647 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002648 ALOGE("%s:[%d] failed to restart", __func__, st_ses->sm_handle);
Zhou Song944d8742019-09-26 16:22:06 +08002649 /*
2650 * lower layers like gcs/lsm need to handle double stop calls properly
2651 * to avoid possible crash, as some of the clean ups are already issued
2652 * during fptrs->restart() when it's failed.
2653 */
2654 stop_hw_session(st_ses, hw_ses, true);
Quinn Male2e883752019-03-22 11:28:54 -07002655 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002656
Quinn Male2e883752019-03-22 11:28:54 -07002657 return status;
2658}
2659
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002660static int stop_session(st_proxy_session_t *st_ses,
2661 st_hw_session_t *hw_ses, bool unload_sm)
Quinn Male2e883752019-03-22 11:28:54 -07002662{
2663 if (!st_ses->hw_session_started) {
2664 ALOGV("%s:[%d] already stopped", __func__, st_ses->sm_handle);
2665 return 0;
2666 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002667 st_ses->detection_requested = false;
Quinn Male2e883752019-03-22 11:28:54 -07002668 return stop_hw_session(st_ses, hw_ses, unload_sm);
2669}
2670
2671/*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002672 * This function gets the first stage detection keyword indices, which are
2673 * needed by the second stage sessions. If the legacy DSP is used, which does
2674 * not provide keyword indices, set the indices to include the entire keyword
2675 * duration. This function also gets the user confidence level if there is an
2676 * active voiceprint session.
Quinn Male2e883752019-03-22 11:28:54 -07002677 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002678static int get_first_stage_detection_params(st_proxy_session_t *st_ses,
2679 void *payload, size_t payload_size)
Quinn Male2e883752019-03-22 11:28:54 -07002680{
2681 size_t count_size = 0;
2682 uint8_t *payload_ptr = (uint8_t *)payload;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002683 uint8_t *cf_levels = NULL;
2684 uint32_t key_id = 0, key_payload_size = 0, cf_levels_size = 0;
Quinn Male2e883752019-03-22 11:28:54 -07002685 uint32_t kw_start_ms = 0, kw_end_ms = 0;
2686 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002687 struct listnode *node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07002688 st_arm_second_stage_t *st_sec_stage = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002689 st_session_t *stc_ses = st_ses->det_stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07002690 bool is_active_vop_session = false;
2691
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002692 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07002693 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002694 if (st_sec_stage->ss_info->sm_detection_type ==
2695 ST_SM_TYPE_USER_VERIFICATION) {
Quinn Male2e883752019-03-22 11:28:54 -07002696 is_active_vop_session = true;
2697 break;
2698 }
2699 }
2700
2701 if (hw_ses->is_generic_event) {
2702 /*
2703 * This case is for the generic detection event from the DSP. Set the
2704 * keyword start and end indices and user confidence level based on key
2705 * id, if applicable.
2706 */
2707 while (count_size < payload_size) {
2708 key_id = *(uint32_t *)payload_ptr;
2709 key_payload_size = *((uint32_t *)payload_ptr + 1);
2710
2711 switch (key_id) {
2712 case KEY_ID_CONFIDENCE_LEVELS:
2713 if (is_active_vop_session) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002714 /*
2715 * It is expected that VoP is supported with single KW/user
2716 * SVA3.0 model, hence get it directly with hard offset.
2717 */
2718 if (!st_ses->sm_info.sm_merged) {
2719 hw_ses->user_level = (int32_t)(*(payload_ptr +
2720 GENERIC_DET_EVENT_USER_LEVEL_OFFSET));
2721 } else {
2722 /* Extract from first stage merged conf levels */
2723 check_and_extract_det_conf_levels_payload(st_ses,
2724 payload_ptr + (4 * sizeof(uint32_t)),
2725 *((uint32_t *)payload_ptr + 3),
2726 &cf_levels, &cf_levels_size);
2727 if (!cf_levels || !cf_levels_size)
2728 break;
2729 hw_ses->user_level = cf_levels[1];
2730 ALOGV("%s:hw_ses->user_level %d at cf_levels[1]",
2731 __func__, hw_ses->user_level);
2732 }
Quinn Male2e883752019-03-22 11:28:54 -07002733 }
2734 break;
2735
2736 case KEY_ID_KEYWORD_POSITION_STATS:
2737 hw_ses->kw_start_idx = *((uint32_t *)payload_ptr +
2738 GENERIC_DET_EVENT_KW_START_OFFSET);
2739 hw_ses->kw_end_idx = *((uint32_t *)payload_ptr +
2740 GENERIC_DET_EVENT_KW_END_OFFSET);
2741 break;
2742
2743 default:
2744 ALOGW("%s: Unsupported generic detection event key id",
2745 __func__);
2746 break;
2747 }
2748 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
2749 payload_ptr += count_size;
2750 }
2751 } else {
2752 /*
2753 * This case is for the DSP detection events which are not the generic
2754 * detection event. There will be no keyword indices from first stage
2755 * detection, so the start index will be 0 and the end index will be the
2756 * buffer duration sent from the app. If this is not sent, the keyword
2757 * duration from platform xml will be used.
2758 */
2759 hw_ses->kw_start_idx = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002760 if (hw_ses->sthw_cfg.client_req_hist_buf) {
Quinn Male2e883752019-03-22 11:28:54 -07002761 hw_ses->kw_end_idx =
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002762 convert_ms_to_bytes(hw_ses->sthw_cfg.client_req_hist_buf,
Quinn Male2e883752019-03-22 11:28:54 -07002763 &hw_ses->config);
2764 } else {
2765 hw_ses->kw_end_idx =
2766 convert_ms_to_bytes(st_ses->vendor_uuid_info->kw_duration,
2767 &hw_ses->config);
2768 }
2769
2770 if (is_active_vop_session) {
2771 if ((st_ses->exec_mode == ST_EXEC_MODE_CPE) &&
2772 st_ses->stdev->is_gcs) {
2773 hw_ses->user_level = (int32_t)(*(payload_ptr +
2774 GCS_NON_GENERIC_USER_LEVEL_OFFSET));
2775 } else if ((st_ses->exec_mode == ST_EXEC_MODE_ADSP) ||
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002776 !st_ses->stdev->is_gcs) {
Quinn Male2e883752019-03-22 11:28:54 -07002777 hw_ses->user_level = (int32_t)(*(payload_ptr +
2778 LSM_NON_GENERIC_USER_LEVEL_OFFSET));
2779 }
2780 }
2781 }
2782
2783 kw_start_ms = convert_bytes_to_ms(hw_ses->kw_start_idx, &hw_ses->config);
2784 kw_end_ms = convert_bytes_to_ms(hw_ses->kw_end_idx, &hw_ses->config);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002785 ALOGD("%s:[%d] 1st stage kw_start = %dms, kw_end = %dms,"
2786 "is_generic_event %d", __func__, st_ses->sm_handle,
2787 kw_start_ms, kw_end_ms, hw_ses->is_generic_event);
Quinn Male2e883752019-03-22 11:28:54 -07002788
2789 return 0;
2790}
2791
Quinn Male12f5c6f2019-11-14 17:34:10 -08002792static inline int prepare_second_stage_for_client(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07002793{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002794 struct listnode *node = NULL;
2795 st_arm_second_stage_t *st_sec_stage = NULL;
2796 int status = 0;
2797
2798 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
2799
2800 list_for_each(node, &stc_ses->second_stage_list) {
2801 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
2802 status = st_second_stage_prepare_session(st_sec_stage);
2803 }
2804 return status;
2805}
2806
2807static inline int start_second_stage_for_client(st_session_t *stc_ses)
2808{
2809 struct listnode *node = NULL;
2810 st_arm_second_stage_t *st_sec_stage = NULL;
2811 int status = 0;
2812
2813 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
2814
2815 list_for_each(node, &stc_ses->second_stage_list) {
2816 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
2817 status = st_second_stage_start_session(st_sec_stage);
2818 }
2819 return status;
2820}
2821
2822static inline void stop_second_stage_for_client(st_session_t *stc_ses)
2823{
2824 struct listnode *node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07002825 st_arm_second_stage_t *st_sec_stage = NULL;
2826
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002827 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
2828
2829 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07002830 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
2831 st_second_stage_stop_session(st_sec_stage);
2832 }
2833}
2834
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002835static int generate_legacy_st_phrase_recognition_event
2836(
2837 const struct sound_trigger_phrase_sound_model *phrase_sm,
2838 const struct sound_trigger_recognition_config *rc_config,
2839 const void *payload,
2840 unsigned int payload_size,
2841 struct sound_trigger_phrase_recognition_event **out_rc_event
2842)
2843{
2844 struct sound_trigger_phrase_recognition_event *event;
2845 unsigned int i = 0, j = 0, user_id = 0;
2846
2847 ALOGD("%s: Enter payload_size %d", __func__, payload_size);
2848
2849 if(!payload || !phrase_sm || !rc_config || !out_rc_event) {
2850 ALOGE("%s: Null params", __func__);
2851 return -EINVAL;
2852 }
2853
2854 *out_rc_event = NULL;
2855 event = calloc(1, sizeof(*event) + payload_size);
2856 if (!event) {
2857 ALOGE("%s: event allocation failed size %d", __func__, payload_size);
2858 return -ENODEV;
2859 }
2860
2861 event->num_phrases = rc_config->num_phrases;
2862 event->common.data_offset = sizeof(*event);
2863 event->common.data_size = payload_size;
2864 memcpy((char *)event + event->common.data_offset, payload, payload_size);
2865
2866 /* fill confidence levels */
2867 for (i = 0; i < rc_config->num_phrases; i++) {
2868 event->phrase_extras[i].id = rc_config->phrases[i].id;
2869 event->phrase_extras[i].recognition_modes =
2870 phrase_sm->phrases[0].recognition_mode;
2871 event->phrase_extras[i].confidence_level = ((char *)payload)[i];
2872 event->phrase_extras[i].num_levels = rc_config->phrases[i].num_levels;
2873 for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
2874 user_id = rc_config->phrases[i].levels[j].user_id;
2875 event->phrase_extras[i].levels[j].user_id = user_id;
2876 event->phrase_extras[i].levels[j].level =
2877 ((char *)payload)[user_id];
2878 }
2879 }
2880
2881 *out_rc_event = event;
2882 return 0;
2883}
2884
2885/*
2886 * This function sets the opaque data size for the DSP's generic detection
2887 * events. This opaque data can now have varying size based on the requested
2888 * params.
2889 */
2890static size_t set_opaque_data_size(char *payload, size_t payload_size,
2891 uint32_t version)
2892{
2893 size_t count_size = 0, opaque_size = 0;
2894 uint32_t key_id = 0, key_payload_size = 0;
2895
2896 while (count_size < payload_size) {
2897 key_id = *(uint32_t *)payload;
2898 key_payload_size = *((uint32_t *)payload + 1);
2899
2900 switch (key_id) {
2901 case KEY_ID_CONFIDENCE_LEVELS:
2902 opaque_size += sizeof(struct st_param_header);
2903 if (version != CONF_LEVELS_INTF_VERSION_0002) {
2904 opaque_size +=
2905 sizeof(struct st_confidence_levels_info);
2906 } else {
2907 opaque_size +=
2908 sizeof(struct st_confidence_levels_info_v2);
2909 }
2910 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
2911 payload += count_size;
2912 break;
2913
2914 case KEY_ID_KEYWORD_POSITION_STATS:
2915 opaque_size += sizeof(struct st_param_header) +
2916 sizeof(struct st_keyword_indices_info);
2917 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
2918 payload += count_size;
2919 break;
2920
2921 default:
2922 ALOGE("%s: Unsupported generic detection event key id", __func__);
2923 }
2924 }
2925
2926 opaque_size += sizeof(struct st_param_header) +
2927 sizeof(struct st_timestamp_info);
2928
2929 return opaque_size;
2930}
2931
2932/*
2933 * This function packs the updated opaque data confidence levels which are
2934 * passed to the client via callback.
2935 */
2936static int pack_opaque_data_conf_levels(
2937 st_proxy_session_t *st_ses, void *opaque_data,
2938 uint8_t *payload,
2939 unsigned int payload_size)
2940{
2941 uint8_t *payload_ptr = payload;
2942 unsigned int i = 0, j = 0, k = 0, user_id = 0;
2943 st_arm_second_stage_t *st_sec_stage = NULL;
2944 struct listnode *node = NULL;
2945 struct st_confidence_levels_info *conf_levels = NULL;
2946 struct st_confidence_levels_info_v2 *conf_levels_v2 = NULL;
2947 st_session_t *stc_ses = st_ses->det_stc_ses;
2948 int32_t kw_level = 0, user_level = 0;
2949
2950 list_for_each(node, &stc_ses->second_stage_list) {
2951 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002952 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002953 kw_level = st_sec_stage->ss_session->confidence_score;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002954 } else if (IS_USER_VERIFICATION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002955 user_level = st_sec_stage->ss_session->confidence_score;
2956 }
2957 }
2958
2959 if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002) {
2960 conf_levels = (struct st_confidence_levels_info *)opaque_data;
2961 for (i = 0; i < conf_levels->num_sound_models; i++) {
2962 if (conf_levels->conf_levels[i].sm_id == ST_SM_ID_SVA_GMM) {
2963 for (j = 0;
2964 j < conf_levels->conf_levels[i].num_kw_levels; j++) {
2965 if (j <= payload_size)
2966 conf_levels->conf_levels[i].kw_levels[j].kw_level =
2967 payload_ptr[j];
2968 else
2969 ALOGE("%s: unexpected conf size %d < %d", __func__,
2970 payload_size, j);
2971 for (k = 0;
2972 k < conf_levels->conf_levels[i].kw_levels[j].num_user_levels;
2973 k++) {
2974 user_id =
2975 conf_levels->conf_levels[i].kw_levels[j].
2976 user_levels[k].user_id;
2977 if (user_id <= payload_size)
2978 conf_levels->conf_levels[i].kw_levels[j].
2979 user_levels[k].level = payload_ptr[user_id];
2980 else
2981 ALOGE("%s: Unexpected conf size %d < %d", __func__,
2982 payload_size, user_id);
2983 }
2984 }
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002985 } else if (IS_KEYWORD_DETECTION_MODEL(conf_levels->conf_levels[i].sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002986 conf_levels->conf_levels[i].kw_levels[0].kw_level = kw_level;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07002987 } else if (IS_USER_VERIFICATION_MODEL(conf_levels->conf_levels[i].sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002988 /*
2989 * Fill both the keyword and user confidence level with the
2990 * confidence score returned from the voiceprint algorithm.
2991 */
2992 conf_levels->conf_levels[i].kw_levels[0].kw_level =
2993 (uint8_t)user_level;
2994 conf_levels->conf_levels[i].kw_levels[0].user_levels[0].level =
2995 (uint8_t)user_level;
2996 }
2997 }
2998 } else {
2999 conf_levels_v2 = (struct st_confidence_levels_info_v2 *)opaque_data;
3000 for (i = 0; i < conf_levels_v2->num_sound_models; i++) {
3001 if (conf_levels_v2->conf_levels[i].sm_id == ST_SM_ID_SVA_GMM) {
3002 for (j = 0;
3003 j < conf_levels_v2->conf_levels[i].num_kw_levels; j++) {
3004 if (j <= payload_size)
3005 conf_levels_v2->conf_levels[i].kw_levels[j].kw_level =
3006 payload_ptr[j];
3007 else
3008 ALOGE("%s: unexpected conf size %d < %d", __func__,
3009 payload_size, j);
3010
3011 for (k = 0;
3012 k < conf_levels_v2->conf_levels[i].kw_levels[j].num_user_levels;
3013 k++) {
3014 user_id =
3015 conf_levels_v2->conf_levels[i].kw_levels[j].
3016 user_levels[k].user_id;
3017 if (user_id <= payload_size)
3018 conf_levels_v2->conf_levels[i].kw_levels[j].
3019 user_levels[k].level = payload_ptr[user_id];
3020 else
3021 ALOGE("%s: Unexpected conf size %d < %d", __func__,
3022 payload_size, user_id);
3023 }
3024 }
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003025 } else if (IS_KEYWORD_DETECTION_MODEL(conf_levels_v2->conf_levels[i].sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003026 conf_levels_v2->conf_levels[i].kw_levels[0].kw_level = kw_level;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003027 } else if (IS_USER_VERIFICATION_MODEL(conf_levels_v2->conf_levels[i].sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003028 /*
3029 * Fill both the keyword and user confidence level with the
3030 * confidence score returned from the voiceprint algorithm.
3031 */
3032 conf_levels_v2->conf_levels[i].kw_levels[0].kw_level =
3033 user_level;
3034 conf_levels_v2->conf_levels[i].kw_levels[0].user_levels[0].level =
3035 user_level;
3036 }
3037 }
3038 }
3039
3040 return 0;
3041}
3042
3043/* This function packs the sound trigger API confidence levels */
3044static int pack_recognition_event_conf_levels(
3045 st_proxy_session_t *st_ses, uint8_t *payload,
3046 unsigned int payload_size,
3047 struct sound_trigger_phrase_recognition_event *local_event)
3048{
3049 unsigned int j = 0, k = 0, user_id = 0;
3050 st_arm_second_stage_t *st_sec_stage = NULL;
3051 struct listnode *node = NULL;
3052 st_session_t *stc_ses = st_ses->det_stc_ses;
3053 struct sound_trigger_phrase_sound_model *phrase_sm =
3054 (struct sound_trigger_phrase_sound_model *)stc_ses->phrase_sm;
3055
3056 /*
3057 * Fill in the GMM confidence levels to the sound trigger recognition event
3058 * APIs first. If any second stage session is enabled, overwrite the APIs
3059 * with the second stage confidence levels.
3060 */
3061 for (j = 0; j < stc_ses->rc_config->num_phrases; j++) {
3062 local_event->phrase_extras[j].id = stc_ses->rc_config->phrases[j].id;
3063 local_event->phrase_extras[j].recognition_modes =
3064 phrase_sm->phrases[j].recognition_mode;
3065 local_event->phrase_extras[j].num_levels =
3066 stc_ses->rc_config->phrases[j].num_levels;
3067 if (j <= payload_size)
3068 local_event->phrase_extras[j].confidence_level = payload[j];
3069 else
3070 ALOGE("%s: unexpected conf size %d < %d", __func__,
3071 payload_size, j);
3072
3073 for (k = 0; k < stc_ses->rc_config->phrases[j].num_levels; k++) {
3074 user_id = stc_ses->rc_config->phrases[j].levels[k].user_id;
3075 if (user_id <= payload_size) {
3076 local_event->phrase_extras[j].levels[k].user_id = user_id;
3077 local_event->phrase_extras[j].levels[k].level =
3078 payload[user_id];
3079 } else {
3080 ALOGE("%s: Unexpected conf size %d < %d", __func__,
3081 payload_size, user_id);
3082 }
3083 }
3084 }
3085
3086 list_for_each(node, &stc_ses->second_stage_list) {
3087 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003088 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003089 local_event->phrase_extras[0].confidence_level =
3090 (uint8_t)st_sec_stage->ss_session->confidence_score;
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003091 } else if (IS_USER_VERIFICATION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003092 local_event->phrase_extras[0].levels[0].level =
3093 (uint8_t)st_sec_stage->ss_session->confidence_score;
3094 }
3095 }
3096 return 0;
3097}
3098
3099static int parse_generic_event_and_pack_opaque_data(
3100 st_proxy_session_t *st_ses, uint8_t *opaque_data,
3101 uint8_t *payload, size_t payload_size,
3102 struct sound_trigger_phrase_recognition_event *local_event)
3103{
3104 uint32_t key_id = 0, key_payload_size = 0;
3105 struct st_param_header *param_hdr = NULL;
3106 struct st_keyword_indices_info *kw_indices = NULL;
3107 struct st_timestamp_info *timestamps = NULL;
3108 size_t count_size = 0;
3109 st_arm_second_stage_t *st_sec_stage = NULL;
3110 struct listnode *node = NULL;
3111 st_session_t *stc_ses = st_ses->det_stc_ses;
3112 int status = 0;
3113 unsigned char *cf_levels = NULL;
3114 unsigned int cf_levels_size = 0;
3115
3116 while (count_size < payload_size) {
3117 key_id = *(uint32_t *)payload;
3118 key_payload_size = *((uint32_t *)payload + 1);
3119
3120 switch (key_id) {
3121 case KEY_ID_CONFIDENCE_LEVELS:
3122 /* Pack the opaque data confidence levels structure */
3123 param_hdr = (struct st_param_header *)(opaque_data);
3124 param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
3125 opaque_data += sizeof(struct st_param_header);
3126 if (stc_ses->conf_levels_intf_version !=
3127 CONF_LEVELS_INTF_VERSION_0002) {
3128 param_hdr->payload_size =
3129 sizeof(struct st_confidence_levels_info);
3130 } else {
3131 param_hdr->payload_size =
3132 sizeof(struct st_confidence_levels_info_v2);
3133 }
3134 check_and_extract_det_conf_levels_payload(st_ses,
3135 payload + (4 * sizeof(uint32_t)), *((uint32_t *)payload + 3),
3136 &cf_levels, &cf_levels_size);
3137 if (!cf_levels || !cf_levels_size) {
3138 status = -EINVAL;
3139 goto exit;
3140 }
3141 memcpy(opaque_data, stc_ses->st_conf_levels,
3142 param_hdr->payload_size);
3143 pack_opaque_data_conf_levels(st_ses, opaque_data,
3144 cf_levels, cf_levels_size);
3145 pack_recognition_event_conf_levels(st_ses, cf_levels,
3146 cf_levels_size, local_event);
3147 opaque_data += param_hdr->payload_size;
3148 break;
3149
3150 case KEY_ID_KEYWORD_POSITION_STATS:
3151 /* Pack the opaque data keyword indices structure */
3152 param_hdr = (struct st_param_header *)(opaque_data);
3153 param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
3154 param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
3155 opaque_data += sizeof(struct st_param_header);
3156 kw_indices = (struct st_keyword_indices_info *)(opaque_data);
3157 kw_indices->version = 0x1;
3158 kw_indices->start_index = *((uint32_t *)payload + 3);
3159 kw_indices->end_index = *((uint32_t *)payload + 4);
3160
3161 list_for_each(node, &stc_ses->second_stage_list) {
3162 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
3163 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003164 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003165 kw_indices->start_index =
3166 st_sec_stage->ss_session->kw_start_idx;
3167 kw_indices->end_index =
3168 st_sec_stage->ss_session->kw_end_idx;
3169 }
3170 }
3171 opaque_data += sizeof(struct st_keyword_indices_info);
3172 break;
3173
3174 default:
3175 ALOGE("%s: Unsupported generic detection event key id", __func__);
3176 status = -EINVAL;
3177 goto exit;
3178 }
3179 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
3180 payload += count_size;
3181 }
3182
3183 /* Pack the opaque data detection timestamp structure */
3184 param_hdr = (struct st_param_header *)(opaque_data);
3185 param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
3186 param_hdr->payload_size = sizeof(struct st_timestamp_info);
3187 opaque_data += sizeof(struct st_param_header);
3188 timestamps = (struct st_timestamp_info *)(opaque_data);
3189 timestamps->version = 0x1;
3190 timestamps->first_stage_det_event_time =
3191 st_ses->hw_ses_current->first_stage_det_event_time;
3192 if (!list_empty(&stc_ses->second_stage_list))
3193 timestamps->second_stage_det_event_time =
3194 st_ses->hw_ses_current->second_stage_det_event_time;
3195 opaque_data += sizeof(struct st_timestamp_info);
3196
3197exit:
3198 return status;
3199}
3200
3201static int parse_generic_event_without_opaque_data(
3202 st_proxy_session_t *st_ses, uint8_t *payload, size_t payload_size,
3203 struct sound_trigger_phrase_recognition_event *local_event)
3204{
3205 uint32_t key_id = 0, key_payload_size = 0;
3206 size_t count_size = 0;
3207 int status = 0;
3208 unsigned char *cf_levels = NULL;
3209 unsigned int cf_levels_size = 0;;
3210
3211 while (count_size < payload_size) {
3212 key_id = *(uint32_t *)payload;
3213 key_payload_size = *((uint32_t *)payload + 1);
3214
3215 switch (key_id) {
3216 case KEY_ID_CONFIDENCE_LEVELS:
3217 check_and_extract_det_conf_levels_payload(st_ses,
3218 payload + (4 * sizeof(uint32_t)), *((uint32_t *)payload + 3),
3219 &cf_levels, &cf_levels_size);
3220 if (!cf_levels || !cf_levels_size) {
3221 status = -EINVAL;
3222 return status;
3223 }
3224 pack_recognition_event_conf_levels(st_ses, cf_levels,
3225 cf_levels_size, local_event);
3226 return status;
3227
3228 case KEY_ID_KEYWORD_POSITION_STATS:
3229 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
3230 payload += count_size;
3231 break;
3232
3233 default:
3234 ALOGE("%s: Unsupported generic detection event key id", __func__);
3235 status = -EINVAL;
3236 return status;
3237 }
3238 }
3239 return status;
3240}
3241
3242/*
3243 * This function handles detection payloads in the format of the DSP's
3244 * generic detection event.
3245 */
3246int process_detection_event_keyphrase_v2(
3247 st_proxy_session_t *st_ses, int detect_status,
3248 void *payload, size_t payload_size,
3249 struct sound_trigger_phrase_recognition_event **event)
3250{
3251 st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
3252 st_session_t *stc_ses = st_ses->det_stc_ses;
3253 unsigned int i = 0, j = 0;
3254 int status = 0;
3255 uint8_t *opaque_data = NULL;
3256 size_t opaque_size = 0;
3257 struct sound_trigger_phrase_recognition_event *local_event = NULL;
3258
3259 if (st_ses->vendor_uuid_info->is_qcva_uuid)
3260 opaque_size = set_opaque_data_size(payload, payload_size,
3261 stc_ses->conf_levels_intf_version);
3262 else
3263 opaque_size = payload_size;
3264
3265 local_event = calloc(1,
3266 sizeof(struct sound_trigger_phrase_recognition_event) + opaque_size);
3267 if (!local_event) {
3268 ALOGE("%s: local_event allocation failed, opaque data size = %d",
3269 __func__, (unsigned int)opaque_size);
3270 return -ENOMEM;
3271 }
3272
3273 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3274 local_event->common.data_offset =
3275 sizeof(struct sound_trigger_phrase_recognition_event);
3276 local_event->common.data_size = opaque_size;
3277 opaque_data = (uint8_t *)local_event + local_event->common.data_offset;
3278
3279 if (st_ses->vendor_uuid_info->is_qcva_uuid) {
3280 if (stc_ses->rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) {
3281 status = parse_generic_event_and_pack_opaque_data(st_ses,
3282 opaque_data, payload, payload_size, local_event);
3283 if (status) {
3284 ALOGE("%s: Failed to parse generic detection event with opaque"
3285 "data %d", __func__, status);
3286 goto exit;
3287 }
3288
Quinn Maleaba13db2019-07-11 15:52:14 -07003289 if (st_ses->stdev->enable_debug_dumps) {
3290 ST_DBG_DECLARE(FILE *opaque_fd = NULL;
3291 static int opaque_cnt = 0);
3292 ST_DBG_FILE_OPEN_WR(opaque_fd, ST_DEBUG_DUMP_LOCATION,
3293 "detection_opaque_data", "bin", opaque_cnt++);
3294 ST_DBG_FILE_WRITE(opaque_fd, opaque_data, opaque_size);
3295 ST_DBG_FILE_CLOSE(opaque_fd);
3296 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003297 } else {
3298 status = parse_generic_event_without_opaque_data(st_ses, payload,
3299 payload_size, local_event);
3300 if (status) {
3301 ALOGE("%s: Failed to parse generic detection event without"
3302 "opaque data %d", __func__, status);
3303 goto exit;
3304 }
3305 }
3306 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003307 memcpy(local_event->phrase_extras,
3308 stc_ses->rc_config->phrases, stc_ses->rc_config->num_phrases *
3309 sizeof(struct sound_trigger_phrase_recognition_extra));
3310 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3311 local_event->common.data_offset = sizeof(*local_event);
3312 local_event->common.data_size = opaque_size;
3313 memcpy(opaque_data, payload, opaque_size);
3314 opaque_data += opaque_size;
3315 }
3316
3317 /*
3318 * fill the remaining recognition event parameters not specific
3319 * to soundmodel lib
3320 */
3321 local_event->common.status = detect_status;
3322 local_event->common.type = stc_ses->phrase_sm->common.type;
3323 local_event->common.model = stc_ses->sm_handle;
3324 local_event->common.capture_available =
3325 stc_ses->rc_config->capture_requested;
3326 local_event->common.capture_delay_ms = 0;
3327 local_event->common.capture_preamble_ms = 0;
3328 local_event->common.audio_config.sample_rate =
3329 SOUND_TRIGGER_SAMPLING_RATE_16000;
3330 local_event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
3331 local_event->common.audio_config.channel_mask =
3332 audio_channel_in_mask_from_count(st_hw_ses->config.channels);
3333
3334 for (i = 0; i < local_event->num_phrases; ++i) {
3335 ALOGV("%s: [%d] kw_id %d level %d", __func__, i,
3336 local_event->phrase_extras[i].id,
3337 local_event->phrase_extras[i].confidence_level);
3338 for (j = 0; j < local_event->phrase_extras[i].num_levels; ++j) {
3339 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
3340 local_event->phrase_extras[i].levels[j].user_id,
3341 local_event->phrase_extras[i].levels[j].level);
3342 }
3343 }
3344
3345 ALOGI("%s:[c%d]", __func__, stc_ses->sm_handle);
3346
3347 ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
3348 "num_phrases=%d id=%d", __func__, stc_ses->sm_handle,
3349 local_event->common.status, local_event->common.type,
3350 local_event->common.model, local_event->common.capture_available,
3351 local_event->num_phrases, local_event->phrase_extras[0].id);
3352
3353 *event = local_event;
3354 return 0;
3355
3356exit:
3357 if (local_event)
3358 free(local_event);
3359 return status;
3360}
3361
3362/*
3363 * This function handles detection payloads in the format of the DSP's
3364 * legacy (non-generic) detection event.
3365 * TODO: Deprecate this when DSP for all shared targets of this component
3366 * move to generic event.
3367 */
3368static int process_detection_event_keyphrase(
3369 st_proxy_session_t *st_ses, int detect_status,
3370 void *payload, size_t payload_size,
3371 struct sound_trigger_phrase_recognition_event **event)
3372{
3373 st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
3374 st_session_t *stc_ses = st_ses->det_stc_ses;
3375 unsigned int i = 0, j = 0;
3376 int status = 0;
3377 struct sound_trigger_phrase_recognition_event *local_event = NULL;
3378 size_t opaque_size = 0;
3379 uint8_t *opaque_data = NULL, *payload_ptr = NULL;
3380 struct st_param_header *param_hdr = NULL;
3381 st_arm_second_stage_t *st_sec_stage = NULL;
3382 struct listnode *node = NULL;
3383 struct st_keyword_indices_info *kw_indices = NULL;
3384 struct st_timestamp_info *timestamps = NULL;
3385 bool enable_kw_indices = false;
3386 unsigned char *cf_levels = NULL;
3387 unsigned int cf_levels_size = 0;
3388
3389 if ((stc_ses->rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
3390 st_ses->vendor_uuid_info->is_qcva_uuid) {
3391 /*
3392 * This logic is for the updated opaque data format. Sound trigger
3393 * recognition event APIs are filled along with the opaque data's
3394 * confidence levels, keyword indices, and timestamp parameters.
3395 */
3396 opaque_size = (2 * sizeof(struct st_param_header)) +
3397 sizeof(struct st_timestamp_info);
3398 if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002)
3399 opaque_size += sizeof(struct st_confidence_levels_info);
3400 else
3401 opaque_size += sizeof(struct st_confidence_levels_info_v2);
3402
3403 list_for_each(node, &stc_ses->second_stage_list) {
3404 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003405 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003406 enable_kw_indices = true;
3407 opaque_size += sizeof(struct st_param_header) +
3408 sizeof(struct st_keyword_indices_info);
3409 break;
3410 }
3411 }
3412
3413 local_event = calloc(1,
3414 sizeof(struct sound_trigger_phrase_recognition_event) +
3415 opaque_size);
3416 if (!local_event) {
3417 ALOGE("%s: local_event allocation failed, opaque data size = %d",
3418 __func__, (unsigned int)opaque_size);
3419 return -ENOMEM;
3420 }
3421
3422 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3423 local_event->common.data_offset =
3424 sizeof(struct sound_trigger_phrase_recognition_event);
3425 local_event->common.data_size = opaque_size;
3426 opaque_data = (uint8_t *)local_event + local_event->common.data_offset;
3427 if ((st_ses->exec_mode == ST_EXEC_MODE_CPE) && st_ses->stdev->is_gcs) {
3428 payload_ptr = (uint8_t *)payload + 2;
3429 payload_size -= 2; /* Re-use */
3430 } else if ((st_ses->exec_mode == ST_EXEC_MODE_ADSP) ||
3431 !st_ses->stdev->is_gcs) {
3432 payload_ptr = (uint8_t *)payload;
3433 } else {
3434 ALOGE("%s: Invalid execution mode, exiting", __func__);
3435 status = -EINVAL;
3436 goto err_exit;
3437 }
3438
3439 /* Pack the opaque data confidence levels structure */
3440 param_hdr = (struct st_param_header *)opaque_data;
3441 param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
3442 opaque_data += sizeof(struct st_param_header);
3443 if (stc_ses->conf_levels_intf_version !=
3444 CONF_LEVELS_INTF_VERSION_0002) {
3445 param_hdr->payload_size =
3446 sizeof(struct st_confidence_levels_info);
3447 } else {
3448 param_hdr->payload_size =
3449 sizeof(struct st_confidence_levels_info_v2);
3450 }
3451 check_and_extract_det_conf_levels_payload(st_ses, payload_ptr,
3452 payload_size, &cf_levels, &cf_levels_size);
3453 if (!cf_levels || !cf_levels_size) {
3454 status = -EINVAL;
3455 goto err_exit;
3456 }
3457 memcpy(opaque_data, stc_ses->st_conf_levels, param_hdr->payload_size);
3458 pack_opaque_data_conf_levels(st_ses, opaque_data, cf_levels,
3459 cf_levels_size);
3460 pack_recognition_event_conf_levels(st_ses, cf_levels, cf_levels_size,
3461 local_event);
3462 opaque_data += param_hdr->payload_size;
3463
3464 /* Pack the opaque data keyword indices structure */
3465 if (enable_kw_indices) {
3466 param_hdr = (struct st_param_header *)opaque_data;
3467 param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
3468 param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
3469 opaque_data += sizeof(struct st_param_header);
3470 kw_indices = (struct st_keyword_indices_info *)opaque_data;
3471 kw_indices->version = 0x1;
3472 list_for_each(node, &stc_ses->second_stage_list) {
3473 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
3474 list_node);
Dallas Delaneyf5132c72019-07-01 15:09:06 -07003475 if (IS_KEYWORD_DETECTION_MODEL(st_sec_stage->ss_info->sm_id)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003476 kw_indices->start_index =
3477 st_sec_stage->ss_session->kw_start_idx;
3478 kw_indices->end_index =
3479 st_sec_stage->ss_session->kw_end_idx;
3480 }
3481 }
3482 opaque_data += sizeof(struct st_keyword_indices_info);
3483 }
3484
3485 /* Pack the opaque data detection timestamp structure */
3486 param_hdr = (struct st_param_header *)opaque_data;
3487 param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
3488 param_hdr->payload_size = sizeof(struct st_timestamp_info);
3489 opaque_data += sizeof(struct st_param_header);
3490 timestamps = (struct st_timestamp_info *)opaque_data;
3491 timestamps->version = 0x1;
3492 timestamps->first_stage_det_event_time =
3493 st_hw_ses->first_stage_det_event_time;
3494 if (!list_empty(&stc_ses->second_stage_list))
3495 timestamps->second_stage_det_event_time =
3496 st_hw_ses->second_stage_det_event_time;
3497 opaque_data += sizeof(struct st_timestamp_info);
3498
Quinn Maleaba13db2019-07-11 15:52:14 -07003499 if (st_ses->stdev->enable_debug_dumps) {
3500 ST_DBG_DECLARE(FILE *opaque_fd = NULL; static int opaque_cnt = 0);
3501 ST_DBG_FILE_OPEN_WR(opaque_fd, ST_DEBUG_DUMP_LOCATION,
3502 "detection_opaque_data", "bin", opaque_cnt++);
3503 ST_DBG_FILE_WRITE(opaque_fd, (opaque_data - opaque_size),
3504 opaque_size);
3505 ST_DBG_FILE_CLOSE(opaque_fd);
3506 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003507
3508 } else {
3509 if (st_ses->vendor_uuid_info->is_qcva_uuid ||
3510 st_ses->vendor_uuid_info->is_qcmd_uuid) {
3511 if (st_ses->stdev->is_gcs &&
3512 ST_EXEC_MODE_CPE == st_ses->exec_mode &&
3513 !st_hw_ses->is_generic_event) {
3514 payload_ptr = payload;
3515 payload_ptr += 2; /* Skip minor_version and num_active_models */
3516 payload_size -= 2;
3517 } else {
3518 payload_ptr = payload;
3519 }
3520 status = generate_legacy_st_phrase_recognition_event(
3521 stc_ses->phrase_sm, stc_ses->rc_config, payload_ptr,
3522 payload_size, &local_event);
3523
3524 if (status)
3525 goto exit;
3526 } else {
3527 ALOGD("%s: Send detection payload as is", __func__);
3528
3529 local_event = calloc(1, sizeof(*local_event) + payload_size);
3530 if (!local_event) {
3531 ALOGE("%s: event allocation failed, size %zd", __func__,
3532 payload_size);
3533 status = -ENOMEM;
3534 goto exit;
3535 }
3536 memcpy(local_event->phrase_extras,
3537 stc_ses->rc_config->phrases, stc_ses->rc_config->num_phrases *
3538 sizeof(struct sound_trigger_phrase_recognition_extra));
3539 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3540 local_event->common.data_offset = sizeof(*local_event);
3541 local_event->common.data_size = payload_size;
3542 memcpy((char *)local_event + local_event->common.data_offset,
3543 payload, payload_size);
3544 }
3545 }
3546
3547 /* fill the remaining recognition event parameters not specific
3548 to soundmodel lib */
3549 local_event->common.status = detect_status;
3550 local_event->common.type = stc_ses->phrase_sm->common.type;
3551 local_event->common.model = stc_ses->sm_handle;
3552 local_event->common.capture_available =
3553 stc_ses->rc_config->capture_requested;
3554 local_event->common.capture_delay_ms = 0;
3555 local_event->common.capture_preamble_ms = 0;
3556 local_event->common.audio_config.sample_rate =
3557 SOUND_TRIGGER_SAMPLING_RATE_16000;
3558 local_event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
3559 local_event->common.audio_config.channel_mask =
3560 audio_channel_in_mask_from_count(st_hw_ses->config.channels);
3561
3562 for (i = 0; i < local_event->num_phrases; ++i) {
3563 ALOGV("%s: [%d] kw_id %d level %d", __func__, i,
3564 local_event->phrase_extras[i].id,
3565 local_event->phrase_extras[i].confidence_level);
3566 for (j = 0; j < local_event->phrase_extras[i].num_levels; ++j) {
3567 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
3568 local_event->phrase_extras[i].levels[j].user_id,
3569 local_event->phrase_extras[i].levels[j].level);
3570 }
3571 }
3572
3573 ALOGI("%s:[c%d]", __func__, stc_ses->sm_handle);
3574
3575 ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
3576 "num_phrases=%d id=%d", __func__, stc_ses->sm_handle,
3577 local_event->common.status, local_event->common.type,
3578 local_event->common.model, local_event->common.capture_available,
3579 local_event->num_phrases, local_event->phrase_extras[0].id);
3580
3581 *event = local_event;
3582 return 0;
3583
3584err_exit:
3585 if (local_event)
3586 free(local_event);
3587
3588exit:
3589 return status;
3590}
3591
3592static int process_detection_event_generic(st_proxy_session_t *st_ses,
3593 int detect_status,
3594 void *payload, size_t payload_size,
3595 struct sound_trigger_recognition_event **event)
3596{
3597 st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
3598 st_session_t *stc_ses = st_ses->det_stc_ses;
3599 struct st_vendor_info *v_info = st_ses->vendor_uuid_info;
3600 int status = 0;
3601 struct sound_trigger_recognition_event *local_event = NULL;
3602
3603 local_event = calloc(1, sizeof(*local_event) + payload_size);
3604 if (!local_event) {
3605 ALOGE("%s: event allocation failed, size %zd", __func__,
3606 payload_size);
3607 status = -ENOMEM;
3608 goto exit;
3609 }
3610
3611 local_event->status = detect_status;
3612 local_event->type = stc_ses->sm_type;
3613 local_event->model = stc_ses->sm_handle;
3614 local_event->capture_available = stc_ses->rc_config->capture_requested;
3615 local_event->capture_delay_ms = 0;
3616 local_event->capture_preamble_ms = 0;
3617 local_event->audio_config.sample_rate = v_info ?
3618 v_info->sample_rate : SOUND_TRIGGER_SAMPLING_RATE_16000;
3619 local_event->audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
3620 local_event->audio_config.channel_mask =
3621 audio_channel_in_mask_from_count(st_hw_ses->config.channels);
3622
3623 local_event->data_offset = sizeof(*local_event);
3624 local_event->data_size = payload_size;
3625 memcpy((char *)local_event + local_event->data_offset,
3626 payload, payload_size);
3627
3628 ALOGI("%s:[%d]", __func__, stc_ses->sm_handle);
3629 ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d",
3630 __func__, stc_ses->sm_handle, local_event->status,
3631 local_event->type, local_event->model,
3632 local_event->capture_available);
3633
3634 *event = local_event;
3635
3636exit:
3637 return status;
3638}
3639
3640static inline int process_detection_event(st_proxy_session_t *st_ses,
3641 uint64_t timestamp __unused,
3642 int detect_status,
3643 void *payload, size_t payload_size,
3644 struct sound_trigger_recognition_event **event)
3645{
3646 int ret;
3647 struct sound_trigger_phrase_recognition_event *phrase_event = NULL;
3648
3649 *event = NULL;
3650 if (st_ses->sm_info.sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
3651 if (sthw_extn_check_process_det_ev_support())
3652 ret = sthw_extn_process_detection_event_keyphrase(st_ses,
3653 timestamp, detect_status, payload, payload_size, &phrase_event);
3654 else if (st_ses->hw_ses_current->is_generic_event &&
3655 !st_ses->vendor_uuid_info->is_qcmd_uuid)
3656 ret = process_detection_event_keyphrase_v2(st_ses, detect_status,
3657 payload, payload_size, &phrase_event);
3658 else
3659 ret = process_detection_event_keyphrase(st_ses, detect_status,
3660 payload, payload_size, &phrase_event);
3661 if (phrase_event)
3662 *event = &phrase_event->common;
3663 } else {
3664 ret = process_detection_event_generic(st_ses, detect_status, payload,
3665 payload_size, event);
3666 }
3667 return ret;
3668}
3669
3670
3671/*
3672 * If the keyword detection session detects before the user verification
3673 * session, signal to process user verification. If the keyword detection
3674 * session rejects before the user verification session, signal to stop
3675 * processing user verification.
3676 */
3677static void handle_vop_pending_detection(st_arm_ss_session_t *ss_session,
3678 unsigned int det_status, unsigned int kw_det_buff_sz)
3679{
3680 if (det_status & KEYWORD_DETECTION_SUCCESS) {
3681 if (kw_det_buff_sz > ss_session->unread_bytes)
3682 ss_session->buff_sz = kw_det_buff_sz;
3683 else
3684 ss_session->buff_sz = ss_session->unread_bytes;
3685
3686 /*
3687 * It is possible that VOP started processing by already consuming
3688 * data from unread_bytes while CNN detects. In this case, it does
3689 * not need to be signaled.
3690 */
3691 if (ss_session->unread_bytes >= ss_session->buff_sz) {
3692 ALOGD("%s: Processing UV due to KW detection success", __func__);
3693 pthread_cond_signal(&ss_session->cond);
3694 }
3695 } else if (det_status & KEYWORD_DETECTION_REJECT) {
3696 ss_session->exit_buffering = true;
3697 ALOGD("%s: Exiting from UV due to KW detection rejection", __func__);
3698 pthread_cond_signal(&ss_session->cond);
3699 }
3700}
3701
3702/*
3703 * If the user verification session rejects before the keyword detection
3704 * session, signal to stop processing keyword detection.
3705 */
3706static void handle_cnn_pending_detection(st_arm_ss_session_t *ss_session,
3707 unsigned int det_status)
3708{
3709 if (det_status & USER_VERIFICATION_REJECT) {
3710 ss_session->exit_buffering = true;
3711 ALOGD("%s: Exiting from KW detection due to UV rejection", __func__);
3712 pthread_cond_signal(&ss_session->cond);
3713 }
3714}
3715
3716/*
3717 * This thread handles detection events from the second stage sessions
3718 * and aggregates them into 1 final decision. It will call the client callback
3719 * or restart the first stage session based on this decision.
3720 */
3721static void *aggregator_thread_loop(void *st_session)
3722{
3723 st_proxy_session_t *st_ses = (st_proxy_session_t *)st_session;
3724 st_session_t *stc_ses = NULL;
3725 recognition_callback_t callback = NULL;
3726 void *cookie = NULL;
3727 struct listnode *node = NULL;
3728 st_arm_second_stage_t *st_sec_stage = NULL;
3729 int status = 0, lock_status = 0;
3730 unsigned int kw_det_buff_sz = 0, det_status = 0;
3731 struct timespec tspec = {0};
3732 struct sound_trigger_recognition_event *event = NULL;
3733 bool capture_requested = false;
Quinn Maled0814de2019-05-29 17:33:22 -07003734 uint64_t callback_time = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003735
3736 ALOGV("%s: Enter", __func__);
3737
3738 /*
3739 * For multi-clients it is expected only one of the clients detection
3740 * happens at a time. Continue processing on a run time detected client
3741 */
3742 pthread_mutex_lock(&st_ses->ss_detections_lock);
3743 while (!st_ses->exit_aggregator_loop) {
3744 det_status = 0;
3745 lock_status = 0;
3746 ALOGV("%s: waiting on cond", __func__);
3747 pthread_cond_wait(&st_ses->ss_detections_cond,
3748 &st_ses->ss_detections_lock);
3749 ALOGV("%s: done waiting on cond", __func__);
3750 if (st_ses->exit_aggregator_loop) {
3751 ALOGV("%s: exit", __func__);
3752 pthread_mutex_unlock(&st_ses->ss_detections_lock);
3753 return NULL;
3754 }
3755 if (!st_ses->det_stc_ses)
3756 continue;
3757 stc_ses = st_ses->det_stc_ses;
3758
3759 list_for_each(node, &stc_ses->second_stage_list) {
3760 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
3761 list_node);
3762
3763 pthread_mutex_lock(&st_sec_stage->ss_session->lock);
3764 det_status |= st_sec_stage->ss_session->det_status;
3765 if (st_sec_stage->ss_session->det_status ==
3766 KEYWORD_DETECTION_SUCCESS)
3767 kw_det_buff_sz = st_sec_stage->ss_session->bytes_processed;
3768 pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
3769 }
3770
3771 list_for_each(node, &stc_ses->second_stage_list) {
3772 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
3773 list_node);
3774
3775 pthread_mutex_lock(&st_sec_stage->ss_session->lock);
3776 if ((st_sec_stage->ss_info->sm_detection_type ==
3777 ST_SM_TYPE_USER_VERIFICATION) &&
3778 (det_status & USER_VERIFICATION_PENDING)) {
3779 handle_vop_pending_detection(st_sec_stage->ss_session,
3780 det_status, kw_det_buff_sz);
3781 } else if ((st_sec_stage->ss_info->sm_detection_type ==
3782 ST_SM_TYPE_KEYWORD_DETECTION) &&
3783 (det_status & KEYWORD_DETECTION_PENDING)) {
3784 handle_cnn_pending_detection(st_sec_stage->ss_session,
3785 det_status);
3786 }
3787 pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
3788 }
3789
3790 if (!IS_SS_DETECTION_PENDING(det_status)) {
3791 pthread_mutex_lock(&st_ses->lock);
3792 /*
3793 * If the client stops before 2nd stage finishes processing, or a
3794 * transition is in progress, the detection event should not be
3795 * handled.
3796 */
3797 if ((st_ses->current_state != buffering_state_fn) ||
3798 (st_ses->exec_mode == ST_EXEC_MODE_NONE)) {
3799 ALOGW("%s: First stage is not in a valid state, continuing",
3800 __func__);
3801 pthread_mutex_unlock(&st_ses->lock);
3802 continue;
3803 }
3804 if (IS_SS_DETECTION_SUCCESS(det_status)) {
3805 clock_gettime(CLOCK_MONOTONIC, &tspec);
3806 st_ses->hw_ses_current->second_stage_det_event_time =
3807 get_current_time_ns();
3808 ATRACE_ASYNC_END("sthal: detection success",
3809 st_ses->sm_handle);
3810
3811 status = process_detection_event(st_ses,
3812 st_ses->det_session_ev->payload.detected.timestamp,
3813 st_ses->det_session_ev->payload.detected.detect_status,
3814 st_ses->det_session_ev->payload.detected.detect_payload,
3815 st_ses->det_session_ev->payload.detected.payload_size,
3816 &event);
3817 if (status || !event) {
3818 ALOGE("%s:[%d] process_detection_event failed err %d",
3819 __func__, st_ses->sm_handle, status);
3820 /*
3821 * Stop buffering if this is not a successful detection and
3822 * LAB is triggered in hw automatically
3823 */
3824 st_ses->hw_ses_current->fptrs->stop_buffering(
3825 st_ses->hw_ses_current);
3826
3827 pthread_mutex_unlock(&st_ses->lock);
3828 if (event) {
3829 free(event);
3830 event = NULL;
3831 }
3832 goto exit;
3833 }
Venkatesh Mangalappalib4243f42019-08-19 15:25:39 -07003834 stc_ses->detection_sent = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003835 callback = stc_ses->callback;
3836 capture_requested = stc_ses->rc_config->capture_requested;
3837 cookie = stc_ses->cookie;
Quinn Maled0814de2019-05-29 17:33:22 -07003838 callback_time = get_current_time_ns();
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003839 ALOGD("%s:[c%d] Second stage detected successfully, "
3840 "calling client callback", __func__, stc_ses->sm_handle);
Quinn Maled0814de2019-05-29 17:33:22 -07003841 ALOGD("%s: Total sthal processing time: %llums", __func__,
3842 (callback_time - st_ses->detection_event_time) /
3843 NSECS_PER_MSEC);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003844 pthread_mutex_unlock(&st_ses->lock);
3845 ATRACE_BEGIN("sthal: client detection callback");
3846 callback(event, cookie);
3847 free(event);
3848 ATRACE_END();
3849
3850 /*
3851 * The client could unload the sound model during the callback,
3852 * which would join this thread and wait for this thread exit
3853 * as part of st_session_deinit() with st_session_lock held. By
3854 * this time, the state is also moved to idle. To avoid
3855 * deadlock, upon return from client callback, try acquiring
3856 * lock only if not in idle state, else exit right away.
3857 */
3858 do {
3859 lock_status = pthread_mutex_trylock(&st_ses->lock);
3860 } while (lock_status && (st_ses->current_state !=
3861 idle_state_fn));
3862
3863 if (st_ses->current_state == idle_state_fn) {
3864 ALOGV("%s:[%d] client unloaded after callback"
3865 ", lock status %d", __func__, st_ses->sm_handle,
3866 lock_status);
3867 if (!lock_status)
3868 pthread_mutex_unlock(&st_ses->lock);
3869 goto exit;
3870 }
3871 /*
3872 * If client has not requested capture data,
3873 * stop hw session buffering here to resume next
3874 * detection
3875 */
3876 if (!capture_requested)
3877 st_ses->hw_ses_current->fptrs->stop_buffering(
3878 st_ses->hw_ses_current);
3879 } else {
3880 ATRACE_ASYNC_END("sthal: detection reject",
3881 st_ses->sm_handle);
3882 ALOGD("%s: Second stage did NOT detect, restarting st_session",
3883 __func__);
3884 st_ses->hw_ses_current->fptrs->stop_buffering(
3885 st_ses->hw_ses_current);
3886 start_second_stage_for_client(stc_ses);
3887 st_session_ev_t ev = {.ev_id = ST_SES_EV_RESTART,
3888 .stc_ses = stc_ses};
3889 DISPATCH_EVENT(st_ses, ev, status);
3890 }
3891 pthread_mutex_unlock(&st_ses->lock);
3892 } else {
3893 ALOGV("%s: There is a second stage session pending, continuing",
3894 __func__);
3895 }
3896 }
3897exit:
3898 pthread_mutex_unlock(&st_ses->ss_detections_lock);
3899 ALOGV("%s: Exit", __func__);
3900 return NULL;
3901}
3902
3903static void init_det_event_aggregator(st_proxy_session_t *st_ses)
3904{
3905 int status = 0;
3906 pthread_condattr_t attr;
3907
3908 ALOGV("%s", __func__);
3909
3910 st_ses->exit_aggregator_loop = false;
3911 pthread_mutex_init(&st_ses->ss_detections_lock, NULL);
3912 pthread_condattr_init(&attr);
3913 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
3914 pthread_cond_init(&st_ses->ss_detections_cond, &attr);
3915 pthread_condattr_destroy(&attr);
3916 status = pthread_create(&st_ses->aggregator_thread, NULL,
3917 aggregator_thread_loop, st_ses);
3918 if (status) {
3919 ALOGE("%s: Error creating aggregator thread. status = %d",
3920 __func__, status);
3921 } else {
3922 st_ses->aggregator_thread_created = true;
3923 }
3924}
3925
3926static void destroy_det_event_aggregator(st_proxy_session_t *st_ses)
3927{
3928 int status = 0;
3929
3930 ALOGV("%s", __func__);
3931
3932 st_ses->exit_aggregator_loop = true;
3933 pthread_mutex_lock(&st_ses->ss_detections_lock);
3934 pthread_cond_signal(&st_ses->ss_detections_cond);
3935 pthread_mutex_unlock(&st_ses->ss_detections_lock);
3936 status = pthread_join(st_ses->aggregator_thread, NULL);
3937 if (status)
3938 ALOGE("%s: Error joining aggregator thread. status = %d",
3939 __func__, status);
3940 pthread_cond_destroy(&st_ses->ss_detections_cond);
3941 pthread_mutex_destroy(&st_ses->ss_detections_lock);
3942 st_ses->aggregator_thread_created = false;
3943}
3944
3945/* This function is called for multi-client */
3946static int handle_load_sm(st_proxy_session_t *st_ses, st_session_t *stc_ses)
3947{
3948 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male049e47e2019-10-29 16:35:32 -07003949 st_proxy_session_state_fn_t curr_state = st_ses->current_state;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003950 int status = 0;
3951
3952 ALOGV("%s:[c%d-%d]", __func__, stc_ses->sm_handle, st_ses->sm_handle);
3953 if (!stc_ses->phrase_sm) {
3954 ALOGE("%s:[c%d] sound model data is not initialzed", __func__,
3955 stc_ses->sm_handle);
3956 return -EINVAL;
3957 }
3958
3959 if (!is_other_client_attached(st_ses, stc_ses)) {
3960 ALOGE("%s:[c%d] Unexpected without multi-clients", __func__,
3961 stc_ses->sm_handle);
3962 return -EINVAL;
3963 }
3964
3965 if (st_ses->current_state == buffering_state_fn)
3966 hw_ses->fptrs->stop_buffering(hw_ses);
3967
3968 if (st_ses->current_state == active_state_fn ||
3969 st_ses->current_state == detected_state_fn ||
3970 st_ses->current_state == buffering_state_fn) {
3971 status = stop_session(st_ses, hw_ses, false);
3972 if (status)
3973 ALOGE("%s:[%d] stop_session failed %d", __func__, st_ses->sm_handle,
3974 status);
Quinn Male80c1e0d2019-10-21 15:16:54 -07003975 STATE_TRANSITION(st_ses, loaded_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003976 }
3977
3978 status = hw_ses->fptrs->dereg_sm(hw_ses);
3979 if (status) {
3980 ALOGE("%s:[%d] dereg_sm failed %d", __func__,
3981 st_ses->sm_handle, status);
3982 }
3983 /* Continue updating sound model resulting in merged model */
3984 status = update_sound_model(stc_ses, true);
3985 if (status) {
3986 ALOGE("%s:[c%d] update_sound_model add failed %d", __func__,
3987 stc_ses->sm_handle, status);
3988 goto exit;
3989 }
3990 hw_ses->sthw_cfg.conf_levels = st_ses->sm_info.cf_levels;
3991 hw_ses->sthw_cfg.num_conf_levels = st_ses->sm_info.cf_levels_size;
3992 hw_ses->sthw_cfg_updated = true;
3993 /*
3994 * Sound model merge would have changed the order of merge conf levels,
3995 * which need to be re-updated for all current active clients, if any.
3996 */
3997 status = update_merge_conf_levels_payload_with_active_clients(st_ses);
3998 if (status)
3999 goto exit_1;
4000
4001 /* Load merged sound model */
4002 status = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_info.sm_data,
4003 st_ses->sm_info.sm_size, st_ses->sm_info.sm_type);
4004 if (status) {
4005 ALOGE("%s:[%d] reg_sm failed %d", __func__,
4006 st_ses->sm_handle, status);
4007 goto exit_1;
4008 }
4009
Quinn Male049e47e2019-10-29 16:35:32 -07004010 if (curr_state == active_state_fn ||
4011 curr_state == detected_state_fn ||
4012 curr_state == buffering_state_fn) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004013
4014 status = start_session(st_ses, hw_ses, false);
4015 if (status)
4016 goto exit_2;
4017 STATE_TRANSITION(st_ses, active_state_fn);
4018 }
4019
4020 return 0;
4021
4022exit_2:
4023 if (!st_ses->stdev->ssr_offline_received)
4024 hw_ses->fptrs->dereg_sm(hw_ses);
4025
4026exit_1:
4027 if (!st_ses->stdev->ssr_offline_received) {
4028 update_sound_model(stc_ses, false);
4029 update_merge_conf_levels_payload_with_active_clients(st_ses);
4030 }
4031
4032exit:
4033 if (st_ses->stdev->ssr_offline_received) {
4034 STATE_TRANSITION(st_ses, ssr_state_fn);
4035 status = 0;
4036 }
4037 return status;
4038}
4039
4040/* This function is called for multi-client */
4041static int handle_unload_sm(st_proxy_session_t *st_ses, st_session_t *stc_ses)
4042{
4043 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male049e47e2019-10-29 16:35:32 -07004044 st_proxy_session_state_fn_t curr_state = st_ses->current_state;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004045 int status = 0;
4046
4047 ALOGV("%s:[c%d-%d]", __func__, stc_ses->sm_handle, st_ses->sm_handle);
4048
4049 if (!is_other_client_attached(st_ses, stc_ses)) {
4050 ALOGE("%s:[c%d] Unexpected without multi-clients", __func__,
4051 stc_ses->sm_handle);
4052 return -EINVAL;
4053 }
4054
4055 if (st_ses->current_state == buffering_state_fn)
4056 hw_ses->fptrs->stop_buffering(hw_ses);
4057
4058 if (st_ses->current_state == active_state_fn ||
4059 st_ses->current_state == detected_state_fn ||
4060 st_ses->current_state == buffering_state_fn) {
4061 status = stop_session(st_ses, hw_ses, false);
4062 if (status)
4063 ALOGE("%s:[%d] stop_session failed %d", __func__,
4064 st_ses->sm_handle, status);
Quinn Male80c1e0d2019-10-21 15:16:54 -07004065 STATE_TRANSITION(st_ses, loaded_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004066 }
4067
4068 status = hw_ses->fptrs->dereg_sm(hw_ses);
4069 if (status)
4070 ALOGE("%s:[%d] dereg_sm failed %d", __func__, st_ses->sm_handle, status);
4071
4072 /* Continue deleting this model */
4073 status = update_sound_model(stc_ses, false);
4074 if (status)
4075 ALOGE("%s:[c%d] update_sound_model delete failed %d", __func__,
4076 stc_ses->sm_handle, status);
4077
4078 hw_ses->sthw_cfg.conf_levels = st_ses->sm_info.cf_levels;
4079 hw_ses->sthw_cfg.num_conf_levels = st_ses->sm_info.cf_levels_size;
4080 hw_ses->sthw_cfg_updated = true;
4081 /*
4082 * Sound model merge would have changed the order of merge conf levels,
4083 * which need to be re-updated for all current active clients, if any.
4084 */
4085 update_merge_conf_levels_payload_with_active_clients(st_ses);
4086
4087 /* Load remaining merged sound model */
4088 status = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_info.sm_data,
4089 st_ses->sm_info.sm_size, st_ses->sm_info.sm_type);
4090 if (status) {
4091 ALOGE("%s:[%d] reg_sm failed %d", __func__,
4092 st_ses->sm_handle, status);
4093 goto exit;
4094 }
4095
Quinn Male049e47e2019-10-29 16:35:32 -07004096 if (curr_state == active_state_fn ||
4097 curr_state == detected_state_fn ||
4098 curr_state == buffering_state_fn) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004099
4100 status = start_session(st_ses, hw_ses, false);
4101 if (status)
4102 goto exit;
4103 STATE_TRANSITION(st_ses, active_state_fn);
4104 }
4105 return 0;
4106
4107exit:
4108 if (st_ses->stdev->ssr_offline_received) {
4109 STATE_TRANSITION(st_ses, ssr_state_fn);
4110 status = 0;
4111 }
4112 return status;
4113}
4114
4115static int idle_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07004116{
4117 int status = 0;
4118 int ret = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004119 st_session_t *stc_ses = ev->stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07004120 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male2e883752019-03-22 11:28:54 -07004121
4122 /* skip parameter check as this is an internal funciton */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004123 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
4124 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07004125
4126 switch (ev->ev_id) {
4127 case ST_SES_EV_LOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004128 if (!stc_ses->phrase_sm) {
Quinn Male2e883752019-03-22 11:28:54 -07004129 ALOGE("%s: sound model data is not initialzed", __func__);
4130 status = -EINVAL;
4131 break;
4132 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004133 status = update_sound_model(stc_ses, true);
4134 if (status) {
4135 ALOGE("%s:[c%d] update sound model add failed %d", __func__,
4136 stc_ses->sm_handle, status);
4137 status = -EINVAL;
4138 break;
4139 }
Quinn Male2e883752019-03-22 11:28:54 -07004140
4141 /*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004142 * Do retry to handle a corner case that when ADSP SSR ONLINE is
4143 * received, sometimes ADSP is still not ready to receive cmd from HLOS
4144 * and thus fails, so try more times to recover the session from SSR
4145 * state.
Quinn Male2e883752019-03-22 11:28:54 -07004146 */
4147 for (int i = 0; i < REG_SM_RETRY_CNT; i++) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004148 status = ret = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_info.sm_data,
4149 st_ses->sm_info.sm_size, st_ses->sm_info.sm_type);
Quinn Male2e883752019-03-22 11:28:54 -07004150 if (ret) {
4151 if (st_ses->stdev->ssr_offline_received) {
Quinn Male2e883752019-03-22 11:28:54 -07004152 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07004153 status = 0;
4154 break;
4155 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004156 ALOGE("%s:[%d] failed to reg sm, err %d, retry cnt %d",
4157 __func__, st_ses->sm_handle, status, i);
Quinn Male2e883752019-03-22 11:28:54 -07004158 usleep(REG_SM_WAIT_TIME_MS * 1000);
4159 }
4160 } else {
4161 break;
4162 }
4163 }
4164 if (ret)
4165 break;
4166
Quinn Male2e883752019-03-22 11:28:54 -07004167 STATE_TRANSITION(st_ses, loaded_state_fn);
4168 break;
4169
4170 case ST_SES_EV_SET_EXEC_MODE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004171 stc_ses->exec_mode = ev->payload.exec_mode;
4172 if (ev->payload.exec_mode == st_ses->exec_mode)
4173 break;
4174
Quinn Male2e883752019-03-22 11:28:54 -07004175 st_ses->exec_mode = ev->payload.exec_mode;
4176 if (ST_EXEC_MODE_CPE == st_ses->exec_mode)
4177 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
4178 else if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
4179 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
4180 /* remain in current state */
4181 break;
4182
4183 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004184 stc_ses->paused = true;
Quinn Male2e883752019-03-22 11:28:54 -07004185 break;
4186
4187 case ST_SES_EV_RESUME:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004188 stc_ses->paused = false;
Quinn Male2e883752019-03-22 11:28:54 -07004189 break;
4190
4191 case ST_SES_EV_SSR_OFFLINE:
4192 STATE_TRANSITION(st_ses, ssr_state_fn);
4193 break;
4194
4195 case ST_SES_EV_SEND_CHMIX_COEFF:
4196 status = -EIO;
4197 break;
4198
4199 case ST_SES_EV_GET_PARAM_DATA:
4200 status = -EIO;
4201 break;
4202
4203 case ST_SES_EV_REQUEST_DET:
4204 ALOGE("%s:[%d] Event not supported in this state",
4205 __func__, st_ses->sm_handle);
4206 status = -EINVAL;
4207 break;
4208
4209 default:
4210 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
4211 break;
4212 };
4213
4214 return status;
4215}
4216
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004217static int loaded_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07004218{
4219 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004220 st_session_t *stc_ses = ev->stc_ses;
4221 struct listnode *node = NULL;
4222 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07004223 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
4224 st_hw_session_t *new_hw_ses = NULL;
4225 st_exec_mode_t new_exec_mode = 0;
Quinn Male2e883752019-03-22 11:28:54 -07004226
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004227 /* skip parameter check as this is an internal function */
4228 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
4229 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07004230
4231 switch (ev->ev_id) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004232 case ST_SES_EV_LOAD_SM:
4233 /* Valid only in multi-client session usecase */
4234 status = handle_load_sm(st_ses, stc_ses);
Quinn Male2e883752019-03-22 11:28:54 -07004235 break;
4236
4237 case ST_SES_EV_UNLOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004238 if (is_other_client_attached(st_ses, stc_ses)) {
4239 status = handle_unload_sm(st_ses, stc_ses);
4240 break;
Quinn Male2e883752019-03-22 11:28:54 -07004241 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004242
4243 status = hw_ses->fptrs->dereg_sm(hw_ses);
4244 if (status)
4245 ALOGE("%s:[%d] dereg_sm failed %d", __func__,
4246 st_ses->sm_handle, status);
4247
4248 status = update_sound_model(stc_ses, false);
4249 if (status)
4250 ALOGE("%s:[c%d] update_sound_model failed %d", __func__,
4251 stc_ses->sm_handle, status);
4252
4253 /* since this is a teardown scenario dont fail here */
4254 status = 0;
Quinn Male2e883752019-03-22 11:28:54 -07004255 STATE_TRANSITION(st_ses, idle_state_fn);
4256 break;
4257
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004258 case ST_SES_EV_RESUME:
4259 stc_ses->paused = false;
Quinn Male60ca2022019-08-21 17:10:25 -07004260 if (!is_any_client_in_state(st_ses, ST_STATE_ACTIVE)) {
4261 /*
4262 * When a transition is needed due to lpi mode or barge-in mode,
4263 * call dereg_sm and reg_sm to select the updated lsm_usecase.
4264 */
4265 if (hw_ses->lpi_enable != hw_ses->stdev->lpi_enable ||
4266 (hw_ses->barge_in_mode != hw_ses->stdev->barge_in_mode &&
4267 !hw_ses->stdev->support_dynamic_ec_update)) {
4268
4269 hw_ses->lpi_enable = hw_ses->stdev->lpi_enable;
4270 hw_ses->barge_in_mode = hw_ses->stdev->barge_in_mode;
4271
4272 status = hw_ses->fptrs->dereg_sm(hw_ses);
4273 if (status) {
4274 ALOGE("%s:[%d] failed to dereg_sm err %d", __func__,
4275 st_ses->sm_handle, status);
4276 break;
4277 }
4278
4279 status = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_info.sm_data,
4280 st_ses->sm_info.sm_size, st_ses->sm_info.sm_type);
4281 if (status) {
4282 ALOGE("%s:[%d] failed to reg_sm err %d", __func__,
4283 st_ses->sm_handle, status);
4284 STATE_TRANSITION(st_ses, idle_state_fn);
4285 }
4286 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004287 break;
Quinn Male60ca2022019-08-21 17:10:25 -07004288 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004289 /* Fall through */
4290 case ST_SES_EV_START:
4291 case ST_SES_EV_RESTART:
4292 if (ev->ev_id == ST_SES_EV_RESTART)
4293 update_hw_config_on_restart(st_ses, stc_ses);
4294
4295 /*
4296 * During Resume, the first active client will start the hw sesison.
4297 * During Start, check for any paused sessions to delay actual start
4298 * to Resume.
4299 */
4300 if ((ev->ev_id != ST_SES_EV_RESUME) && is_any_client_paused(st_ses))
4301 break;
4302
4303 status = start_session(st_ses, hw_ses, false);
4304 if (status) {
4305 if (st_ses->stdev->ssr_offline_received) {
4306 hw_ses->fptrs->dereg_sm(hw_ses);
4307 STATE_TRANSITION(st_ses, ssr_state_fn);
4308 status = 0;
4309 } else {
4310 ALOGE("%s:[%d] failed to start session, err %d", __func__,
4311 st_ses->sm_handle, status);
4312 }
4313 break;
4314 }
4315 STATE_TRANSITION(st_ses, active_state_fn);
4316 break;
4317
4318 case ST_SES_EV_STOP:
4319 /*
4320 * Valid in multi-client case.
4321 * Reconfig based off other active clients, if any, so that RESUME
4322 * can apply this reconfig.
4323 */
4324 update_hw_config_on_stop(st_ses, stc_ses);
4325 break;
4326
Quinn Male2e883752019-03-22 11:28:54 -07004327 case ST_SES_EV_SSR_OFFLINE:
Quinn Male2e883752019-03-22 11:28:54 -07004328 /* exec mode can be none if ssr occurs during a transition */
4329 if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004330 hw_ses->fptrs->dereg_sm(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07004331 STATE_TRANSITION(st_ses, ssr_state_fn);
4332 break;
4333
4334 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004335 stc_ses->paused = true;
Quinn Male2e883752019-03-22 11:28:54 -07004336 break;
4337
4338 case ST_SES_EV_SET_EXEC_MODE:
4339 new_exec_mode = ev->payload.exec_mode;
4340
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004341 if (new_exec_mode == st_ses->exec_mode) {
4342 stc_ses->exec_mode = st_ses->exec_mode;
4343 break;
Quinn Male2e883752019-03-22 11:28:54 -07004344 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004345
4346 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
4347 st_ses->exec_mode = ST_EXEC_MODE_NONE;
4348 list_for_each(node, &st_ses->clients_list) {
4349 c_ses = node_to_item(node, st_session_t, hw_list_node);
4350 c_ses->exec_mode = ST_EXEC_MODE_NONE;
4351 }
4352 /* unload sm for current hw session */
4353 status = hw_ses->fptrs->dereg_sm(hw_ses);
4354 if (status) {
4355 ALOGE("%s:[%d] dereg_sm failed with err %d", __func__,
4356 st_ses->sm_handle, status);
4357 break;
4358 }
4359 }
4360
4361 if (new_exec_mode == ST_EXEC_MODE_NONE)
4362 break;
4363
4364 /* load sm to new hw_ses */
4365 if (ST_EXEC_MODE_CPE == new_exec_mode) {
4366 new_hw_ses = st_ses->hw_ses_cpe;
4367 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
4368 new_hw_ses = st_ses->hw_ses_adsp;
4369 } else {
4370 ALOGE("%s: unknown execution mode %d", __func__,
4371 new_exec_mode);
4372 status = -EINVAL;
4373 break;
4374 }
4375
4376 status = new_hw_ses->fptrs->reg_sm(new_hw_ses,
4377 st_ses->sm_info.sm_data, st_ses->sm_info.sm_size,
4378 st_ses->sm_info.sm_type);
4379 if (status) {
4380 ALOGE("%s:[%d] reg_sm failed with err %d", __func__,
4381 st_ses->sm_handle, status);
4382 break;
4383 }
4384 /* switch hw sessions only if successful*/
4385 list_for_each(node, &st_ses->clients_list) {
4386 c_ses = node_to_item(node, st_session_t, hw_list_node);
4387 c_ses->exec_mode = new_exec_mode;
4388 if (c_ses->state == ST_STATE_ACTIVE) {
4389 dereg_hal_event_session(c_ses);
4390 reg_hal_event_session(c_ses, new_hw_ses);
4391 }
4392 }
4393 st_ses->exec_mode = new_exec_mode;
4394 st_ses->hw_ses_current = new_hw_ses;
4395 /* remain in current state */
Quinn Male2e883752019-03-22 11:28:54 -07004396 break;
4397
4398 case ST_SES_EV_SET_DEVICE:
4399 /*
4400 * This event handling is needed for certain graphs which
4401 * have multiple buffering modules with a single voice wakeup
4402 * module in each usecase.
4403 */
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07004404 if (!ev->payload.enable) {
Quinn Male2e883752019-03-22 11:28:54 -07004405 status = hw_ses->fptrs->disable_device(hw_ses, false);
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07004406 } else {
Quinn Male2e883752019-03-22 11:28:54 -07004407 status = hw_ses->fptrs->enable_device(hw_ses, false);
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07004408 /*
4409 * Device switch might happen during active buffering.
4410 * If any client is active, start hw session.
4411 */
4412 if (is_any_client_in_state(st_ses, ST_STATE_ACTIVE)) {
4413 st_session_ev_t start_ev = {.ev_id = ST_SES_EV_START,
4414 .stc_ses = stc_ses};
4415 DISPATCH_EVENT(st_ses, start_ev, status);
4416 }
4417 }
Quinn Male2e883752019-03-22 11:28:54 -07004418
4419 break;
4420
4421 case ST_SES_EV_READ_PCM:
4422 /*
4423 * set status to failure this will tell AHAL to
4424 * provide zero buffers to client
4425 */
4426 status = -EIO;
4427 break;
4428
4429 case ST_SES_EV_SEND_CHMIX_COEFF:
4430 status = -EIO;
4431 break;
4432
4433 case ST_SES_EV_GET_PARAM_DATA:
4434 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004435 ev->payload.getparam.param, ev->payload.getparam.payload,
4436 ev->payload.getparam.payload_size,
4437 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07004438 break;
4439
4440 case ST_SES_EV_REQUEST_DET:
4441 ALOGE("%s:[%d] Event not supported in this state",
4442 __func__, st_ses->sm_handle);
4443 status = -EINVAL;
4444 break;
4445
4446 default:
4447 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
4448 break;
Quinn Male2e883752019-03-22 11:28:54 -07004449 };
4450
4451 return status;
Quinn Male2e883752019-03-22 11:28:54 -07004452}
4453
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004454static int active_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07004455{
4456 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004457 st_session_t *stc_ses = ev->stc_ses;
4458 struct listnode *node = NULL;
4459 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07004460 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male2e883752019-03-22 11:28:54 -07004461 st_hw_session_t *new_hw_ses = NULL;
4462 st_exec_mode_t new_exec_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004463 st_arm_second_stage_t *st_sec_stage = NULL;
4464 struct sound_trigger_recognition_event *event = NULL;
4465 recognition_callback_t callback = NULL;
4466 void *cookie = NULL;
4467 bool lab_enabled = false, enable_second_stage = false, active = false;
Quinn Male2e883752019-03-22 11:28:54 -07004468
4469 /* skip parameter check as this is an internal funciton */
4470 ALOGD("%s:[%d] handle event id %d", __func__, st_ses->sm_handle, ev->ev_id);
4471
4472 switch (ev->ev_id) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004473 case ST_SES_EV_LOAD_SM:
4474 /* Valid in multi-client usecase */
4475 status = handle_load_sm(st_ses, stc_ses);
4476 break;
4477
4478 case ST_SES_EV_UNLOAD_SM:
4479 /* Valid in multi-client usecase */
4480 status = handle_unload_sm(st_ses, stc_ses);
4481 break;
4482
4483 case ST_SES_EV_RESTART:
4484 /* Valid in multi-client usecase */
4485 update_hw_config_on_restart(st_ses, stc_ses);
4486 /* Fall through */
4487 case ST_SES_EV_START:
4488 /* Valid in multi-client usecase */
4489 status = stop_session(st_ses, hw_ses, false);
4490 if (!status) {
4491 status = start_session(st_ses, hw_ses, false);
4492 if (status)
4493 ALOGE("%s:[%d] start_session failed %d", __func__,
4494 st_ses->sm_handle, status);
4495 } else {
4496 ALOGE("%s:[%d] stop_session failed %d", __func__,
4497 st_ses->sm_handle, status);
4498 }
4499 if (status & st_ses->stdev->ssr_offline_received) {
4500 hw_ses->fptrs->dereg_sm(hw_ses);
4501 STATE_TRANSITION(st_ses, ssr_state_fn);
4502 status = 0;
4503 }
4504 break;
4505
Quinn Male2e883752019-03-22 11:28:54 -07004506 case ST_SES_EV_SET_EXEC_MODE:
4507 new_exec_mode = ev->payload.exec_mode;
4508
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004509 if (new_exec_mode == st_ses->exec_mode) {
4510 stc_ses->exec_mode = st_ses->exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07004511 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004512 }
Quinn Male2e883752019-03-22 11:28:54 -07004513
4514 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
4515 ALOGV("%s: disable current session", __func__);
4516 st_ses->exec_mode = ST_EXEC_MODE_NONE;
4517 status = stop_session(st_ses, hw_ses, true);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004518 list_for_each(node, &st_ses->clients_list) {
4519 c_ses = node_to_item(node, st_session_t, hw_list_node);
4520 c_ses->exec_mode = ST_EXEC_MODE_NONE;
4521 }
Quinn Male2e883752019-03-22 11:28:54 -07004522 if (status)
4523 break;
4524 }
4525
4526 if (new_exec_mode == ST_EXEC_MODE_NONE)
4527 break;
4528
4529 if (ST_EXEC_MODE_CPE == new_exec_mode) {
4530 new_hw_ses = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07004531 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
4532 new_hw_ses = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07004533 } else {
4534 ALOGE("%s: unknown execution mode %d", __func__,
4535 new_exec_mode);
4536 status = -EINVAL;
4537 break;
4538 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004539 /*
4540 * hw session changed to/from WDSP/ADSP, hence update the
4541 * related config.
4542 * Not applicable for LPI<->non-LPI transtions as hw session
4543 * doesn't change.
4544 */
4545 status = update_hw_config_on_start(stc_ses, new_hw_ses);
4546 if (status) {
4547 ALOGE("%s: Update_hw_config_on_start failed %d",
4548 __func__, status);
4549 break;
4550 }
Quinn Male2e883752019-03-22 11:28:54 -07004551
4552 ALOGV("%s: enable current session", __func__);
4553 status = start_session(st_ses, new_hw_ses, true);
4554 if (status)
4555 break;
4556
4557 /* set new exec mode and current session */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004558 list_for_each(node, &st_ses->clients_list) {
4559 c_ses = node_to_item(node, st_session_t, hw_list_node);
4560 c_ses->exec_mode = new_exec_mode;
4561 if (c_ses->state == ST_STATE_ACTIVE) {
4562 dereg_hal_event_session(c_ses);
4563 reg_hal_event_session(c_ses, new_hw_ses);
4564 }
4565 }
Quinn Male2e883752019-03-22 11:28:54 -07004566 st_ses->exec_mode = new_exec_mode;
4567 st_ses->hw_ses_current = new_hw_ses;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004568
Quinn Male2e883752019-03-22 11:28:54 -07004569 ALOGV("%s: end transition", __func__);
4570 break;
4571
4572 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004573 /*
4574 * For multi-client, the first active pausing client stops the hw
4575 * session and moves to loaded state.
4576 */
4577 stc_ses->paused = true;
4578 if (stc_ses->state != ST_STATE_ACTIVE)
4579 break;
4580
Quinn Male2e883752019-03-22 11:28:54 -07004581 status = stop_session(st_ses, hw_ses, false);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004582
Quinn Male2e883752019-03-22 11:28:54 -07004583 if (status) {
4584 if (st_ses->stdev->ssr_offline_received) {
4585 STATE_TRANSITION(st_ses, ssr_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004586 hw_ses->fptrs->dereg_sm(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07004587 status = 0;
4588 } else {
4589 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
4590 st_ses->sm_handle, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004591 /* Move anyway to loaded state */
4592 STATE_TRANSITION(st_ses, loaded_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07004593 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004594 break;
Quinn Male2e883752019-03-22 11:28:54 -07004595 }
Quinn Male2e883752019-03-22 11:28:54 -07004596 STATE_TRANSITION(st_ses, loaded_state_fn);
4597 break;
4598
Zhou Song5d413d72019-11-13 17:47:24 +08004599 case ST_SES_EV_RESUME:
4600 if (stc_ses->paused == true)
4601 stc_ses->paused = false;
4602 break;
4603
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004604 case ST_SES_EV_STOP:
4605 status = stop_session(st_ses, hw_ses, false);
4606 if (status)
4607 ALOGE("%s:[%d] start_session failed %d", __func__,
4608 st_ses->sm_handle, status);
Quinn Male2e883752019-03-22 11:28:54 -07004609
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004610 /* Continue to reconfig based off other active clients, if any */
4611 active = update_hw_config_on_stop(st_ses, stc_ses);
4612
4613 if (!status) {
4614 if (active) {
4615 ALOGD("%s: client c%d stopped, start %d due to reconfig",
4616 __func__, stc_ses->sm_handle, st_ses->sm_handle);
4617 status = start_session(st_ses, hw_ses, false);
4618 if (status)
4619 ALOGE("%s:[%d] start_session failed %d", __func__,
Quinn Male2e883752019-03-22 11:28:54 -07004620 st_ses->sm_handle, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004621 /* Stay in active state */
Quinn Male2e883752019-03-22 11:28:54 -07004622 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004623 STATE_TRANSITION(st_ses, loaded_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07004624 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004625 }
Quinn Male2e883752019-03-22 11:28:54 -07004626
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004627 if (status) {
4628 if (st_ses->stdev->ssr_offline_received) {
4629 hw_ses->fptrs->dereg_sm(hw_ses);
4630 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07004631 status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004632 } else {
4633 STATE_TRANSITION(st_ses, loaded_state_fn);
4634 }
4635 }
4636
4637 break;
4638
4639 case ST_SES_EV_DETECTED:
Quinn Maled0814de2019-05-29 17:33:22 -07004640
4641 st_ses->detection_event_time = get_current_time_ns();
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004642 /*
4643 * Find which client is this detection for.
4644 * Note that only one keyword detection can happen at a time.
4645 */
4646 stc_ses = get_detected_client(st_ses,
4647 ev->payload.detected.detect_payload,
4648 ev->payload.detected.payload_size);
4649
4650 if (!stc_ses) {
4651 ALOGW("%s:[%d] Couldn't find a matching client for detection",
4652 __func__, st_ses->sm_handle);
4653 /*
4654 * Though we set higest conf level 100 for inactive client in merged
4655 * sound model, it may be possible it still detects. In case the lab
4656 * is enabled due to other active client, stop hw buffering.
4657 */
4658 if (st_ses->lab_enabled)
4659 hw_ses->fptrs->stop_buffering(hw_ses);
4660 break;
4661 }
4662 st_ses->det_stc_ses = stc_ses;
4663 st_ses->hw_ses_current->enable_second_stage = false; /* Initialize */
Venkatesh Mangalappalib4243f42019-08-19 15:25:39 -07004664 stc_ses->detection_sent = false;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004665
4666 if (list_empty(&stc_ses->second_stage_list) ||
4667 st_ses->detection_requested) {
4668 st_ses->detection_requested = false;
4669 status = process_detection_event(st_ses,
4670 ev->payload.detected.timestamp,
4671 ev->payload.detected.detect_status,
4672 ev->payload.detected.detect_payload,
4673 ev->payload.detected.payload_size,
4674 &event);
4675 if (status || !event) {
4676 ALOGE("%s:[%d] process_detection_event failed err %d", __func__,
4677 st_ses->sm_handle, status);
4678 /*
4679 * Stop buffering if this is not a successful detection and
4680 * LAB is triggered in hw automatically
4681 */
4682 hw_ses->fptrs->stop_buffering(hw_ses);
4683 if (event)
4684 free(event);
Quinn Male2e883752019-03-22 11:28:54 -07004685 break;
4686 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004687 } else {
4688 ALOGV("%s:[c%d] second stage enabled, list_empty %d,"
4689 "det_requested %d", __func__, stc_ses->sm_handle,
4690 list_empty(&stc_ses->second_stage_list),
4691 st_ses->detection_requested);
Quinn Male2e883752019-03-22 11:28:54 -07004692
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004693 enable_second_stage = true;
Quinn Male2e883752019-03-22 11:28:54 -07004694 /*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004695 * Before first stage starts buffering, update the second stage info
4696 * to first stage layer for further communication between first and
4697 * second stage layers.
Quinn Male2e883752019-03-22 11:28:54 -07004698 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004699 st_ses->hw_ses_current->enable_second_stage = true;
4700 st_ses->hw_ses_current->second_stage_list =
4701 &(stc_ses->second_stage_list);
Quinn Male2e883752019-03-22 11:28:54 -07004702
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004703 list_for_each(node, &stc_ses->second_stage_list) {
4704 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
4705 list_node);
4706 st_sec_stage->ss_session->st_ses = st_ses;
4707 }
4708 get_first_stage_detection_params(st_ses,
4709 ev->payload.detected.detect_payload,
4710 ev->payload.detected.payload_size);
4711 memcpy(st_ses->det_session_ev, ev, sizeof(st_session_ev_t));
4712 }
4713 /*
4714 * change to new state before invoking user callback, this will
4715 * ensure that if user calls start_recognition immediately from the
4716 * callback it will be handled by one of the two states below
4717 */
4718 if (!status && st_ses->lab_enabled) {
4719 if (stc_ses->rc_config->capture_requested ||
4720 !list_empty(&stc_ses->second_stage_list)) {
Quinn Maleaba13db2019-07-11 15:52:14 -07004721 if (st_ses->stdev->enable_debug_dumps) {
4722 ST_DBG_FILE_OPEN_WR(st_ses->lab_fp, ST_DEBUG_DUMP_LOCATION,
4723 "lab_capture", "bin", file_cnt++);
4724 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004725 STATE_TRANSITION(st_ses, buffering_state_fn);
4726 lab_enabled = true;
4727 } else {
4728 /*
4729 * for merged model case the client detected may not have
4730 * requested the capture nor enabled the second stage, but the
4731 * hw lab could be enabled due to other client requested capture
4732 * or enabled second stage.
4733 */
4734 ALOGV("%s: stop buffering as c%d doesn't need", __func__,
4735 stc_ses->sm_handle);
4736 hw_ses->fptrs->stop_buffering(hw_ses);
4737 STATE_TRANSITION(st_ses, detected_state_fn);
4738 lab_enabled = false;
4739 }
4740 } else {
4741 STATE_TRANSITION(st_ses, detected_state_fn);
4742 }
4743
4744 if (!stc_ses->callback) {
4745 ALOGE("%s:[c%d] received detection event but no callback",
4746 __func__, stc_ses->sm_handle);
4747 status = -EINVAL;
4748 if (event)
Quinn Male2e883752019-03-22 11:28:54 -07004749 free(event);
4750 break;
4751 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004752 /*
4753 * callback to user, assumption is that client does not
4754 * block in the callback waiting for data otherwise will be a deadlock.
4755 * If second stage is enabled, the detection will be sent later when
4756 * second stage successfully detects.
4757 */
4758 if (!enable_second_stage) {
Venkatesh Mangalappalib4243f42019-08-19 15:25:39 -07004759 stc_ses->detection_sent = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004760 callback = stc_ses->callback;
4761 cookie = stc_ses->cookie;
4762 ALOGD("%s:[c%d] invoking the client callback",
4763 __func__, stc_ses->sm_handle);
4764 ATRACE_ASYNC_END("sthal: detection success",
4765 st_ses->sm_handle);
4766 pthread_mutex_unlock(&st_ses->lock);
4767 ATRACE_BEGIN("sthal: client detection callback");
4768 callback(event, cookie);
4769 ATRACE_END();
4770 } else {
4771 pthread_mutex_unlock(&st_ses->lock);
4772 }
4773 if (event)
4774 free(event);
4775
4776 /*
4777 * TODO: Add RECOGNITION_STATUS_GET_STATE_RESPONSE to
4778 * the SoundTrigger API header.
4779 */
4780 if (lab_enabled &&
4781 ((ev->payload.detected.detect_status ==
4782 RECOGNITION_STATUS_SUCCESS) ||
4783 (ev->payload.detected.detect_status == 3))) {
4784 /* Cache lab data to internal buffers (blocking call) */
4785 hw_ses->fptrs->process_lab_capture(hw_ses);
4786 }
4787
4788 /*
4789 * It is possible that the client may start/stop/unload the session
4790 * with the same lock held, before we aqcuire lock here.
4791 * We need further processing only if client starts in detected state
4792 * or buffering state if lab was enabled, else return gracefully.
4793 * For multi-client scenario, only one client is assumed to be
4794 * detected/bufffering, so the logic remains same.
4795 */
4796 do {
4797 status = pthread_mutex_trylock(&st_ses->lock);
4798 } while (status && ((st_ses->current_state == detected_state_fn) ||
Zhou Songafcefe02019-08-27 22:53:09 +08004799 (st_ses->current_state == buffering_state_fn)) &&
4800 !st_ses->stdev->ssr_offline_received);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004801
4802 if (st_ses->current_state != detected_state_fn) {
4803 ALOGV("%s:[%d] client not in detected state, lock status %d",
4804 __func__, st_ses->sm_handle, status);
4805 if (!status) {
4806 /*
Venkatesh Mangalappalib4243f42019-08-19 15:25:39 -07004807 * If detection is sent to client while in buffering state,
4808 * and if internal buffering is stopped due to errors, stop
4809 * session internally as client is expected to restart the
4810 * detection if required.
4811 * Note: It is possible that detection event is not sent to
4812 * client if second stage is not yet detected during internal
4813 * buffering stop, in which case restart is posted from second
Zhou Song58192042020-02-12 10:39:13 +08004814 * stage thread for further detections. Only if the second
4815 * stage detection hasn't be started due to internal buffering
4816 * stop too early, restart session should be explictily issued.
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004817 */
Zhou Song58192042020-02-12 10:39:13 +08004818 if (st_ses->current_state == buffering_state_fn) {
4819 if (stc_ses->detection_sent) {
4820 if (!stc_ses->pending_stop) {
4821 ALOGD("%s:[%d] buffering stopped internally, post c%d stop",
4822 __func__, st_ses->sm_handle,
4823 st_ses->det_stc_ses->sm_handle);
4824 status = hw_session_notifier_enqueue(stc_ses->sm_handle,
4825 ST_SES_EV_DEFERRED_STOP,
4826 ST_SES_DEFERRED_STOP_SS_DELAY_MS);
4827 if (!status)
4828 stc_ses->pending_stop = true;
4829 }
4830 } else {
4831 list_for_each(node, &stc_ses->second_stage_list) {
4832 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
4833 list_node);
4834 if (!st_sec_stage->ss_session->start_processing) {
4835 st_session_ev_t ev = {.ev_id = ST_SES_EV_RESTART,
4836 .stc_ses = stc_ses};
4837 DISPATCH_EVENT(st_ses, ev, status);
4838 break;
4839 }
4840 }
4841 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004842 }
4843 pthread_mutex_unlock(&st_ses->lock);
4844 }
4845 status = 0;
4846 break;
4847 }
4848
4849 /*
4850 * If we are not buffering (i.e capture is not requested), then
4851 * trigger a deferred stop. Most applications issue (re)start
4852 * almost immediately. Delaying stop allows unnecessary teardown
4853 * and reinitialization of backend.
4854 */
4855 if (!lab_enabled) {
4856 /*
4857 * Note that this event will only be posted to the detected state
4858 * The current state may switch to active if the client
4859 * issues start/restart before control of the callback thread
4860 * reaches this point.
4861 */
4862 st_session_ev_t deferred_ev = { .ev_id = ST_SES_EV_DEFERRED_STOP,
4863 .stc_ses = stc_ses};
4864 DISPATCH_EVENT(st_ses, deferred_ev, status);
4865 } else {
4866 ALOGE("%s:[%d] capture is requested but state is still detected!?",
4867 __func__, st_ses->sm_handle);
4868 }
4869 break;
Quinn Male2e883752019-03-22 11:28:54 -07004870
4871 case ST_SES_EV_SSR_OFFLINE:
Quinn Male2e883752019-03-22 11:28:54 -07004872 /* exec mode can be none if ssr occurs during a transition */
4873 if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004874 stop_session(st_ses, hw_ses, true);
4875 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07004876 break;
4877
4878 case ST_SES_EV_SEND_CHMIX_COEFF:
4879 status = hw_ses->fptrs->send_custom_chmix_coeff(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004880 ev->payload.chmix_coeff_str);
Quinn Male2e883752019-03-22 11:28:54 -07004881 break;
4882
4883 case ST_SES_EV_SET_DEVICE:
4884 if (!ev->payload.enable)
4885 status = hw_ses->fptrs->disable_device(hw_ses, true);
4886 else
4887 status = hw_ses->fptrs->enable_device(hw_ses, true);
4888
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004889 if (status && st_ses->stdev->ssr_offline_received) {
4890 STATE_TRANSITION(st_ses, ssr_state_fn);
4891 status = 0;
4892 }
Quinn Male2e883752019-03-22 11:28:54 -07004893 break;
4894
4895 case ST_SES_EV_READ_PCM:
4896 /*
4897 * buffering could have been stopped internally
4898 * and switched to active state ex: transitions.
4899 * set status to failure this will tell AHAL to
4900 * provide zero buffers to client
4901 */
4902 status = -EIO;
4903 break;
4904
4905 case ST_SES_EV_GET_PARAM_DATA:
4906 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004907 ev->payload.getparam.param, ev->payload.getparam.payload,
4908 ev->payload.getparam.payload_size,
4909 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07004910 break;
4911
4912 case ST_SES_EV_REQUEST_DET:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004913 if (!list_empty(&stc_ses->second_stage_list)) {
4914 ALOGE("%s:[%d] Event not supported with second stage enabled",
4915 __func__, st_ses->sm_handle);
4916 status = -EINVAL;
4917 break;
Quinn Male2e883752019-03-22 11:28:54 -07004918 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004919 status = hw_ses->fptrs->send_detection_request(hw_ses);
4920 if (!status)
4921 st_ses->detection_requested = true;
Quinn Male2e883752019-03-22 11:28:54 -07004922 break;
4923
4924 default:
4925 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
4926 break;
Quinn Male2e883752019-03-22 11:28:54 -07004927 };
4928
4929 return status;
4930}
4931
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004932static int detected_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07004933{
4934 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004935 st_exec_mode_t new_exec_mode = ST_EXEC_MODE_NONE;
4936 st_session_t *stc_ses = ev->stc_ses;
4937 struct listnode *node = NULL;
4938 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07004939 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
4940 st_hw_session_t *new_hw_ses = NULL;
4941
4942 /* skip parameter check as this is an internal funciton */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004943 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
4944 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07004945
4946 switch (ev->ev_id) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004947 case ST_SES_EV_LOAD_SM:
4948 /* Valid event only in multi-client usecase */
4949 /*
4950 * If a detected client deffered stop event is not handled yet,
4951 * handle here before moving out of detected state
4952 */
4953 if (st_ses->det_stc_ses && !st_ses->det_stc_ses->pending_stop) {
4954 ALOGD("%s:[%d] post deferred stop for c%d", __func__,
4955 st_ses->sm_handle, st_ses->det_stc_ses->sm_handle);
4956 status = hw_session_notifier_enqueue(
4957 st_ses->det_stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP,
4958 ST_SES_DEFERRED_STOP_DELAY_MS);
4959 if (!status)
4960 st_ses->det_stc_ses->pending_stop = true;
4961 }
4962 status = handle_load_sm(st_ses, stc_ses);
4963 break;
4964
4965 case ST_SES_EV_UNLOAD_SM:
4966 /* Valid event only in multi-client usecase */
4967 /*
4968 * If a detected client deffered stop event is not handled yet,
4969 * handle here before moving out of detected state
4970 */
4971 if (st_ses->det_stc_ses && !st_ses->det_stc_ses->pending_stop) {
4972 ALOGD("%s:[%d] post deferred stop for client c%d", __func__,
4973 st_ses->sm_handle, st_ses->det_stc_ses->sm_handle);
4974 status = hw_session_notifier_enqueue(
4975 st_ses->det_stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP,
4976 ST_SES_DEFERRED_STOP_DELAY_MS);
4977 if (!status)
4978 st_ses->det_stc_ses->pending_stop = true;
4979 }
4980 status = handle_unload_sm(st_ses, stc_ses);
4981 break;
4982
Quinn Male2e883752019-03-22 11:28:54 -07004983 case ST_SES_EV_START:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004984 /* For multi-client, other loaded client may start */
Quinn Male2e883752019-03-22 11:28:54 -07004985 STATE_TRANSITION(st_ses, active_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004986 DISPATCH_EVENT(st_ses, *ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07004987 break;
4988
4989 case ST_SES_EV_RESTART:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004990 status = restart_session(st_ses, hw_ses);
4991 if (status && !st_ses->stdev->ssr_offline_received)
4992 ALOGE("%s:[%d] failed to start session, err %d", __func__,
4993 st_ses->sm_handle, status);
4994
4995 if (st_ses->stdev->ssr_offline_received) {
4996 stop_session(st_ses, hw_ses, true);
4997 STATE_TRANSITION(st_ses, ssr_state_fn);
4998 status = 0;
4999 } else {
5000 /* Move anyways to allow client unload */
5001 STATE_TRANSITION(st_ses, active_state_fn);
5002 }
Quinn Male2e883752019-03-22 11:28:54 -07005003 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005004
Quinn Male2e883752019-03-22 11:28:54 -07005005 case ST_SES_EV_PAUSE:
Quinn Male2e883752019-03-22 11:28:54 -07005006 case ST_SES_EV_STOP:
5007 /*
5008 * It is possible that the client can issue stop after detection
5009 * callback. This even can be issued internally as part of
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005010 * deferred stop as well. For multi-client, it could be current
5011 * detected client stop or other client stop.
Quinn Male2e883752019-03-22 11:28:54 -07005012 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005013 STATE_TRANSITION(st_ses, active_state_fn);
5014 DISPATCH_EVENT(st_ses, *ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07005015 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005016
Quinn Male2e883752019-03-22 11:28:54 -07005017 case ST_SES_EV_SSR_OFFLINE:
Quinn Male2e883752019-03-22 11:28:54 -07005018 /*
5019 * Ignore return status during SSR handling
5020 * as the ADSP or CPE might be down so these
5021 * calls would fail. Exec mode can be none if
5022 * ssr occurs during a transition.
5023 */
5024 if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005025 stop_session(st_ses, hw_ses, true);
Quinn Male2e883752019-03-22 11:28:54 -07005026 STATE_TRANSITION(st_ses, ssr_state_fn);
5027 break;
5028
5029 case ST_SES_EV_SET_EXEC_MODE:
5030 new_exec_mode = ev->payload.exec_mode;
5031
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005032 if (new_exec_mode == st_ses->exec_mode) {
5033 stc_ses->exec_mode = st_ses->exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07005034 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005035 }
Quinn Male2e883752019-03-22 11:28:54 -07005036
5037 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
5038 st_ses->exec_mode = ST_EXEC_MODE_NONE;
5039 status = stop_session(st_ses, hw_ses, true);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005040 list_for_each(node, &st_ses->clients_list) {
5041 c_ses = node_to_item(node, st_session_t, hw_list_node);
5042 c_ses->exec_mode = new_exec_mode;
5043 }
Quinn Male2e883752019-03-22 11:28:54 -07005044 if (status)
5045 break;
5046 }
5047
5048 if (new_exec_mode == ST_EXEC_MODE_NONE)
5049 break;
5050
5051 /* switch to new hw session */
5052 if (ST_EXEC_MODE_CPE == new_exec_mode) {
5053 new_hw_ses = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07005054 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
5055 new_hw_ses = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07005056 } else {
5057 ALOGE("%s: unknown execution mode %d", __func__,
5058 new_exec_mode);
5059 status = -EINVAL;
5060 break;
5061 }
5062
5063 /*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005064 * hw session changed to/from WDSP/ADSP, hence update the
5065 * related config.
5066 * Not applicable for LPI<->non-LPI transtions as hw session
5067 * doesn't change.
5068 */
5069 status = update_hw_config_on_start(stc_ses, new_hw_ses);
5070 if (status) {
5071 ALOGE("%s: Update_hw_config_on_start failed %d",
5072 __func__, status);
5073 break;
5074 }
5075 /*
Quinn Male2e883752019-03-22 11:28:54 -07005076 * start new hw session and stay in detected state as
5077 * client restart and stop concurrency scenarios are handled
5078 * in this state
5079 */
5080 status = start_session(st_ses, new_hw_ses, true);
5081 if (status)
5082 break;
5083
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005084 list_for_each(node, &st_ses->clients_list) {
5085 c_ses = node_to_item(node, st_session_t, hw_list_node);
5086 c_ses->exec_mode = new_exec_mode;
5087 if (c_ses->state == ST_STATE_ACTIVE) {
5088 dereg_hal_event_session(c_ses);
5089 reg_hal_event_session(c_ses, new_hw_ses);
5090 }
5091 }
Quinn Male2e883752019-03-22 11:28:54 -07005092 st_ses->exec_mode = new_exec_mode;
5093 st_ses->hw_ses_current = new_hw_ses;
5094 break;
5095
5096 case ST_SES_EV_SEND_CHMIX_COEFF:
5097 status = -EINVAL;
5098 break;
5099
5100 case ST_SES_EV_SET_DEVICE:
5101 /*
5102 * set device is a no-op in detected state due to the following reasons
5103 * A set device is a sequence of disable and enable device commands.
5104 * set device sequence is triggered with dev lock held. Therefore there
5105 * cannot be a concurrency with other client issued events.
5106 * As a deferred stop is posted prior to entering detected state,
5107 * one of the two events are possible
5108 * 1) timer expires and stop is issued : this implies stop_session
5109 * 2) timer is cancelled and start is issued by client: this implies
5110 * new device is set as part of start_session
5111 */
5112 break;
5113
5114 case ST_SES_EV_GET_PARAM_DATA:
5115 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005116 ev->payload.getparam.param, ev->payload.getparam.payload,
5117 ev->payload.getparam.payload_size,
5118 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07005119 break;
5120 case ST_SES_EV_DEFERRED_STOP:
5121 ALOGD("%s:[%d] post deferred stop from detected state", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005122 st_ses->sm_handle);
5123 status = hw_session_notifier_enqueue(stc_ses->sm_handle,
5124 ST_SES_EV_DEFERRED_STOP, ST_SES_DEFERRED_STOP_DELAY_MS);
Quinn Male2e883752019-03-22 11:28:54 -07005125 if (!status)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005126 stc_ses->pending_stop = true;
Quinn Male2e883752019-03-22 11:28:54 -07005127 break;
5128 case ST_SES_EV_REQUEST_DET:
5129 ALOGE("%s:[%d] Event not supported in this state",
5130 __func__, st_ses->sm_handle);
5131 status = -EINVAL;
5132 break;
5133 default:
5134 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
5135 break;
Quinn Male2e883752019-03-22 11:28:54 -07005136 };
Quinn Male2e883752019-03-22 11:28:54 -07005137 return status;
5138}
5139
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005140static int buffering_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07005141{
5142 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005143 st_session_t *stc_ses = ev->stc_ses;
5144 struct listnode *node = NULL;
5145 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07005146 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005147 st_exec_mode_t new_exec_mode = ST_EXEC_MODE_NONE;
Quinn Male2e883752019-03-22 11:28:54 -07005148 st_hw_session_t *new_hw_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07005149
5150 /* skip parameter check as this is an internal function */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005151 ALOGVV("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5152 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005153
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005154 switch (ev->ev_id) {
5155 case ST_SES_EV_LOAD_SM:
5156 /* Valid in multi-client usecase */
5157 ALOGD("%s:[c%d-%d] load sm", __func__, stc_ses->sm_handle,
5158 st_ses->sm_handle);
5159
5160 status = handle_load_sm(st_ses, stc_ses);
5161 break;
5162
5163 case ST_SES_EV_UNLOAD_SM:
5164 ALOGD("%s:[c%d-%d] unload sm", __func__, stc_ses->sm_handle,
5165 st_ses->sm_handle);
5166
5167 status = handle_unload_sm(st_ses, stc_ses);
5168 break;
5169
5170 case ST_SES_EV_READ_PCM:
Quinn Male2e883752019-03-22 11:28:54 -07005171 /* Note: this function may block if there is no PCM data ready*/
5172 hw_ses->fptrs->read_pcm(hw_ses, ev->payload.readpcm.out_buff,
5173 ev->payload.readpcm.out_buff_size);
Quinn Maleaba13db2019-07-11 15:52:14 -07005174 if (st_ses->stdev->enable_debug_dumps) {
5175 ST_DBG_FILE_WRITE(st_ses->lab_fp, ev->payload.readpcm.out_buff,
5176 ev->payload.readpcm.out_buff_size);
5177 }
Quinn Male2e883752019-03-22 11:28:54 -07005178 break;
5179 case ST_SES_EV_END_BUFFERING:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005180 if (stc_ses == st_ses->det_stc_ses) {
5181 hw_ses->fptrs->stop_buffering(hw_ses);
5182 if (!stc_ses->pending_stop) {
5183 ALOGD("%s:[c%d] post deferred stop on buffering end", __func__,
5184 stc_ses->sm_handle);
5185 status = hw_session_notifier_enqueue(stc_ses->sm_handle,
5186 ST_SES_EV_DEFERRED_STOP, ST_SES_DEFERRED_STOP_DELAY_MS);
5187 if (!status)
5188 stc_ses->pending_stop = true;
5189 } else {
5190 ALOGD("%s:[c%d] skip deferred stop on buffering as already set",
5191 __func__, stc_ses->sm_handle);
5192 }
Quinn Male2e883752019-03-22 11:28:54 -07005193 }
5194 break;
Quinn Male2e883752019-03-22 11:28:54 -07005195
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005196 case ST_SES_EV_STOP:
5197 ALOGD("%s:[c%d-%d] handle event STOP", __func__, stc_ses->sm_handle,
5198 st_ses->sm_handle);
5199 if (stc_ses != st_ses->det_stc_ses) {
5200 ALOGD("%s: c%d buffering, delay c%d stop", __func__,
5201 st_ses->det_stc_ses->sm_handle, stc_ses->sm_handle);
5202 update_hw_config_on_stop(st_ses, stc_ses);
5203 break;
5204 }
5205 /* Fall through */
5206 case ST_SES_EV_PAUSE:
5207 hw_ses->fptrs->stop_buffering(hw_ses);
5208 STATE_TRANSITION(st_ses, active_state_fn);
5209 DISPATCH_EVENT(st_ses, *ev, status);
Quinn Maleaba13db2019-07-11 15:52:14 -07005210 if (st_ses->stdev->enable_debug_dumps)
5211 ST_DBG_FILE_CLOSE(st_ses->lab_fp);
Quinn Male2e883752019-03-22 11:28:54 -07005212 break;
5213
5214 case ST_SES_EV_SET_DEVICE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005215 ALOGD("%s:[c%d-%d] handle SET_DEVICE", __func__, stc_ses->sm_handle,
5216 st_ses->sm_handle);
Quinn Male2e883752019-03-22 11:28:54 -07005217 /*
5218 * Device switch will not wait for buffering to finish. It will instead
5219 * interrupt and stop the buffering and transition to the loaded state.
5220 * The loaded state will then take care of the device switch.
5221 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005222 hw_ses->fptrs->stop_buffering(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005223 status = stop_session(st_ses, hw_ses, false);
5224 if (status && !st_ses->stdev->ssr_offline_received) {
5225 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
5226 st_ses->sm_handle, status);
5227 break;
5228 }
5229 STATE_TRANSITION(st_ses, loaded_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005230 DISPATCH_EVENT(st_ses, *ev, status);
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005231
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005232 /*
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005233 * set_device event can be dispatched with any one of attached
5234 * multi-clients. For current detected client, the App may or may
5235 * not start next detection, so handle the state accordingly.
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005236 */
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005237 if (st_ses->det_stc_ses->pending_stop) {
5238 ALOGD("%s:[c%d] cancel ST_SES_EV_DEFERRED_STOP", __func__,
5239 st_ses->det_stc_ses->sm_handle);
5240 hw_session_notifier_cancel(stc_ses->sm_handle,
5241 ST_SES_EV_DEFERRED_STOP);
5242 stc_ses->pending_stop = false;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005243 }
Venkatesh Mangalappali616dbf72019-09-16 16:35:13 -07005244 st_ses->det_stc_ses->state = ST_STATE_LOADED;
Quinn Male2e883752019-03-22 11:28:54 -07005245 break;
5246
5247 case ST_SES_EV_START:
5248 case ST_SES_EV_RESTART:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005249 ALOGD("%s:[c%d-%d] handle event START/RESTART", __func__,
5250 stc_ses->sm_handle, st_ses->sm_handle);
5251
5252 if (stc_ses != st_ses->det_stc_ses) {
5253 ALOGD("%s: c%d buffering, delay c%d start", __func__,
5254 st_ses->det_stc_ses->sm_handle, stc_ses->sm_handle);
5255 break;
5256 }
Quinn Male2e883752019-03-22 11:28:54 -07005257 /*
5258 * Client starts detection again.
5259 * This implies a previous deferred stop hasn't completed yet as
5260 * stop would have changed state to loaded.
5261 * For a restart event, issue stop buffering and restart the session
5262 * For a start event, stop buffering then stop and start the session
5263 * so that any new parameters take effect.
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005264 * For multi-client case while the detected is buffering,
5265 * the other client stop/start would have been deferred by updating
5266 * the config, and later when current detected client restarts after
5267 * buffreing is completed, check if hw config is updated due to other
5268 * client and stop->start the hw session to apply updated config.
Quinn Male2e883752019-03-22 11:28:54 -07005269 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005270 hw_ses->fptrs->stop_buffering(hw_ses);
5271 if (hw_ses->sthw_cfg_updated || ev->ev_id == ST_SES_EV_START) {
Quinn Male2e883752019-03-22 11:28:54 -07005272 status = stop_session(st_ses, hw_ses, false);
Zhou Songfe0a2a52019-11-12 15:17:59 +08005273 STATE_TRANSITION(st_ses, loaded_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005274 if (status) {
Quinn Male2e883752019-03-22 11:28:54 -07005275 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005276 st_ses->sm_handle, status);
5277 } else {
5278 status = start_session(st_ses, hw_ses, false);
5279 if (status) {
5280 ALOGE("%s:[%d] failed to start session, err %d", __func__,
5281 st_ses->sm_handle, status);
5282 }
Quinn Male2e883752019-03-22 11:28:54 -07005283 }
Quinn Male2e883752019-03-22 11:28:54 -07005284 } else {
5285 status = restart_session(st_ses, hw_ses);
5286 }
5287
5288 if (status) {
5289 if (st_ses->stdev->ssr_offline_received) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005290 hw_ses->fptrs->dereg_sm(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005291 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07005292 status = 0;
5293 } else {
Quinn Male2e883752019-03-22 11:28:54 -07005294 /* move to active anyways to allow unload sm */
5295 STATE_TRANSITION(st_ses, active_state_fn);
5296 }
5297 } else {
Quinn Male2e883752019-03-22 11:28:54 -07005298 STATE_TRANSITION(st_ses, active_state_fn);
5299 }
5300 break;
5301
5302 case ST_SES_EV_SSR_OFFLINE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005303 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5304 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005305 /*
5306 * Ignore return status during SSR handling
5307 * as the ADSP or CPE might be down so these
5308 * calls would fail. Exec mode can be none if
5309 * ssr occurs during a transition.
5310 */
5311 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005312 hw_ses->fptrs->stop_buffering(hw_ses);
5313 stop_session(st_ses, hw_ses, true);
Quinn Male2e883752019-03-22 11:28:54 -07005314 }
5315 STATE_TRANSITION(st_ses, ssr_state_fn);
5316 break;
5317
5318 case ST_SES_EV_SET_EXEC_MODE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005319 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5320 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005321
5322 new_exec_mode = ev->payload.exec_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005323 if (new_exec_mode == st_ses->exec_mode) {
5324 stc_ses->exec_mode = st_ses->exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07005325 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005326 }
Quinn Male2e883752019-03-22 11:28:54 -07005327
5328 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
5329 st_ses->exec_mode = ST_EXEC_MODE_NONE;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005330 status = hw_ses->fptrs->stop_buffering(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005331 if (status) {
5332 ALOGE("%s:[%d] failed to stop_buffering err %d", __func__,
5333 st_ses->sm_handle, status);
5334 break;
5335 }
Quinn Male2e883752019-03-22 11:28:54 -07005336 status = stop_session(st_ses, hw_ses, true);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005337 list_for_each(node, &st_ses->clients_list) {
5338 c_ses = node_to_item(node, st_session_t, hw_list_node);
5339 c_ses->exec_mode = new_exec_mode;
5340 }
Quinn Male2e883752019-03-22 11:28:54 -07005341 if (status) {
5342 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
5343 st_ses->sm_handle, status);
5344 break;
5345 }
5346 }
5347
5348 if (new_exec_mode == ST_EXEC_MODE_NONE)
5349 break;
5350
5351 /* switch to new hw session */
5352 if (ST_EXEC_MODE_CPE == new_exec_mode) {
5353 new_hw_ses = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07005354 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
5355 new_hw_ses = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07005356 } else {
5357 ALOGE("%s: unknown execution mode %d", __func__,
5358 new_exec_mode);
5359 status = -EINVAL;
5360 break;
5361 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005362 /*
5363 * hw session changed to/from WDSP/ADSP, hence update the
5364 * related config.
5365 * Not applicable for LPI<->non-LPI transtions as hw session
5366 * doesn't change.
5367 */
5368 status = update_hw_config_on_start(stc_ses, new_hw_ses);
5369 if (status) {
5370 ALOGE("%s: Update_hw_config_on_start failed %d",
5371 __func__, status);
5372 break;
5373 }
Quinn Male2e883752019-03-22 11:28:54 -07005374 status = start_session(st_ses, new_hw_ses, true);
5375 if (status) {
5376 ALOGE("%s:[%d] failed to start hw ses, err %d", __func__,
5377 st_ses->sm_handle, status);
5378 break;
5379 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005380 list_for_each(node, &st_ses->clients_list) {
5381 c_ses = node_to_item(node, st_session_t, hw_list_node);
5382 c_ses->exec_mode = new_exec_mode;
5383 if (c_ses->state == ST_STATE_ACTIVE) {
5384 dereg_hal_event_session(c_ses);
5385 reg_hal_event_session(c_ses, new_hw_ses);
5386 }
5387 }
Quinn Male2e883752019-03-22 11:28:54 -07005388 st_ses->exec_mode = new_exec_mode;
5389 st_ses->hw_ses_current = new_hw_ses;
5390 STATE_TRANSITION(st_ses, active_state_fn);
5391 break;
5392
5393 case ST_SES_EV_SEND_CHMIX_COEFF:
5394 status = hw_ses->fptrs->send_custom_chmix_coeff(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005395 ev->payload.chmix_coeff_str);
Quinn Male2e883752019-03-22 11:28:54 -07005396 break;
5397
5398 case ST_SES_EV_GET_PARAM_DATA:
5399 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005400 ev->payload.getparam.param, ev->payload.getparam.payload,
5401 ev->payload.getparam.payload_size,
5402 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07005403 break;
5404
5405 case ST_SES_EV_REQUEST_DET:
5406 ALOGE("%s:[%d] Event %d not supported in this state",
5407 __func__, st_ses->sm_handle, ev->ev_id);
5408 status = -EINVAL;
5409 break;
5410
5411 default:
5412 ALOGD("%s:[%d] unhandled event, id %d", __func__, st_ses->sm_handle,
5413 ev->ev_id);
5414 break;
Quinn Male2e883752019-03-22 11:28:54 -07005415 };
5416
5417 return status;
5418}
5419
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005420static int ssr_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07005421{
5422 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005423 st_session_t *stc_ses = ev->stc_ses;
5424 st_session_ev_t load_ev = {.ev_id = ST_SES_EV_LOAD_SM};
5425 st_session_ev_t start_ev = {.ev_id = ST_SES_EV_START};
5426 st_session_ev_t exec_mode_ev = {.ev_id = ST_SES_EV_SET_EXEC_MODE};
5427 bool active = false;
Quinn Male2e883752019-03-22 11:28:54 -07005428
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005429 /* skip parameter check as this is an internal function */
5430 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5431 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005432
5433 switch (ev->ev_id) {
5434 case ST_SES_EV_SSR_ONLINE:
5435 ALOGV("%s:[%d] SSR ONLINE received", __func__, st_ses->sm_handle);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005436 /*
5437 * Load and start all clients at once instead of unload/loading
5438 * due to each subsequent client dispatch. It is expected the
5439 * upper layer calls SSR_ONLINE for all clients.
5440 */
5441 stc_ses->pending_load = true;
5442 if (is_any_client_not_pending_load(st_ses))
5443 break;
5444
5445 reset_clients_pending_load(st_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005446
5447 STATE_TRANSITION(st_ses, idle_state_fn);
5448
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005449 if ((stc_ses->ssr_transit_exec_mode == ST_EXEC_MODE_CPE) ||
5450 (stc_ses->ssr_transit_exec_mode == ST_EXEC_MODE_ADSP)) {
5451 exec_mode_ev.stc_ses = stc_ses;
5452 exec_mode_ev.payload.exec_mode = stc_ses->ssr_transit_exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07005453 DISPATCH_EVENT(st_ses, exec_mode_ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005454 if (status)
5455 break;
5456 stc_ses->ssr_transit_exec_mode = ST_EXEC_MODE_NONE;
Quinn Male2e883752019-03-22 11:28:54 -07005457 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005458 active = is_any_client_in_state(st_ses, ST_STATE_ACTIVE);
5459 if (active || is_any_client_in_state(st_ses, ST_STATE_LOADED)) {
5460 load_ev.stc_ses = stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005461 DISPATCH_EVENT(st_ses, load_ev, status);
5462 if (status)
5463 break;
5464 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005465 if (active) {
5466 start_ev.stc_ses = stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005467 DISPATCH_EVENT(st_ses, start_ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07005468 }
5469
5470 break;
5471
5472 case ST_SES_EV_LOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005473 if (ST_STATE_IDLE == stc_ses->state) {
5474 status = update_sound_model(stc_ses, true);
5475 if (status) {
5476 ALOGE("%s:[c%d] update sound model add failed %d", __func__,
5477 stc_ses->sm_handle, status);
5478 status = -EINVAL;
5479 break;
5480 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005481 stc_ses->state = ST_STATE_LOADED;
Quinn Male2e883752019-03-22 11:28:54 -07005482 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005483 ALOGE("%s: received unexpected event, client state = %d",
5484 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07005485 }
5486 break;
5487
5488 case ST_SES_EV_UNLOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005489 if (ST_STATE_LOADED == stc_ses->state) {
5490 status = update_sound_model(stc_ses, false);
5491 if (status)
5492 ALOGE("%s:[c%d] update sound_model failed %d", __func__,
5493 stc_ses->sm_handle, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005494 stc_ses->state = ST_STATE_IDLE;
Quinn Male2e883752019-03-22 11:28:54 -07005495 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005496 ALOGE("%s: received unexpected event, client state = %d",
5497 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07005498 }
5499 break;
5500
5501 case ST_SES_EV_START:
5502 case ST_SES_EV_RESTART:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005503 if (ST_STATE_LOADED == stc_ses->state) {
5504 if (ev->ev_id == ST_SES_EV_RESTART)
5505 update_hw_config_on_restart(st_ses, stc_ses);
5506 stc_ses->state = ST_STATE_ACTIVE;
Quinn Male2e883752019-03-22 11:28:54 -07005507 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005508 ALOGE("%s: received unexpected event, client state = %d",
5509 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07005510 }
5511 break;
5512
5513 case ST_SES_EV_STOP:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005514 if (ST_STATE_ACTIVE == stc_ses->state) {
5515 update_hw_config_on_stop(st_ses, stc_ses);
5516 stc_ses->state = ST_STATE_LOADED;
Quinn Male2e883752019-03-22 11:28:54 -07005517 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005518 ALOGE("%s: received unexpected event, client state = %d",
5519 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07005520 }
5521 break;
5522
5523 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005524 stc_ses->paused = true;
Quinn Male2e883752019-03-22 11:28:54 -07005525 break;
5526
5527 case ST_SES_EV_RESUME:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005528 stc_ses->paused = false;
Quinn Male2e883752019-03-22 11:28:54 -07005529 break;
5530
5531 case ST_SES_EV_READ_PCM:
5532 status = -EIO;
5533 break;
5534
5535 case ST_SES_EV_SEND_CHMIX_COEFF:
5536 status = -EIO;
5537 break;
5538
5539 case ST_SES_EV_GET_PARAM_DATA:
5540 status = -EIO;
5541 break;
5542
5543 case ST_SES_EV_SET_EXEC_MODE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005544 stc_ses->exec_mode = ev->payload.exec_mode;
5545 if (ev->payload.exec_mode == st_ses->exec_mode)
5546 break;
5547
Quinn Male2e883752019-03-22 11:28:54 -07005548 st_ses->exec_mode = ev->payload.exec_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005549
Quinn Male2e883752019-03-22 11:28:54 -07005550 if (ST_EXEC_MODE_CPE == st_ses->exec_mode)
5551 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
5552 else if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
5553 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
5554 /* remain in current state */
5555 break;
5556
5557 case ST_SES_EV_REQUEST_DET:
5558 ALOGE("%s:[%d] Event not supported in this state",
5559 __func__, st_ses->sm_handle);
5560 status = -EINVAL;
5561 break;
5562
5563 default:
5564 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
5565 break;
5566 };
5567
5568 return status;
5569}
5570
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005571int st_session_load_sm(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005572{
5573 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005574
5575 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005576 return -EINVAL;
5577
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005578 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5579 st_session_loadsm_payload_t payload = { .phrase_sm = stc_ses->phrase_sm };
Quinn Male2e883752019-03-22 11:28:54 -07005580 st_session_ev_t ev = { .ev_id = ST_SES_EV_LOAD_SM,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005581 .payload.loadsm = payload, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005582
5583 pthread_mutex_lock(&st_ses->lock);
5584 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005585 if (!status) {
Quinn Male12f5c6f2019-11-14 17:34:10 -08005586 prepare_second_stage_for_client(stc_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005587 stc_ses->state = ST_STATE_LOADED;
5588 }
Quinn Male2e883752019-03-22 11:28:54 -07005589 pthread_mutex_unlock(&st_ses->lock);
5590
5591 return status;
5592}
5593
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005594int st_session_unload_sm(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005595{
5596 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005597
5598 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005599 return -EINVAL;
5600
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005601 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5602 st_session_ev_t ev = { .ev_id = ST_SES_EV_UNLOAD_SM, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005603
5604 pthread_mutex_lock(&st_ses->lock);
5605 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005606 stop_second_stage_for_client(stc_ses);
5607 stc_ses->state = ST_STATE_IDLE;
Quinn Male2e883752019-03-22 11:28:54 -07005608 pthread_mutex_unlock(&st_ses->lock);
5609
5610 return status;
5611}
5612
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005613int st_session_start(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005614{
5615 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005616
5617 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005618 return -EINVAL;
5619
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005620 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5621 st_session_ev_t ev = { .ev_id = ST_SES_EV_START, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005622
Quinn Male2e883752019-03-22 11:28:54 -07005623 pthread_mutex_lock(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005624 if (stc_ses->pending_stop) {
5625 ALOGV("%s:[c%d] cancel ST_SES_EV_DEFERRED_STOP", __func__,
5626 stc_ses->sm_handle);
5627 hw_session_notifier_cancel(stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP);
5628 stc_ses->pending_stop = false;
5629 }
5630
Quinn Male2e883752019-03-22 11:28:54 -07005631 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005632 if (!status) {
5633 reg_hal_event_session(stc_ses, st_ses->hw_ses_current);
5634 start_second_stage_for_client(stc_ses);
5635 stc_ses->state = ST_STATE_ACTIVE;
5636 }
Quinn Male2e883752019-03-22 11:28:54 -07005637 pthread_mutex_unlock(&st_ses->lock);
5638 return status;
5639}
5640
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005641int st_session_stop(st_session_t *stc_ses)
5642{
5643 int status = 0;
5644
5645 if (!stc_ses || !stc_ses->hw_proxy_ses)
5646 return -EINVAL;
5647
5648 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5649 st_session_ev_t ev = { .ev_id = ST_SES_EV_STOP, .stc_ses = stc_ses };
5650
5651 pthread_mutex_lock(&st_ses->lock);
5652 DISPATCH_EVENT(st_ses, ev, status);
5653 dereg_hal_event_session(stc_ses);
5654 stc_ses->pending_stop = false;
5655 stc_ses->state = ST_STATE_LOADED;
5656 pthread_mutex_unlock(&st_ses->lock);
5657
5658 return status;
5659}
5660
5661int st_session_restart(st_session_t *stc_ses)
5662{
5663 int status = 0;
5664
5665 if (!stc_ses || !stc_ses->hw_proxy_ses)
5666 return -EINVAL;
5667
5668 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5669 st_session_ev_t ev = { .ev_id = ST_SES_EV_RESTART, .stc_ses = stc_ses };
5670
5671 pthread_mutex_lock(&st_ses->lock);
5672 if (stc_ses->pending_stop) {
5673 ALOGV("%s:[c%d] cancel ST_SES_EV_DEFERRED_STOP", __func__,
5674 stc_ses->sm_handle);
5675 hw_session_notifier_cancel(stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP);
5676 stc_ses->pending_stop = false;
5677 }
5678
5679 DISPATCH_EVENT(st_ses, ev, status);
5680 if (!status) {
5681 start_second_stage_for_client(stc_ses);
5682 stc_ses->state = ST_STATE_ACTIVE;
5683 } else {
5684 dereg_hal_event_session(stc_ses);
5685 stc_ses->state = ST_STATE_LOADED;
5686 }
5687 pthread_mutex_unlock(&st_ses->lock);
5688
5689 return status;
5690}
5691
5692int st_session_ssr_offline(st_session_t *stc_ses,
Quinn Male2e883752019-03-22 11:28:54 -07005693 enum ssr_event_status ssr_type)
5694{
5695 int status = 0;
5696
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005697 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005698 return -EINVAL;
5699
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005700 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005701 st_session_ev_t ev = { .ev_id = ST_SES_EV_SSR_OFFLINE,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005702 .payload.ssr = ssr_type, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005703
5704 pthread_mutex_lock(&st_ses->lock);
5705 /*
5706 * In typical usecases, handle SSR only if it occured on the core we are
5707 * currently using. In cases that have an SSR event during transitions,
5708 * the exec_mode can be NONE. For these cases, handle SSR on the core
5709 * which was in use prior to the transition. For example, if the
5710 * ssr_transit_exec_mode is ADSP, then the core prior to the transition
5711 * is CPE, so we handle the CPE SSR event.
5712 *
5713 * On 8909w BG uses CPE mode for detection. So add BG specific
5714 * conditon check to handle SSR event.
5715 */
5716 if (((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
5717 (CPE_STATUS_OFFLINE == ssr_type)) ||
5718 ((ST_EXEC_MODE_ADSP == st_ses->exec_mode) &&
5719 (SND_CARD_STATUS_OFFLINE == ssr_type)) ||
5720 ((ST_EXEC_MODE_NONE == st_ses->exec_mode) &&
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005721 (((ST_EXEC_MODE_CPE == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07005722 (SND_CARD_STATUS_OFFLINE == ssr_type)) ||
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005723 ((ST_EXEC_MODE_ADSP == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07005724 (CPE_STATUS_OFFLINE == ssr_type)))) ||
5725 ((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
5726 (SND_CARD_STATUS_OFFLINE == ssr_type) &&
5727 (st_ses->stdev->bg_kwd)))
5728 DISPATCH_EVENT(st_ses, ev, status);
5729 pthread_mutex_unlock(&st_ses->lock);
5730
5731 return status;
5732}
5733
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005734int st_session_ssr_online(st_session_t *stc_ses,
Quinn Male2e883752019-03-22 11:28:54 -07005735 enum ssr_event_status ssr_type)
5736{
5737 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005738
5739 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005740 return -EINVAL;
5741
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005742 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005743 st_session_ev_t ev = { .ev_id = ST_SES_EV_SSR_ONLINE,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005744 .payload.ssr = ssr_type, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005745
5746 pthread_mutex_lock(&st_ses->lock);
5747 /*
5748 * In typical usecases, handle SSR only if it occured on the core we are
5749 * currently using. In cases that have an SSR event during transitions,
5750 * the exec_mode can be NONE. For these cases, handle SSR on the core
5751 * which was in use prior to the transition. For example, if the
5752 * ssr_transit_exec_mode is ADSP, then the core prior to the transition
5753 * is CPE, so we handle the CPE SSR event.
5754 *
5755 * On 8909w BG uses CPE mode for detection. So add BG specific
5756 * conditon check to handle SSR event.
5757 */
5758 if (((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
5759 (CPE_STATUS_ONLINE == ssr_type)) ||
5760 ((ST_EXEC_MODE_ADSP == st_ses->exec_mode) &&
5761 (SND_CARD_STATUS_ONLINE == ssr_type)) ||
5762 ((ST_EXEC_MODE_NONE == st_ses->exec_mode) &&
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005763 (((ST_EXEC_MODE_CPE == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07005764 (SND_CARD_STATUS_ONLINE == ssr_type)) ||
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005765 ((ST_EXEC_MODE_ADSP == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07005766 (CPE_STATUS_ONLINE == ssr_type)))) ||
5767 ((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
5768 (SND_CARD_STATUS_ONLINE == ssr_type) &&
5769 (st_ses->stdev->bg_kwd)))
5770 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005771
Quinn Male2e883752019-03-22 11:28:54 -07005772 pthread_mutex_unlock(&st_ses->lock);
5773
5774 return status;
5775}
5776
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005777int st_session_pause(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005778{
5779 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005780
5781 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005782 return -EINVAL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005783
5784 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5785 st_session_ev_t ev = { .ev_id = ST_SES_EV_PAUSE, .stc_ses = stc_ses };
5786
Venkatesh Mangalappali47118dc2019-07-29 11:51:52 -07005787 pthread_mutex_lock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07005788 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappali47118dc2019-07-29 11:51:52 -07005789 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07005790 return status;
5791}
5792
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005793int st_session_resume(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005794{
5795 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005796
5797 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005798 return -EINVAL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005799
5800 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5801 st_session_ev_t ev = { .ev_id = ST_SES_EV_RESUME, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005802
5803 pthread_mutex_lock(&st_ses->lock);
5804 DISPATCH_EVENT(st_ses, ev, status);
5805 pthread_mutex_unlock(&st_ses->lock);
5806 return status;
5807}
5808
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005809int st_session_disable_device(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005810{
5811 int status = 0;
Zhou Songcd3c8e62019-07-16 13:30:19 +08005812 st_session_event_id_t ev_id = ST_SES_EV_SET_DEVICE;
Quinn Male2e883752019-03-22 11:28:54 -07005813
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005814 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005815 return -EINVAL;
5816
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005817 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Zhou Songcd3c8e62019-07-16 13:30:19 +08005818 pthread_mutex_lock(&st_ses->lock);
5819 if (check_gcs_usecase_switch(stc_ses->hw_proxy_ses))
5820 ev_id = ST_SES_EV_PAUSE;
5821
5822 st_session_ev_t ev = {.ev_id = ev_id,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005823 .payload.enable = false, .stc_ses = stc_ses};
5824
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005825 /*
5826 * Avoid dispatching for each attached multi-client, instead
5827 * defer it until last client
5828 */
5829 stc_ses->pending_set_device = true;
5830 if (is_any_client_not_pending_set_device(st_ses)) {
5831 pthread_mutex_unlock(&st_ses->lock);
5832 return status;
5833 }
5834 reset_clients_pending_set_device(st_ses);
5835
5836 DISPATCH_EVENT(st_ses, ev, status);
5837 pthread_mutex_unlock(&st_ses->lock);
5838 return status;
5839}
5840
5841int st_session_enable_device(st_session_t *stc_ses)
5842{
5843 int status = 0;
Zhou Songcd3c8e62019-07-16 13:30:19 +08005844 st_session_event_id_t ev_id = ST_SES_EV_SET_DEVICE;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005845
5846 if (!stc_ses || !stc_ses->hw_proxy_ses)
5847 return -EINVAL;
5848
5849 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Zhou Songcd3c8e62019-07-16 13:30:19 +08005850 pthread_mutex_lock(&st_ses->lock);
5851 if (check_gcs_usecase_switch(stc_ses->hw_proxy_ses))
5852 ev_id = ST_SES_EV_RESUME;
5853
5854 st_session_ev_t ev = { .ev_id = ev_id,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005855 .payload.enable = true, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005856
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005857 /*
5858 * Avoid dispatching for each attached multi-client, instead
5859 * defer it until last client
5860 */
5861 stc_ses->pending_set_device = true;
5862 if (is_any_client_not_pending_set_device(st_ses)) {
5863 pthread_mutex_unlock(&st_ses->lock);
5864 return status;
5865 }
5866 reset_clients_pending_set_device(st_ses);
5867
Quinn Male2e883752019-03-22 11:28:54 -07005868 DISPATCH_EVENT(st_ses, ev, status);
5869 pthread_mutex_unlock(&st_ses->lock);
5870 return status;
5871}
5872
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005873bool st_session_is_detected(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005874{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005875 bool ret = false;
Quinn Male2e883752019-03-22 11:28:54 -07005876
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005877 if (!stc_ses || !stc_ses->hw_proxy_ses)
5878 return ret;
Quinn Male2e883752019-03-22 11:28:54 -07005879
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005880 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005881
5882 pthread_mutex_lock(&st_ses->lock);
5883 ret = (st_ses->current_state == detected_state_fn) ? true : false;
5884 pthread_mutex_unlock(&st_ses->lock);
5885
5886 return ret;
5887}
5888
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005889bool st_session_is_active(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005890{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005891 bool ret = false;
5892
5893 if (!stc_ses || !stc_ses->hw_proxy_ses)
5894 return ret;
5895
5896 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005897
5898 pthread_mutex_lock(&st_ses->lock);
5899 ret = (st_ses->current_state == active_state_fn) ? true : false;
5900 pthread_mutex_unlock(&st_ses->lock);
5901
5902 return ret;
5903}
5904
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005905bool st_session_is_buffering(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005906{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005907 bool ret = false;
5908
5909 if (!stc_ses || !stc_ses->hw_proxy_ses)
5910 return ret;
5911
5912 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005913
5914 pthread_mutex_lock(&st_ses->lock);
5915 ret = (st_ses->current_state == buffering_state_fn) ? true : false;
5916 pthread_mutex_unlock(&st_ses->lock);
5917
5918 return ret;
5919}
5920
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005921bool st_session_is_ssr_state(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005922{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005923 bool ret = false;
5924
5925 if (!stc_ses || !stc_ses->hw_proxy_ses)
5926 return ret;
5927
5928 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005929
5930 pthread_mutex_lock(&st_ses->lock);
5931 ret = (st_ses->current_state == ssr_state_fn) ? true : false;
5932 pthread_mutex_unlock(&st_ses->lock);
5933
5934 return ret;
5935}
5936
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005937int st_session_read_pcm(st_session_t *stc_ses, uint8_t *buff,
Quinn Male2e883752019-03-22 11:28:54 -07005938 size_t buff_size, size_t *read_size)
5939{
5940 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005941
5942 if (!stc_ses || !stc_ses->hw_proxy_ses || !buff || buff_size == 0 ||
5943 read_size == 0)
Quinn Male2e883752019-03-22 11:28:54 -07005944 return -EINVAL;
5945
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005946 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5947 st_session_readpcm_payload_t payload = {.out_buff = buff,
5948 .out_buff_size = buff_size, .actual_read_size = read_size};
Quinn Male2e883752019-03-22 11:28:54 -07005949
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005950 st_session_ev_t ev = {.ev_id = ST_SES_EV_READ_PCM,
5951 .payload.readpcm = payload, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07005952
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005953 /*
5954 * Do not lock when handling this event, this event
5955 * can go in parallel with other events as multiple
5956 * sessions can buffer in parallel.
5957 */
Quinn Male2e883752019-03-22 11:28:54 -07005958 DISPATCH_EVENT(st_ses, ev, status);
5959 return status;
5960}
5961
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005962int st_session_stop_lab(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005963{
5964 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005965
5966 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005967 return -EINVAL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005968
5969 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5970 st_session_ev_t ev = {.ev_id = ST_SES_EV_END_BUFFERING, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07005971
5972 pthread_mutex_lock(&st_ses->lock);
5973 DISPATCH_EVENT(st_ses, ev, status);
5974 pthread_mutex_unlock(&st_ses->lock);
5975 return status;
5976}
5977
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005978int st_session_set_exec_mode(st_session_t *stc_ses, st_exec_mode_t exec)
Quinn Male2e883752019-03-22 11:28:54 -07005979{
5980 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005981
5982 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005983 return -EINVAL;
5984
5985 ALOGV("%s: exec mode %d", __func__, exec);
5986
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005987 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5988 st_session_ev_t ev = {.ev_id = ST_SES_EV_SET_EXEC_MODE,
5989 .payload.exec_mode = exec, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07005990
5991 pthread_mutex_lock(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005992 if (st_ses->enable_trans)
5993 DISPATCH_EVENT(st_ses, ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07005994 pthread_mutex_unlock(&st_ses->lock);
5995 return status;
5996}
5997
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005998int st_session_update_recongition_config(st_session_t *stc_ses)
5999{
6000
6001 int status = 0;
6002
6003 if (!stc_ses || !stc_ses->hw_proxy_ses)
6004 return -EINVAL;
6005
6006 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6007
6008 pthread_mutex_lock(&st_ses->lock);
6009 status = update_hw_config_on_start(stc_ses, st_ses->hw_ses_current);
6010 pthread_mutex_unlock(&st_ses->lock);
6011 return status;
6012
6013}
6014
6015int st_session_get_preroll(st_session_t *stc_ses)
6016{
6017 int val = 0;
6018
6019 if (!stc_ses || !stc_ses->hw_proxy_ses)
6020 return 0;
6021
6022 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6023
6024 pthread_mutex_lock(&st_ses->lock);
6025 val = st_ses->hw_ses_current->sthw_cfg.client_req_preroll;
6026 pthread_mutex_unlock(&st_ses->lock);
6027
6028 return val;
6029}
6030
6031int st_session_send_custom_chmix_coeff(st_session_t *stc_ses, char *str)
Quinn Male2e883752019-03-22 11:28:54 -07006032{
6033 int status = 0;
6034
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006035 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006036 return -EINVAL;
6037
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006038 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006039 st_session_ev_t ev = { .ev_id = ST_SES_EV_SEND_CHMIX_COEFF,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006040 .payload.chmix_coeff_str = str, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006041
6042 pthread_mutex_lock(&st_ses->lock);
6043 if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
6044 DISPATCH_EVENT(st_ses, ev, status);
6045 pthread_mutex_unlock(&st_ses->lock);
6046 return status;
6047}
6048
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006049int st_session_get_config(st_session_t *stc_ses, struct pcm_config *config)
Quinn Male2e883752019-03-22 11:28:54 -07006050{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006051 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006052 return -EINVAL;
6053
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006054 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6055
6056 pthread_mutex_lock(&st_ses->lock);
6057 memcpy(config, &st_ses->hw_ses_current->config, sizeof(struct pcm_config));
6058 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006059
6060 return 0;
6061}
6062
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006063int st_session_get_param_data(st_session_t *stc_ses, const char *param,
6064 void *payload, size_t payload_size, size_t *param_data_size)
Quinn Male2e883752019-03-22 11:28:54 -07006065{
6066 int status = 0;
6067
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006068 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006069 return -EINVAL;
6070
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006071 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006072 st_session_getparam_payload_t getparam_payload = { .param = param,
6073 .payload = payload,
6074 .payload_size = payload_size,
6075 .param_data_size = param_data_size};
6076 st_session_ev_t ev = { .ev_id = ST_SES_EV_GET_PARAM_DATA,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006077 .payload.getparam = getparam_payload, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006078
6079 pthread_mutex_lock(&st_ses->lock);
6080 /* Currently get param data supported for ARM & ADSP mode */
6081 if ((ST_EXEC_MODE_ARM == st_ses->exec_mode) ||
6082 (ST_EXEC_MODE_ADSP == st_ses->exec_mode))
6083 DISPATCH_EVENT(st_ses, ev, status);
6084 pthread_mutex_unlock(&st_ses->lock);
6085
6086 return status;
6087}
6088
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006089int st_session_ss_init(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006090{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006091 int status = 0;
6092 struct listnode *node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07006093 st_arm_second_stage_t *st_sec_stage = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006094 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006095
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006096 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07006097 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
6098 status = st_second_stage_module_init(st_sec_stage,
6099 (void *)st_sec_stage->ss_info->lib_name);
6100 if (status) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006101 ALOGE("%s:[c%d] initializing second stage session failed %d",
6102 __func__, stc_ses->sm_handle, status);
Quinn Male2e883752019-03-22 11:28:54 -07006103 goto ss_cleanup;
6104 }
6105 }
6106
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006107 pthread_mutex_lock(&st_ses->lock);
6108 if (st_ses->aggregator_thread_created) {
6109 pthread_mutex_unlock(&st_ses->lock);
6110 return 0;
6111 }
6112 /*
6113 * Aggregator is not maintatined per client as there is only one
6114 * client keyword detection happens at a time in multi-client scenario.
6115 * Instead use single aggregator thread at proxy level, processing the
6116 * second stage for detected client at run time.
6117 */
6118 init_det_event_aggregator(st_ses);
6119
Quinn Male2e883752019-03-22 11:28:54 -07006120 st_ses->det_session_ev = calloc(1, sizeof(st_session_ev_t));
6121 if (!st_ses->det_session_ev) {
6122 ALOGE("%s: Failed to allocate st_session_ev_t, exiting", __func__);
6123 status = -ENOMEM;
6124 goto ss_cleanup;
6125 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006126 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006127 return 0;
6128
6129ss_cleanup:
6130 destroy_det_event_aggregator(st_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006131 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07006132 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
6133 st_second_stage_module_deinit(st_sec_stage);
6134 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006135 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006136 return status;
6137}
6138
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006139int st_session_ss_deinit(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006140{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006141 struct listnode *node = NULL;
6142 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07006143 st_arm_second_stage_t *st_sec_stage = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006144 st_session_t *c_ses = NULL;
6145 bool aggregator_needed = false;
Quinn Male2e883752019-03-22 11:28:54 -07006146
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006147 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07006148 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
6149 st_second_stage_module_deinit(st_sec_stage);
6150 }
6151
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006152 pthread_mutex_lock(&st_ses->lock);
6153 if (!st_ses->aggregator_thread_created) {
6154 pthread_mutex_unlock(&st_ses->lock);
6155 return 0;
6156 }
6157 /* If other client has second stage enabled, keep the aggregator */
6158 list_for_each(node, &st_ses->clients_list) {
6159 c_ses = node_to_item(node, st_session_t, hw_list_node);
6160 if (c_ses != stc_ses && !list_empty(&c_ses->second_stage_list)) {
6161 aggregator_needed = true;
6162 break;
6163 }
6164 }
6165 if (aggregator_needed) {
6166 pthread_mutex_unlock(&st_ses->lock);
6167 return 0;
6168 }
6169
6170 destroy_det_event_aggregator(st_ses);
6171
Quinn Male2e883752019-03-22 11:28:54 -07006172 if (st_ses->det_session_ev)
6173 free(st_ses->det_session_ev);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006174 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006175
6176 return 0;
6177}
6178
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006179int st_session_request_detection(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006180{
6181 int status = 0;
6182
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006183 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006184 return -EINVAL;
6185
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006186 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6187 st_session_ev_t ev = {.ev_id = ST_SES_EV_REQUEST_DET, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006188
6189 /* lock to serialize event handling */
6190 pthread_mutex_lock(&st_ses->lock);
6191 DISPATCH_EVENT(st_ses, ev, status);
6192 pthread_mutex_unlock(&st_ses->lock);
6193 return status;
6194}
6195
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006196int st_session_init(st_session_t *stc_ses, struct sound_trigger_device *stdev,
Quinn Male2e883752019-03-22 11:28:54 -07006197 st_exec_mode_t exec_mode, sound_model_handle_t sm_handle)
6198{
6199 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006200 struct st_vendor_info *v_info = NULL;
6201 st_proxy_session_t *st_ses = NULL;
6202 struct listnode *node = NULL;
6203 struct st_session *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07006204 pthread_mutexattr_t attr;
6205
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006206 if (!stc_ses || !stdev)
6207 return -EINVAL;
Quinn Male2e883752019-03-22 11:28:54 -07006208
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006209 st_ses = calloc(1, sizeof(st_proxy_session_t));
6210 if (!st_ses) {
6211 ALOGE("%s: hw_proxy_ses allocation failed", __func__);
6212 return -ENOMEM;
6213 }
6214 st_ses->stdev = stc_ses->stdev = stdev;
6215 v_info = stc_ses->vendor_uuid_info;
Quinn Male2e883752019-03-22 11:28:54 -07006216
6217 if (v_info && (EXEC_MODE_CFG_DYNAMIC == v_info->exec_mode_cfg)) {
6218 st_ses->enable_trans = true;
Quinn Male2e883752019-03-22 11:28:54 -07006219 if (stdev->is_gcs) {
6220 /* alloc and init cpe session*/
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006221 st_ses->hw_ses_cpe =
6222 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
Quinn Male2e883752019-03-22 11:28:54 -07006223 if (!st_ses->hw_ses_cpe) {
6224 status = -ENOMEM;
6225 goto cleanup;
6226 }
6227 status = st_hw_sess_gcs_init(st_ses->hw_ses_cpe, hw_sess_cb,
6228 (void *)st_ses, ST_EXEC_MODE_CPE, v_info, sm_handle, stdev);
6229 if (status) {
6230 ALOGE("%s: initializing gcs hw session failed %d", __func__,
6231 status);
6232 goto cleanup;
6233 }
6234
6235 /* alloc and init adsp session*/
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006236 st_ses->hw_ses_adsp =
6237 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
Quinn Male2e883752019-03-22 11:28:54 -07006238 if (!st_ses->hw_ses_adsp) {
6239 st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
6240 status = -ENOMEM;
6241 goto cleanup;
6242 }
6243
6244 status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
6245 (void *)st_ses, ST_EXEC_MODE_ADSP, v_info, sm_handle, stdev);
6246 if (status) {
6247 ALOGE("%s: initializing lsm session failed", __func__);
6248 st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
6249 goto cleanup;
6250 }
6251
6252 } else {
6253 /* alloc and init cpe session*/
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006254 st_ses->hw_ses_cpe =
6255 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
Quinn Male2e883752019-03-22 11:28:54 -07006256 if (!st_ses->hw_ses_cpe) {
6257 status = -ENOMEM;
6258 goto cleanup;
6259 }
6260 status = st_hw_sess_lsm_init(st_ses->hw_ses_cpe, hw_sess_cb,
6261 (void *)st_ses, ST_EXEC_MODE_CPE, v_info, sm_handle, stdev);
6262 if (status) {
6263 ALOGE("%s: initialzing lsm hw session failed %d", __func__,
6264 status);
6265 goto cleanup;
6266 }
6267 /* alloc and init adsp session*/
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006268 st_ses->hw_ses_adsp =
6269 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
Quinn Male2e883752019-03-22 11:28:54 -07006270 if (!st_ses->hw_ses_adsp) {
6271 status = -ENOMEM;
6272 st_hw_sess_lsm_deinit(st_ses->hw_ses_cpe);
6273 goto cleanup;
6274 }
Quinn Male2e883752019-03-22 11:28:54 -07006275 status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
6276 (void *)st_ses, ST_EXEC_MODE_ADSP, v_info, sm_handle, stdev);
6277 if (status) {
6278 ALOGE("%s: initializing lsm session failed", __func__);
6279 st_hw_sess_lsm_deinit(st_ses->hw_ses_cpe);
6280 goto cleanup;
6281 }
6282 }
Quinn Male2e883752019-03-22 11:28:54 -07006283 /* set current hw_session */
6284 if (exec_mode == ST_EXEC_MODE_CPE)
6285 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
6286 else if (exec_mode == ST_EXEC_MODE_ADSP)
6287 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07006288 } else if (v_info && (EXEC_MODE_CFG_CPE == v_info->exec_mode_cfg)) {
6289 st_ses->enable_trans = false;
6290 if (stdev->is_gcs) {
6291 ALOGD("%s: initializing gcs hw session", __func__);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006292 st_ses->hw_ses_cpe =
6293 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
Quinn Male2e883752019-03-22 11:28:54 -07006294 if (!st_ses->hw_ses_cpe) {
6295 status = -ENOMEM;
6296 goto cleanup;
6297 }
6298 status = st_hw_sess_gcs_init(st_ses->hw_ses_cpe, hw_sess_cb,
6299 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6300 if (status) {
6301 ALOGE("%s: initializing gcs hw session failed %d",
6302 __func__, status);
6303 goto cleanup;
6304 }
6305 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006306 st_ses->hw_ses_cpe =
6307 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
Quinn Male2e883752019-03-22 11:28:54 -07006308 if (!st_ses->hw_ses_cpe) {
6309 status = -ENOMEM;
6310 goto cleanup;
6311 }
6312 status = st_hw_sess_lsm_init(st_ses->hw_ses_cpe, hw_sess_cb,
6313 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6314 if (status) {
6315 ALOGE("%s: initializing lsm hw session failed %d",
6316 __func__, status);
6317 goto cleanup;
6318 }
6319 }
6320 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07006321 } else if (v_info && (EXEC_MODE_CFG_APE == v_info->exec_mode_cfg)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006322 /*
6323 * Check for merge sound model support and return the existing hw
6324 * session. If any other clients have already created it.
6325 */
6326 if (v_info->merge_fs_soundmodels) {
6327 if (!v_info->is_qcva_uuid) {
6328 ALOGE("%s: merge sound model not supported for non SVA engines",
6329 __func__);
6330 status = -ENOSYS;
6331 goto cleanup;
6332 }
6333 list_for_each(node, &stdev->sound_model_list) {
6334 c_ses = node_to_item(node, st_session_t, list_node);
6335 if ((c_ses != stc_ses) &&
6336 c_ses->vendor_uuid_info->is_qcva_uuid &&
6337 c_ses->vendor_uuid_info->merge_fs_soundmodels) {
6338 stc_ses->hw_proxy_ses = c_ses->hw_proxy_ses;
6339 list_add_tail(&stc_ses->hw_proxy_ses->clients_list,
6340 &stc_ses->hw_list_node);
6341 ALOGD("%s: another client attached: h%d <-- c%d", __func__,
6342 stc_ses->hw_proxy_ses->sm_handle, sm_handle);
6343 free(st_ses);
6344 st_ses = NULL;
6345 break;
6346 }
6347 }
6348 }
6349 if (st_ses) { /* If no other client exist */
6350 st_ses->hw_ses_adsp =
6351 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
6352 if (!st_ses->hw_ses_adsp) {
6353 status = -ENOMEM;
6354 goto cleanup;
6355 }
6356 status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
6357 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6358 if (status) {
6359 ALOGE("%s: initializing lsm hw session failed %d",
6360 __func__, status);
6361 goto cleanup;
6362 }
6363 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
6364 }
Quinn Male2e883752019-03-22 11:28:54 -07006365 } else if (v_info && (EXEC_MODE_CFG_ARM == v_info->exec_mode_cfg)) {
6366 st_ses->enable_trans = false;
6367 st_ses->hw_ses_arm = calloc(1, sizeof(st_hw_session_pcm_t));
6368 if (!st_ses->hw_ses_arm) {
6369 status = -ENOMEM;
6370 goto cleanup;
6371 }
6372 status = st_hw_sess_pcm_init(st_ses->hw_ses_arm, hw_sess_cb,
6373 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6374 if (status) {
6375 ALOGE("%s: initializing pcm hw session failed %d",
6376 __func__, status);
6377 goto cleanup;
6378 }
6379 st_ses->hw_ses_current = st_ses->hw_ses_arm;
6380 } else if (!v_info) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006381 st_ses->hw_ses_cpe =
6382 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
Quinn Male2e883752019-03-22 11:28:54 -07006383 if (!st_ses->hw_ses_cpe) {
6384 status = -ENOMEM;
6385 goto cleanup;
6386 }
6387 status = st_hw_sess_lsm_init(st_ses->hw_ses_cpe, hw_sess_cb,
6388 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6389 if (status) {
6390 ALOGE("%s: initializing lsm hw session failed %d",
6391 __func__, status);
6392 goto cleanup;
6393 }
6394 }
6395
6396 pthread_mutexattr_init(&attr);
6397 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006398 pthread_mutex_init(&stc_ses->lock, (const pthread_mutexattr_t *)&attr);
Quinn Male2e883752019-03-22 11:28:54 -07006399
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006400 stc_ses->exec_mode = exec_mode;
6401 stc_ses->sm_handle = sm_handle;
6402 stc_ses->ssr_transit_exec_mode = ST_EXEC_MODE_NONE;
6403 stc_ses->client_req_det_mode = ST_DET_UNKNOWN_MODE;
6404 stc_ses->state = ST_STATE_IDLE;
Quinn Male2e883752019-03-22 11:28:54 -07006405
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006406 if (st_ses) { /* Could get freed if other client exists */
Quinn Male23026702019-07-19 10:51:16 -07006407 st_ses->vendor_uuid_info = v_info;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006408 st_ses->exec_mode = exec_mode;
6409 st_ses->sm_handle = sm_handle;
6410 st_ses->lab_fp = NULL;
6411 pthread_mutex_init(&st_ses->lock, (const pthread_mutexattr_t *)&attr);
Quinn Male2e883752019-03-22 11:28:54 -07006412
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006413 stc_ses->hw_proxy_ses = st_ses;
6414 list_init(&st_ses->clients_list);
6415 list_add_tail(&st_ses->clients_list, &stc_ses->hw_list_node);
6416 ALOGD("%s: client attached: h%d <-- c%d", __func__,
6417 st_ses->sm_handle, sm_handle);
6418
6419 if (!stdev->ssr_offline_received) {
6420 STATE_TRANSITION(st_ses, idle_state_fn);
6421 } else {
6422 STATE_TRANSITION(st_ses, ssr_state_fn);
6423 status = 0;
6424 }
6425 }
Quinn Male2e883752019-03-22 11:28:54 -07006426 return status;
6427
6428cleanup:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006429 if (st_ses) {
6430 if (st_ses->hw_ses_cpe)
6431 free(st_ses->hw_ses_cpe);
6432 if (st_ses->hw_ses_adsp)
6433 free(st_ses->hw_ses_adsp);
6434 free(st_ses);
6435 }
Quinn Male2e883752019-03-22 11:28:54 -07006436 return status;
6437}
6438
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006439int st_session_deinit(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006440{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006441 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6442
6443 pthread_mutex_lock(&st_ses->lock);
6444 list_remove(&stc_ses->hw_list_node);
6445 ALOGV("%s: client detatched: h%d <-- c%d", __func__, st_ses->sm_handle,
6446 stc_ses->sm_handle);
6447 if (stc_ses == st_ses->det_stc_ses)
6448 st_ses->det_stc_ses = NULL;
6449
6450 if (!list_empty(&st_ses->clients_list)) {
6451 pthread_mutex_unlock(&st_ses->lock);
6452 return 0;
6453 }
Quinn Male2e883752019-03-22 11:28:54 -07006454 /* deinit cpe session */
6455 if (st_ses->hw_ses_cpe) {
6456 if (st_ses->stdev->is_gcs)
6457 st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
6458 else
6459 st_hw_sess_lsm_deinit(st_ses->hw_ses_cpe);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006460 free(st_ses->hw_ses_cpe);
Quinn Male2e883752019-03-22 11:28:54 -07006461 st_ses->hw_ses_cpe = NULL;
6462 }
Quinn Male2e883752019-03-22 11:28:54 -07006463 /* deinit adsp session */
6464 if (st_ses->hw_ses_adsp) {
6465 st_hw_sess_lsm_deinit(st_ses->hw_ses_adsp);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006466 free(st_ses->hw_ses_adsp);
Quinn Male2e883752019-03-22 11:28:54 -07006467 st_ses->hw_ses_adsp = NULL;
6468 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006469 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006470 pthread_mutex_destroy(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006471 free(stc_ses->hw_proxy_ses);
6472 stc_ses->hw_proxy_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07006473
6474 return 0;
6475}