blob: 5993fe51bd620bd0fde50c51cd08106186205c14 [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 *
7 * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
8 *
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
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -070068#define STATE_TRANSITION(st_session, new_state_fn)\
69do {\
70 if (st_session->current_state != new_state_fn) {\
71 st_session->current_state = new_state_fn;\
72 ALOGD("session[%d]: %s ---> %s", st_session->sm_handle, __func__, \
73 #new_state_fn);\
74 }\
75} while(0)
76
77#define DISPATCH_EVENT(st_session, event, status)\
78do {\
79 status = st_session->current_state(st_session, &event);\
80} while (0)
81
82#define REG_SM_RETRY_CNT 5
83#define REG_SM_WAIT_TIME_MS 100
84
85#define MAX_CONF_LEVEL_VALUE (100)
86#define MAX_KW_USERS_NAME_LEN (2 * MAX_STRING_LEN)
87
Quinn Male2e883752019-03-22 11:28:54 -070088/* below enum used in cleanup in error scenarios */
89enum hw_session_err_mask {
90 HW_SES_ERR_MASK_DEVICE_SET = 0x1,
91 HW_SES_ERR_MASK_REG_SM = 0x2,
92 HW_SES_ERR_MASK_REG_SM_PARAM = 0x4,
93 HW_SES_ERR_MASK_STARTED = 0x8,
94 HW_SES_ERR_MASK_BUFFERING = 0x10,
95};
96
Quinn Male2e883752019-03-22 11:28:54 -070097typedef struct st_session_loadsm_payload {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -070098 struct sound_trigger_phrase_sound_model *phrase_sm;
Quinn Male2e883752019-03-22 11:28:54 -070099} st_session_loadsm_payload_t;
100
101typedef struct st_session_start_payload {
102 void *config;
103 size_t config_size;
104 recognition_callback_t callback;
105 void *cookie;
106} st_session_start_payload_t;
107
108typedef struct st_session_read_pcm_payload {
109 void *out_buff;
110 size_t out_buff_size;
111 size_t *actual_read_size;
112} st_session_readpcm_payload_t;
113
114typedef struct st_session_get_param_payload {
115 const char *param;
116 void *payload;
117 size_t payload_size;
118 size_t *param_data_size;
119} st_session_getparam_payload_t;
120
121struct st_session_ev {
122 st_session_event_id_t ev_id;
123 union {
124 st_session_loadsm_payload_t loadsm;
125 st_session_start_payload_t start;
126 st_hw_sess_detected_ev_t detected;
127 st_exec_mode_t exec_mode;
128 st_session_readpcm_payload_t readpcm;
129 enum ssr_event_status ssr;
130 char *chmix_coeff_str;
131 bool enable;
132 st_session_getparam_payload_t getparam;
133 } payload;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700134 st_session_t *stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -0700135};
136
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700137static int idle_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
138static int loaded_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
139static int active_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
140static int detected_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
141static int buffering_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
142static int ssr_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
143
144static inline int process_detection_event
145(
146 st_proxy_session_t *st_ses, uint64_t timestamp, int detect_status,
147 void *payload, size_t payload_size,
148 struct sound_trigger_recognition_event **event
149);
150
Quinn Male3d7d9d42019-05-20 13:35:01 -0700151ST_DBG_DECLARE(static int file_cnt = 0);
Quinn Male2e883752019-03-22 11:28:54 -0700152
153void hw_sess_cb(st_hw_sess_event_t *hw_event, void *cookie)
154{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700155 st_proxy_session_t *st_ses = (st_proxy_session_t *)cookie;
Quinn Male2e883752019-03-22 11:28:54 -0700156 int status = 0;
157 int lock_status = 0;
158
159 if (!hw_event || !cookie) {
160 ALOGE("%s: received NULL params", __func__);
161 return;
162 }
163
164 switch (hw_event->event_id) {
165 case ST_HW_SESS_EVENT_DETECTED:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700166 {
167 st_session_ev_t ev;
168 ev.ev_id = ST_SES_EV_DETECTED;
169 ev.payload.detected = hw_event->payload.detected;
Quinn Male2e883752019-03-22 11:28:54 -0700170
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700171 do {
172 lock_status = pthread_mutex_trylock(&st_ses->lock);
173 } while (lock_status && !st_ses->device_disabled &&
174 (st_ses->exec_mode != ST_EXEC_MODE_NONE) &&
175 (st_ses->current_state != ssr_state_fn));
Quinn Male2e883752019-03-22 11:28:54 -0700176
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700177 if (st_ses->device_disabled) {
178 ALOGV("%s:[%d] device switch in progress, ignore event",
179 __func__, st_ses->sm_handle);
180 } else if (st_ses->exec_mode == ST_EXEC_MODE_NONE) {
181 ALOGV("%s:[%d] transition in progress, ignore event",
182 __func__, st_ses->sm_handle);
183 } else if (st_ses->current_state == ssr_state_fn) {
184 ALOGV("%s:[%d] SSR handling in progress, ignore event",
185 __func__, st_ses->sm_handle);
186 } else if (!lock_status) {
Quinn Male2e883752019-03-22 11:28:54 -0700187 /*
188 * TODO: Add RECOGNITION_STATUS_GET_STATE_RESPONSE to
189 * the SoundTrigger API header.
190 */
191 if (st_ses->detection_requested)
192 ev.payload.detected.detect_status = 3;
193
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700194 DISPATCH_EVENT(st_ses, ev, status);
Quinn Male2e883752019-03-22 11:28:54 -0700195 }
196
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700197 if (!lock_status)
198 pthread_mutex_unlock(&st_ses->lock);
199 break;
200 }
201
Quinn Male2e883752019-03-22 11:28:54 -0700202 default:
203 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
204 break;
205 };
206
207}
208
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700209static inline void free_array_ptrs(char **arr, unsigned int arr_len)
210{
211 int i = 0;
212
213 if (!arr)
214 return;
215
216 for (i = 0; i < arr_len; i++) {
217 if (arr[i]) {
218 free(arr[i]);
219 arr[i] = NULL;
220 }
221 }
222 free(arr);
223 arr = NULL;
224}
225
226static inline void alloc_array_ptrs(char ***arr, unsigned int arr_len,
227 unsigned int elem_len)
228{
229 char **str_arr = NULL;
230 int i = 0;
231
232 str_arr = (char **) calloc(arr_len, sizeof(char *));
233
234 if (!str_arr) {
235 *arr = NULL;
236 return;
237 }
238
239 for (i = 0; i < arr_len; i++) {
240 str_arr[i] = (char *) calloc(elem_len, sizeof(char));
241 if (str_arr[i] == NULL) {
242 free_array_ptrs(str_arr, i);
243 *arr = NULL;
244 return;
245 }
246 }
247 *arr = str_arr;
248 ALOGV("%s: string array %p", __func__, *arr);
249 for (i = 0; i < arr_len; i++)
250 ALOGV("%s: string array[%d] %p", __func__, i, (*arr)[i]);
251}
252
253
254static int merge_sound_models(struct sound_trigger_device *stdev,
255 unsigned int num_models, listen_model_type *in_models[],
256 listen_model_type *out_model)
257{
258 listen_status_enum sm_ret = 0;
259 int status = 0;
260
261 ALOGV("%s: num_models to merge %d", __func__, num_models);
262
263 if (!stdev->smlib_handle) {
264 ALOGE("%s: NULL sound model lib handle", __func__);
265 return -ENOSYS;
266 }
267
268 sm_ret = stdev->smlib_getMergedModelSize(num_models, in_models,
269 &out_model->size);
270 if ((sm_ret != kSucess) || !out_model->size) {
271 ALOGE("%s: smlib_getMergedModelSize failed, err %d, size %d", __func__,
272 sm_ret, out_model->size);
273 return -EINVAL;
274 }
275 ALOGD("%s: merge sound model size %d", __func__, out_model->size);
276
277 out_model->data = calloc(1, out_model->size * sizeof(char));
278 if (!out_model->data) {
279 ALOGE("%s: Merged sound model allocation failed", __func__);
280 return -ENOMEM;
281 }
282
283 sm_ret = stdev->smlib_mergeModels(num_models, in_models, out_model);
284 if (sm_ret != kSucess) {
285 ALOGE("%s: smlib_mergeModels failed, err %d", __func__, sm_ret);
286 status = -EINVAL;
287 goto cleanup;
288 }
289 if (!out_model->data || !out_model->size) {
290 ALOGE("%s: MergeModels returned NULL data or size %d", __func__,
291 out_model->size);
292 status = -EINVAL;
293 goto cleanup;
294 }
295 ALOGV("%s: Exit", __func__);
296 return 0;
297
298cleanup:
299 if (out_model->data) {
300 free(out_model->data);
301 out_model->data = NULL;
302 out_model->size = 0;
303 }
304 return status;
305}
306
307static int delete_from_merged_sound_model(struct sound_trigger_device *stdev,
308 char **keyphrases, unsigned int num_keyphrases,
309 listen_model_type *in_model, listen_model_type *out_model)
310{
311 listen_model_type merge_model = {0};
312 listen_status_enum sm_ret = 0;
313 unsigned int out_model_sz = 0;
314 int status = 0, i = 0;
315
316 out_model->data = NULL;
317 out_model->size = 0;
318 merge_model.data = in_model->data;
319 merge_model.size = in_model->size;
320
321 for (i = 0; i < num_keyphrases; i++) {
322 sm_ret = stdev->smlib_getSizeAfterDeleting(&merge_model, keyphrases[i],
323 NULL, &out_model_sz);
324 if (sm_ret != kSucess) {
325 ALOGE("%s: smlib_getSizeAfterDeleting failed %d", __func__, sm_ret);
326 status = -EINVAL;
327 goto cleanup;
328 }
329 if (out_model_sz >= in_model->size) {
330 ALOGE("%s: unexpected, smlib_getSizeAfterDeleting returned size %d"
331 "not less than merged model size %d", __func__,
332 out_model_sz, in_model->size);
333 status = -EINVAL;
334 goto cleanup;
335 }
336 ALOGV("%s: Size after deleting kw[%d] = %d", __func__, i, out_model_sz);
337 if (!out_model->data) {
338 /* Valid if deleting multiple keyphrases one after other */
339 free (out_model->data);
340 out_model->size = 0;
341 }
342 out_model->data = calloc(1, out_model_sz * sizeof(char));
343 if (!out_model->data) {
344 ALOGE("%s: Merge sound model allocation failed, size %d ", __func__,
345 out_model_sz);
346 status = -ENOMEM;
347 goto cleanup;
348 }
349 out_model->size = out_model_sz;
350
351 sm_ret = stdev->smlib_deleteFromModel(&merge_model, keyphrases[i],
352 NULL, out_model);
353 if (sm_ret != kSucess) {
354 ALOGE("%s: smlib_getSizeAfterDeleting failed %d", __func__, sm_ret);
355 status = -EINVAL;
356 goto cleanup;
357 }
358 if (out_model->size != out_model_sz) {
359 ALOGE("%s: unexpected, out_model size %d != expected size %d",
360 __func__, out_model->size, out_model_sz);
361 status = -EINVAL;
362 goto cleanup;
363 }
364 /* Used if deleting multiple keyphrases one after other */
365 merge_model.data = out_model->data;
366 merge_model.size = out_model->size;
367 }
368 return 0;
369
370cleanup:
371 if (out_model->data) {
372 free(out_model->data);
373 out_model->data = NULL;
374 }
375 return status;
376}
377
378static void release_sound_model_info(struct sound_model_info *sm_info)
379{
380 ALOGV("%s", __func__);
381
382 if (sm_info->cf_levels) {
383 free(sm_info->cf_levels);
384 sm_info->cf_levels = NULL;
385 sm_info->det_cf_levels = NULL;
386 }
387 free_array_ptrs(sm_info->keyphrases, sm_info->num_keyphrases);
388 sm_info->keyphrases = NULL;
389
390 free_array_ptrs(sm_info->users, sm_info->num_users);
391 sm_info->users = NULL;
392
393 free_array_ptrs(sm_info->cf_levels_kw_users, sm_info->cf_levels_size);
394 sm_info->cf_levels_kw_users = NULL;
395}
396
397static inline void stdbg_print_sound_model_header(
398 listen_sound_model_header *smh)
399{
400 int i = 0, j = 0;
401
402 ALOGV("%s", __func__);
403 ALOGV("numKeywords = %d", smh->numKeywords);
404 ALOGV("numUsers = %d", smh->numUsers);
405 ALOGV("numActiveUserKeywordPairs = %d", smh->numActiveUserKeywordPairs);
406 ALOGV("isStripped = %d", smh->isStripped);
407 ALOGV("model_indicator = %d", smh->model_indicator);
408
409 for (i = 0; i < smh->numKeywords; i++) {
410 ALOGV("kw-%d langPerKw = %d", i, smh->langPerKw[i]);
411 ALOGV("kw-%d numUsersSetPerKw = %d", i, smh->numUsersSetPerKw[i]);
412 ALOGV("kw-%d isUserDefinedKeyword = %d", i,
413 smh->isUserDefinedKeyword[i]);
414 }
415 if (smh->userKeywordPairFlags) {
416 for (i = 0; i < smh->numUsers; i++) {
417 for (j = 0; j < smh->numKeywords; j++)
418 ALOGV("userKeywordPairFlags[%d][%d] = %d", i, j,
419 smh->userKeywordPairFlags[i][j]);
420 }
421 }
422}
423
424static int query_sound_model(struct sound_trigger_device *stdev,
425 struct sound_model_info *sm_info, unsigned char *sm_data,
426 unsigned int sm_size)
427{
428 listen_sound_model_header sm_header = {0};
429 listen_model_type model = {0};
430 listen_status_enum sm_ret = 0;
431 int status = 0, i = 0, j = 0, k = 0;
432 uint16_t tmp = 0;
433
434 ALOGV("%s: enter sm_size %d", __func__, sm_size);
435
436 if (!stdev->smlib_handle) {
437 ALOGE("%s: NULL sound model lib handle", __func__);
438 return -ENOSYS;
439 }
440
441 model.data = sm_data;
442 model.size = sm_size;
443
444 sm_ret = stdev->smlib_getSoundModelHeader(&model, &sm_header);
445 if (sm_ret != kSucess) {
446 ALOGE("%s: smlib_getSoundModelHeader failed, err %d ", __func__, sm_ret);
447 return -EINVAL;
448 }
449 if (sm_header.numKeywords == 0) {
450 ALOGE("%s: num keywords zero!!", __func__);
451 return -EINVAL;
452 }
453 if (sm_header.numActiveUserKeywordPairs < sm_header.numUsers) {
454 ALOGE("%s: smlib activeUserKwPairs(%d) < total users (%d)", __func__,
455 sm_header.numActiveUserKeywordPairs, sm_header.numUsers);
456 goto cleanup;
457 }
458 if (sm_header.numUsers && !sm_header.userKeywordPairFlags) {
459 ALOGE("%s: userKeywordPairFlags is NULL, numUsers (%d)", __func__,
460 sm_header.numUsers);
461 goto cleanup;
462 }
463 stdbg_print_sound_model_header(&sm_header);
464
465 /* MAX_STRING_LEN is part of listen sound model header file */
466 alloc_array_ptrs(&sm_info->keyphrases, sm_header.numKeywords,
467 MAX_STRING_LEN);
468 if (!sm_info->keyphrases) {
469 ALOGE("%s: keyphrases allocation failed", __func__);
470 status = -ENOMEM;
471 goto cleanup;
472 }
473 sm_info->num_keyphrases = sm_header.numKeywords;
474 sm_info->num_users = sm_header.numUsers;
475
476 tmp = sm_header.numKeywords;
Zhou Songdeddfcc2019-06-18 22:25:03 +0800477 ALOGV("%s: stdb: model.data %pK, model.size %d", __func__, model.data,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700478 model.size);
479 sm_ret = stdev->smlib_getKeywordPhrases(&model, &tmp, sm_info->keyphrases);
480 if (sm_ret) {
481 ALOGE("%s: smlib_getKeywordPhrases failed, err %d ", __func__, sm_ret);
482 goto cleanup;
483 }
484 if (tmp != sm_header.numKeywords) {
485 ALOGE("%s: smlib_getkeywordPhrases(%d) != sml header (%d)", __func__,
486 tmp, sm_header.numKeywords);
487 goto cleanup;
488 }
489 for (i = 0; i < sm_header.numKeywords; i++)
490 ALOGV("%s: keyphrases names = %s", __func__, sm_info->keyphrases[i]);
491
492 if (sm_header.numUsers) {
493 alloc_array_ptrs(&sm_info->users, sm_header.numUsers, MAX_STRING_LEN);
494 if (!sm_info->users) {
495 ALOGE("%s: users allocation failed", __func__);
496 status = -ENOMEM;
497 goto cleanup;
498 }
499
500 tmp = sm_header.numUsers;
501 sm_ret = stdev->smlib_getUserNames(&model, &tmp, sm_info->users);
502 if (sm_ret) {
503 ALOGE("%s: smlib_getUserNames failed, err %d ", __func__, sm_ret);
504 goto cleanup;
505 }
506 if (tmp != sm_header.numUsers) {
507 ALOGE("%s: smlib_getUserNames(%d) != sml header (%d)", __func__,
508 tmp, sm_header.numUsers);
509 status = -EINVAL;
510 goto cleanup;
511 }
512 for (i = 0; i < sm_header.numUsers; i++)
513 ALOGV("%s: users names = %s", __func__, sm_info->users[i]);
514 }
515
516 sm_info->cf_levels_size = sm_header.numKeywords +
517 sm_header.numActiveUserKeywordPairs;
518 alloc_array_ptrs(&sm_info->cf_levels_kw_users, sm_info->cf_levels_size,
519 MAX_KW_USERS_NAME_LEN);
520 if (!sm_info->cf_levels_kw_users) {
521 ALOGE("%s: cf_levels_kw_users allocation failed", __func__);
522 status = -ENOMEM;
523 goto cleanup;
524 }
525
526 /* Used later for mapping client to/from merged DSP confidence levels */
527 sm_info->cf_levels = calloc(1, 2 * sm_info->cf_levels_size);
528 if (!sm_info->cf_levels) {
529 ALOGE("%s: cf_levels allocation failed", __func__);
530 status = -ENOMEM;
531 goto cleanup;
532 }
533 /*
534 * Used for updating detection confidence level values from DSP merged
535 * detection conf levels
536 */
537 sm_info->det_cf_levels = sm_info->cf_levels + sm_info->cf_levels_size;
538
539 /*
540 * Used for conf level setting to DSP. Reset the conf value to max value,
541 * so that the keyword of a loaded and in-active model in a merged model
542 * doesn't detect.
543 */
544 memset(sm_info->cf_levels, MAX_CONF_LEVEL_VALUE, sm_info->cf_levels_size);
545
546 /*
547 * Derive the confidence level payload for keyword and user pairs.
548 * Store the user-keyword pair names in an array that will be used for
549 * mapping the DSP detection and confidence levels to the client.
550 */
551 char **kw_names = sm_info->cf_levels_kw_users;
552 char **ukw_names = &sm_info->cf_levels_kw_users[sm_header.numKeywords];
553 int ukw_idx = 0;
554
555 for (i = 0; i < sm_header.numKeywords; i++) {
556 strlcpy(kw_names[i], sm_info->keyphrases[i], MAX_KW_USERS_NAME_LEN);
557 if (!sm_header.numUsersSetPerKw)
558 continue;
559 for (j = 0, k = 0; j < sm_header.numUsers; j++) {
560 if (k >= sm_header.numUsersSetPerKw[i])
561 break;
562 if (sm_header.userKeywordPairFlags[j][i]) {
563 strlcpy(ukw_names[ukw_idx], sm_info->users[j],
564 MAX_KW_USERS_NAME_LEN);
565 strlcat(ukw_names[ukw_idx], sm_info->keyphrases[i],
566 MAX_KW_USERS_NAME_LEN);
567 ukw_idx++;
568 k++;
569 }
570 }
571 }
572 for (i = 0; i < sm_info->cf_levels_size; i++)
573 ALOGV("%s: cf_levels_kw_users = %s", __func__,
574 sm_info->cf_levels_kw_users[i]);
575
576 sm_ret = stdev->smlib_releaseSoundModelHeader(&sm_header);
577 if (sm_ret != kSucess) {
578 ALOGE("%s: smlib_releaseSoundModelHeader failed, err %d ", __func__,
579 sm_ret);
580 status = -EINVAL;
581 goto cleanup_1;
582 }
583 ALOGV("%s: exit", __func__);
584 return 0;
585
586cleanup:
587 sm_ret = stdev->smlib_releaseSoundModelHeader(&sm_header);
588 if (sm_ret != kSucess)
589 ALOGE("%s: smlib_releaseSoundModelHeader failed, err %d ", __func__,
590 sm_ret);
591
592cleanup_1:
593 release_sound_model_info(sm_info);
594
595 return status;
596}
597
598static int add_sound_model(st_session_t *stc_ses, unsigned char *sm_data,
599 unsigned int sm_size)
600{
601 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
602 struct listnode *node = NULL;
603 st_session_t *c_ses = NULL;
604 listen_model_type **in_models = NULL;
605 listen_model_type out_model = {0};
606 struct sound_model_info sm_info = {0};
607 int status = 0, num_models = 0;
608
609 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
610 if (stc_ses->sm_info.sm_data) {
611 ALOGD("%s:[c%d] Already added", __func__, stc_ses->sm_handle);
612 return 0;
613 }
614 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels) {
615 stc_ses->sm_info.sm_data = sm_data;
616 stc_ses->sm_info.sm_size = sm_size;
617 st_ses->sm_info.sm_data = sm_data;
618 st_ses->sm_info.sm_size = sm_size;
619 st_ses->sm_info.sm_type = stc_ses->sm_type;
620 ALOGD("%s:[c%d] no merge", __func__, stc_ses->sm_handle);
621 return 0;
622 }
623 /* get sound model header information for client model */
624 status = query_sound_model(st_ses->stdev, &stc_ses->sm_info,
625 sm_data, sm_size);
626 if (status)
627 return status;
628
629 stc_ses->sm_info.sm_data = sm_data;
630 stc_ses->sm_info.sm_size = sm_size;
Zhou Songdeddfcc2019-06-18 22:25:03 +0800631 ALOGV("%s: stc_ses %pK - sm_data %pK, sm_size %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700632 stc_ses, stc_ses->sm_info.sm_data,
633 stc_ses->sm_info.sm_size);
634
635 /* Check for remaining client sound models to merge */
636 list_for_each(node, &st_ses->clients_list) {
637 c_ses = node_to_item(node, st_session_t, hw_list_node);
638 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data)
639 num_models++;
640 }
641 if (!num_models) {
642 if (st_ses->sm_info.sm_merged && st_ses->sm_info.sm_data) {
643 free(st_ses->sm_info.sm_data);
644 }
645 /* Only one current client model, just re-use it */
646 st_ses->recognition_mode = stc_ses->recognition_mode;
647 stc_ses->sm_info.sm_type = stc_ses->sm_type;
648 st_ses->sm_info = stc_ses->sm_info;
649 st_ses->sm_info.sm_merged = false;
650 ALOGD("%s: re-use single client c%d model, size %d", __func__,
651 stc_ses->sm_handle, stc_ses->sm_info.sm_size);
652 return 0;
653 }
654 ALOGV("%s: num existing models %d", __func__, num_models);
655 /*
656 * Merge this client model with already existing merged model due to other
657 * clients models.
658 */
659 if (!st_ses->sm_info.sm_data) {
660 if (num_models == 1) {
661 /*
662 * Its not a merged model yet, but proxy ses sm_data is valid and
663 * must be pointing to client sm_data
664 */
665 ALOGE("%s: Unexpected, sm_info.sm_data NULL, num current"
666 "models %d", __func__, num_models);
667 status = -EINVAL;
668 goto cleanup;
669 } else if (!st_ses->sm_info.sm_merged) {
670 ALOGE("%s: Unexpected, no pre-existing merged model, num current"
671 "models %d", __func__, num_models);
672 status = -EINVAL;
673 goto cleanup;
674 }
675 }
676
677 /* Merge this client model with remaining clients models */
678 num_models = 2;/* re-use */
679 alloc_array_ptrs((char***)&in_models, num_models, sizeof(listen_model_type));
680 if (!in_models) {
681 ALOGE("%s: in_models allocation failed", __func__);
682 status = -ENOMEM;
683 goto cleanup;
684 }
685 /* Add existing model */
686 in_models[0]->data = st_ses->sm_info.sm_data;
687 in_models[0]->size = st_ses->sm_info.sm_size;
688 /* Add this client model */
689 in_models[1]->data = sm_data;
690 in_models[1]->size = sm_size;
691
692 status = merge_sound_models(st_ses->stdev, 2, in_models, &out_model);
693 if (status)
694 goto cleanup;
695
696 sm_info.sm_data = out_model.data;
697 sm_info.sm_size = out_model.size;
698 sm_info.sm_merged = true;
699
700 status = query_sound_model(st_ses->stdev, &sm_info,
701 out_model.data, out_model.size);
702 if (status)
703 goto cleanup;
704
705 if (out_model.size < st_ses->sm_info.sm_size) {
706 ALOGE("%s: Unexpected, merged model sz %d < current sz %d",
707 __func__, out_model.size, st_ses->sm_info.sm_size);
708 release_sound_model_info(&sm_info);
709 status = -EINVAL;
710 goto cleanup;
711 }
712 free_array_ptrs((char **)in_models, num_models);
713 in_models = NULL;
714
715 /* Update the new merged model */
716 if (st_ses->sm_info.sm_merged && st_ses->sm_info.sm_data) {
717 release_sound_model_info(&st_ses->sm_info);
718 free(st_ses->sm_info.sm_data);
719 }
720 ALOGD("%s: Updated sound model: current size %d, new size %d", __func__,
721 st_ses->sm_info.sm_size, out_model.size);
722 st_ses->sm_info = sm_info;
723
724 /*
725 * If any of the clients has user identificaiton enabled, underlying
726 * hw session has to operate with user identification enabled.
727 */
728 if (stc_ses->recognition_mode & RECOGNITION_MODE_USER_IDENTIFICATION)
729 st_ses->recognition_mode |= stc_ses->recognition_mode;
730
731 return 0;
732
733cleanup:
734 release_sound_model_info(&stc_ses->sm_info);
735 stc_ses->sm_info.sm_data = NULL;
736
737 if (out_model.data)
738 free(out_model.data);
739
740 if (in_models)
741 free_array_ptrs((char **)in_models, num_models);
742
743 return status;
744}
745
746static int delete_sound_model(st_session_t *stc_ses)
747{
748 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
749 struct listnode *node = NULL;
750 st_session_t *c_ses = NULL, *c_ses_rem = NULL;
751 listen_model_type in_model = {0};
752 listen_model_type out_model = {0};
753 struct sound_model_info sm_info = {0};
754 int status = 0, num_models = 0;
755 unsigned int rec_mode = RECOGNITION_MODE_VOICE_TRIGGER;
756
757 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
758 if (!stc_ses->sm_info.sm_data) {
759 ALOGD("%s:[c%d] Already deleted", __func__, stc_ses->sm_handle);
760 return 0;
761 }
762 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels) {
763 /*
764 * As it directly points to client model, just set as NULL
765 * without freeing
766 */
767 st_ses->sm_info.sm_data = NULL;
768 stc_ses->sm_info.sm_data = NULL;
769 ALOGD("%s:[c%d] no merge", __func__, stc_ses->sm_handle);
770 return 0;
771 }
772
Zhou Songdeddfcc2019-06-18 22:25:03 +0800773 ALOGV("%s: stc_ses %pK - sm_data %pK, sm_size %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700774 stc_ses, stc_ses->sm_info.sm_data,
775 stc_ses->sm_info.sm_size);
776
777 /* Check for remaining clients sound models to merge */
778 list_for_each(node, &st_ses->clients_list) {
779 c_ses = node_to_item(node, st_session_t, hw_list_node);
780 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data) {
781 c_ses_rem = c_ses;
782 num_models++;
783 }
784 }
785 if (num_models == 0) {
786 ALOGD("%s: No remaining models", __func__);
787 /* Delete current client model */
788 release_sound_model_info(&stc_ses->sm_info);
789 stc_ses->sm_info.sm_data = NULL;
790 return 0;
791 }
792
793 if (num_models == 1) {
794 ALOGD("%s: reuse only remaining client model, size %d", __func__,
795 c_ses_rem->sm_info.sm_size);
796 /* If only one remaining client model exists, re-use it */
797 if (st_ses->sm_info.sm_merged) {
798 release_sound_model_info(&st_ses->sm_info);
799 if (st_ses->sm_info.sm_data)
800 free(st_ses->sm_info.sm_data);
801 }
802 st_ses->sm_info = c_ses_rem->sm_info;
803 st_ses->sm_info.sm_merged = false;
804 st_ses->hw_ses_current->sthw_cfg.conf_levels =
805 st_ses->sm_info.cf_levels;
806 st_ses->hw_ses_current->sthw_cfg.num_conf_levels =
807 st_ses->sm_info.cf_levels_size;
808 /* Delete current client model */
809 release_sound_model_info(&stc_ses->sm_info);
810 stc_ses->sm_info.sm_data = NULL;
811 return 0;
812 }
813 /* Update overall recogniton mode from remaining clients */
814 list_for_each(node, &st_ses->clients_list) {
815 c_ses = node_to_item(node, st_session_t, hw_list_node);
816 if ((c_ses != stc_ses) && c_ses->sm_info.sm_data) {
817 if (c_ses->recognition_mode == RECOGNITION_MODE_USER_IDENTIFICATION)
818 rec_mode |= RECOGNITION_MODE_USER_IDENTIFICATION;
819 }
820 }
821
822 /*
823 * Delete this client model with already existing merged model due to other
824 * clients models.
825 */
826 if (!st_ses->sm_info.sm_merged || !st_ses->sm_info.sm_data) {
827 ALOGE("%s: Unexpected, no pre-existing merged model to delete from,"
828 "num current models %d", __func__, num_models);
829 goto cleanup;
830 }
831
832 /* Existing merged model from which the current client model to be deleted */
833 in_model.data = st_ses->sm_info.sm_data;
834 in_model.size = st_ses->sm_info.sm_size;
835
836 status = delete_from_merged_sound_model(st_ses->stdev,
837 stc_ses->sm_info.keyphrases, stc_ses->sm_info.num_keyphrases,
838 &in_model, &out_model);
839
840 if (status)
841 goto cleanup;
842
843 sm_info.sm_data = out_model.data;
844 sm_info.sm_size = out_model.size;
845 sm_info.sm_merged = true;
846
847 /* Update existing merged model info with new merged model */
848 status = query_sound_model(st_ses->stdev, &sm_info, out_model.data,
849 out_model.size);
850 if (status)
851 goto cleanup;
852
853 if (out_model.size > st_ses->sm_info.sm_size) {
854 ALOGE("%s: Unexpected, merged model sz %d > current sz %d",
855 __func__, out_model.size, st_ses->sm_info.sm_size);
856 release_sound_model_info(&sm_info);
857 status = -EINVAL;
858 goto cleanup;
859 }
860
861 if (st_ses->sm_info.sm_merged && st_ses->sm_info.sm_data) {
862 release_sound_model_info(&st_ses->sm_info);
863 free(st_ses->sm_info.sm_data);
864 }
865
866 ALOGD("%s: Updated sound model: current size %d, new size %d", __func__,
867 st_ses->sm_info.sm_size, out_model.size);
868 st_ses->sm_info = sm_info;
869 /*
870 * If any of the remaining clients has user identificaiton enabled,
871 * underlying hw session has to operate with user identificaiton enabled.
872 */
873 st_ses->recognition_mode = rec_mode;
874
875 /* Release current client model */
876 release_sound_model_info(&stc_ses->sm_info);
877 stc_ses->sm_info.sm_data = NULL;
878
879 return 0;
880
881cleanup:
882 release_sound_model_info(&stc_ses->sm_info);
883 stc_ses->sm_info.sm_data = NULL;
884
885 if (out_model.data)
886 free(out_model.data);
887
888 return status;
889}
890
891static int update_sound_model(st_session_t *stc_ses, bool add)
892{
893 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
894 struct sound_trigger_phrase_sound_model *phrase_sm = stc_ses->phrase_sm;
895 struct sound_trigger_sound_model *common_sm =
896 (struct sound_trigger_sound_model*)stc_ses->phrase_sm;
897 unsigned char *sm_data = NULL;
898 unsigned int sm_size = 0;
899 int status = 0;
900
901 ALOGV("%s: Enter", __func__);
902
903 if (stc_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
904 sm_data = (unsigned char*)phrase_sm + phrase_sm->common.data_offset;
905 sm_size = phrase_sm->common.data_size;
906 } else {
907 sm_data = (unsigned char*)common_sm + common_sm->data_offset;
908 sm_size = common_sm->data_size;
909 }
910
911 pthread_mutex_lock(&st_ses->lock);
912 if (add)
913 status = add_sound_model(stc_ses, sm_data, sm_size);
914 else
915 status = delete_sound_model(stc_ses);
916 pthread_mutex_unlock(&st_ses->lock);
917
918 ALOGV("%s: Exit", __func__);
919 return status;
920}
921
922static int update_merge_conf_levels_payload(st_proxy_session_t *st_ses,
923 struct sound_model_info *src_sm_info, unsigned char *src,
924 unsigned int src_size, bool set)
925{
926 int i = 0, j = 0;
927
928 if (!st_ses || !src) {
929 ALOGE("%s: NULL pointer", __func__);
930 return -EINVAL;
931 }
932
933 if (!st_ses->sm_info.sm_merged)
934 return 0;
935
936 if (src_size > st_ses->sm_info.cf_levels_size) {
937 ALOGE("%s:[%d] Unexpected, client conf levels %d > "
938 "merged conf levels %d", __func__, st_ses->sm_handle,
939 src_size, st_ses->sm_info.cf_levels_size);
940 return -EINVAL;
941 }
942
943 for (i = 0; i < src_size; i++)
944 ALOGV("%s: src cf_levels[%d]=%d", __func__, i, src[i]);
945
946 /* Populate DSP merged sound model conf levels */
947 for (i = 0; i < src_size; i++) {
948 for (j = 0; j < st_ses->sm_info.cf_levels_size; j++) {
949 if (!strcmp(st_ses->sm_info.cf_levels_kw_users[j],
950 src_sm_info->cf_levels_kw_users[i])) {
951 if (set) {
952 st_ses->sm_info.cf_levels[j] = src[i];
953 ALOGV("%s: set: sm_info.cf_levels[%d]=%d", __func__,
954 j, st_ses->sm_info.cf_levels[j]);
955 } else {
956 st_ses->sm_info.cf_levels[j] = MAX_CONF_LEVEL_VALUE;
957 ALOGV("%s: reset: sm_info.cf_levels[%d]=%d", __func__,
958 j, st_ses->sm_info.cf_levels[j]);
959 }
960 }
961 }
962 }
963 return 0;
964}
965
966static int update_merge_conf_levels_payload_with_active_clients(
967 st_proxy_session_t *st_ses)
968{
969 int status = 0;
970 struct listnode *node = NULL;
971 st_session_t *c_ses = NULL;
972
973 list_for_each(node, &st_ses->clients_list) {
974 c_ses = node_to_item(node, st_session_t, hw_list_node);
975 if (c_ses->state == ST_STATE_ACTIVE) {
976 ALOGV("%s: update merge conf levels with other active"
977 "client %d ", __func__, c_ses->sm_handle);
978 status = update_merge_conf_levels_payload(st_ses,
979 &c_ses->sm_info, c_ses->sm_info.cf_levels,
980 c_ses->sm_info.cf_levels_size, true);
981 if (status)
982 return status;
983 }
984 }
985 return status;
986}
987
988static void check_and_extract_det_conf_levels_payload(
989 st_proxy_session_t *st_ses,
990 unsigned char *src, unsigned int src_size,
991 unsigned char **dst, unsigned int *dst_size)
992{
993 st_session_t *stc_ses = st_ses->det_stc_ses;
994 int i = 0, j = 0;
995
996 *dst = src;
997 *dst_size = src_size;
998
999 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
1000 !st_ses->sm_info.sm_merged) {
1001 ALOGV("%s:[%d] not merged", __func__, st_ses->sm_handle);
1002 return;
1003 }
1004
1005 if (src_size < st_ses->sm_info.cf_levels_size) {
1006 ALOGE("%s:[%d] Unexpected, detection conf payload size %d < %d",
1007 __func__, st_ses->sm_handle, src_size,
1008 st_ses->sm_info.cf_levels_size);
1009 return;
1010 }
1011
1012 /* Reset any cached previous detection values */
1013 memset(stc_ses->sm_info.det_cf_levels, 0, stc_ses->sm_info.cf_levels_size);
1014
1015 /* Extract the client conf level values from DSP payload */
1016 for(i = 0; i < st_ses->sm_info.cf_levels_size; i++) {
1017 if (!src[i])
1018 continue;
1019 for(j = 0; j < stc_ses->sm_info.cf_levels_size; j++) {
1020 if (!strcmp(stc_ses->sm_info.cf_levels_kw_users[j],
1021 st_ses->sm_info.cf_levels_kw_users[i])) {
1022 stc_ses->sm_info.det_cf_levels[j] = src[i];
1023 }
1024 }
1025 }
1026 for (i = 0; i < stc_ses->sm_info.cf_levels_size; i++)
1027 ALOGD("%s: c%d det_cf_levels[%d]=%d", __func__, stc_ses->sm_handle, i,
1028 stc_ses->sm_info.det_cf_levels[i]);
1029
1030 *dst = stc_ses->sm_info.det_cf_levels;
1031 *dst_size = stc_ses->sm_info.cf_levels_size;
1032}
1033
1034static inline bool check_for_multi_clients(st_proxy_session_t *st_ses)
1035{
1036 struct listnode *node = NULL;
1037 int cnt = 0;
1038
1039 list_for_each(node, &st_ses->clients_list) {
1040 if (++cnt > 1)
1041 return true;
1042 }
1043 return false;
1044}
1045
1046static inline bool is_other_client_attached(st_proxy_session_t *st_ses,
1047 st_session_t *stc_ses)
1048{
1049 struct listnode *node = NULL;
1050 st_session_t *c_ses = NULL;
1051
1052 list_for_each(node, &st_ses->clients_list) {
1053 c_ses = node_to_item(node, st_session_t, hw_list_node);
1054 if (c_ses != stc_ses)
1055 return true;
1056 }
1057 return false;
1058}
1059
1060static inline void reset_clients_pending_load(st_proxy_session_t *st_ses)
1061{
1062 struct listnode *node = NULL;
1063 st_session_t *c_ses = NULL;
1064
1065 list_for_each(node, &st_ses->clients_list) {
1066 c_ses = node_to_item(node, st_session_t, hw_list_node);
1067 c_ses->pending_load = false;
1068 }
1069}
1070
1071static inline int is_any_client_not_pending_load(st_proxy_session_t *st_ses)
1072{
1073 struct listnode *node = NULL;
1074 st_session_t *c_ses = NULL;
1075
1076 list_for_each(node, &st_ses->clients_list) {
1077 c_ses = node_to_item(node, st_session_t, hw_list_node);
1078 if (!c_ses->pending_load)
1079 return true;
1080 }
1081 return false;
1082}
1083
1084static inline int is_any_client_not_pending_set_device(
1085 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 if (!c_ses->pending_set_device)
1093 return true;
1094 }
1095 return false;
1096}
1097
1098static inline void reset_clients_pending_set_device(st_proxy_session_t *st_ses)
1099{
1100 struct listnode *node = NULL;
1101 st_session_t *c_ses = NULL;
1102
1103 list_for_each(node, &st_ses->clients_list) {
1104 c_ses = node_to_item(node, st_session_t, hw_list_node);
1105 c_ses->pending_set_device = false;
1106 }
1107}
1108
1109static bool check_and_get_other_active_client(st_proxy_session_t *st_ses,
1110 st_session_t *stc_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 != stc_ses) && (c_ses->state == ST_STATE_ACTIVE))
1118 return c_ses;
1119 }
1120 return NULL;
1121}
1122
1123static inline bool is_any_client_paused(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 if (c_ses->paused)
1131 return true;
1132 }
1133 return false;
1134}
1135
1136static inline bool is_any_client_in_state(st_proxy_session_t *st_ses,
1137 enum client_states_t state)
1138{
1139 struct listnode *node = NULL;
1140 st_session_t *c_ses = NULL;
1141
1142 list_for_each(node, &st_ses->clients_list) {
1143 c_ses = node_to_item(node, st_session_t, hw_list_node);
1144 if (c_ses->state == state)
1145 return true;
1146 }
1147 return false;
1148}
1149
1150static void update_hw_config_on_restart(st_proxy_session_t *st_ses,
1151 st_session_t *stc_ses)
1152{
1153 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
1154 struct st_hw_ses_config *sthw_cfg = &hw_ses->sthw_cfg;
1155 struct listnode *node = NULL;
1156 st_session_t *c_ses = NULL;
1157 int hb_sz = 0, pr_sz = 0;
1158 bool enable_lab = false;
1159
1160 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
1161 !st_ses->sm_info.sm_merged)
1162 return;
1163
1164 /*
1165 * Adjust history buffer and preroll durations to highest of
1166 * all clients, including current restarting client.
1167 * If any of the clients requested capture or enabled the
1168 * second stage, the underlying hw session buffering needs to be
1169 * enabled.
1170 */
1171 list_for_each(node, &st_ses->clients_list) {
1172 c_ses = node_to_item(node, st_session_t, hw_list_node);
1173 if ((c_ses == stc_ses) || (c_ses->state == ST_STATE_ACTIVE)) {
1174 if (hb_sz < c_ses->hist_buf_duration)
1175 hb_sz = c_ses->hist_buf_duration;
1176 if (pr_sz < c_ses->preroll_duration)
1177 pr_sz = c_ses->preroll_duration;
1178 if (!enable_lab)
1179 enable_lab = (c_ses->rc_config &&
1180 c_ses->rc_config->capture_requested) ||
1181 !list_empty(&c_ses->second_stage_list);
1182 }
1183 }
1184
1185 sthw_cfg->client_req_hist_buf = hb_sz;
1186 sthw_cfg->client_req_preroll = pr_sz;
1187 st_ses->lab_enabled = enable_lab;
1188
1189 update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
1190 stc_ses->sm_info.cf_levels,
1191 stc_ses->sm_info.cf_levels_size,
1192 true);
1193 hw_ses->sthw_cfg_updated = true;
1194
1195 ALOGV("%s:[%d] lab_enabled %d, hb_sz %d, pr_sz %d", __func__,
1196 st_ses->sm_handle, st_ses->lab_enabled,
1197 sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
1198}
1199
1200static bool update_hw_config_on_stop(st_proxy_session_t *st_ses,
1201 st_session_t *stc_ses)
1202{
1203 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
1204 struct st_hw_ses_config *sthw_cfg = &hw_ses->sthw_cfg;
1205 struct listnode *node = NULL;
1206 st_session_t *c_ses = NULL;
1207 int hb_sz = 0, pr_sz = 0;
1208 bool active = false, enable_lab = false;
1209
1210 if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
1211 !st_ses->sm_info.sm_merged) {
1212 if (sthw_cfg->conf_levels) {
1213 ALOGV("%s: free hw conf_levels", __func__);
1214 free(sthw_cfg->conf_levels);
1215 sthw_cfg->conf_levels = NULL;
1216 }
1217 return false;
1218 }
1219 /*
1220 * Adjust history buffer and preroll durations to highest of
1221 * remaining clients.
1222 * If any of the remaining clients requested capture or enabled the
1223 * second stage, the underlying hw session buffering needs to be
1224 * enabled.
1225 */
1226 list_for_each(node, &st_ses->clients_list) {
1227 c_ses = node_to_item(node, st_session_t, hw_list_node);
1228 if ((c_ses != stc_ses) && (c_ses->state == ST_STATE_ACTIVE)) {
1229 active = true;
1230 if (hb_sz < c_ses->hist_buf_duration)
1231 hb_sz = c_ses->hist_buf_duration;
1232 if (pr_sz < c_ses->preroll_duration)
1233 pr_sz = c_ses->preroll_duration;
1234 if (!enable_lab)
1235 enable_lab = c_ses->rc_config->capture_requested ||
1236 !list_empty(&c_ses->second_stage_list);
1237 }
1238 }
1239 if (!active) {
1240 sthw_cfg->client_req_hist_buf = 0;
1241 sthw_cfg->client_req_preroll = 0;
1242 st_ses->lab_enabled = 0;
1243 sthw_cfg->custom_data = NULL;
1244 sthw_cfg->custom_data_size = 0;
1245 hw_ses->sthw_cfg_updated = true;
1246 ALOGV("%s:[%d] no active client hw cfg is reset", __func__,
1247 st_ses->sm_handle);
1248 return false;
1249 }
1250
1251 sthw_cfg->client_req_hist_buf = hb_sz;
1252 sthw_cfg->client_req_preroll = pr_sz;
1253 st_ses->lab_enabled = enable_lab;
1254
1255 update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
1256 stc_ses->sm_info.cf_levels,
1257 stc_ses->sm_info.cf_levels_size,
1258 false);
1259 hw_ses->sthw_cfg_updated = true;
1260
1261 ALOGV("%s:[%d] lab_enabled %d, hb_sz %d, pr_sz %d", __func__,
1262 st_ses->sm_handle, st_ses->lab_enabled,
1263 sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
1264
1265 return active;
1266}
1267
1268static void get_conf_levels_from_dsp_payload(st_proxy_session_t *st_ses,
1269 unsigned char *payload, unsigned int payload_size,
1270 unsigned char **conf_levels, unsigned int *conf_levels_size)
1271{
1272 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
1273 uint32_t key_id = 0, key_payload_size = 0;
1274 unsigned int i = 0;
1275
1276 if (hw_ses->is_generic_event) {
1277 while (i < payload_size) {
1278 key_id = *(uint32_t *)payload;
1279 key_payload_size = *((uint32_t *)payload + 1);
1280
1281 if (key_id == KEY_ID_CONFIDENCE_LEVELS) {
1282 *conf_levels = payload + (4 * sizeof(uint32_t));
1283 *conf_levels_size = *((uint32_t *)payload + 3);;
1284 ALOGV("%s: generic_event: DSP num conf levels %d", __func__,
1285 *conf_levels_size);
1286 break;
1287 }
1288 i += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
1289 payload += i;
1290 }
1291 } else {
1292 if ((st_ses->exec_mode == ST_EXEC_MODE_CPE) && st_ses->stdev->is_gcs) {
1293 *conf_levels = payload + 2;
1294 *conf_levels_size = payload_size - 2;
1295 } else {
1296 *conf_levels = payload;
1297 *conf_levels_size = payload_size;
1298 }
1299 }
1300}
1301
1302st_session_t* get_detected_client(st_proxy_session_t *st_ses,
1303 unsigned char *payload, unsigned int payload_size)
1304{
1305 struct listnode *node = NULL;
1306 st_session_t *c_ses = NULL;
1307 unsigned char *conf_levels = NULL;
1308 unsigned int conf_levels_size = 0;
1309 int i = 0, j = 0;
1310
1311 if (list_empty(&st_ses->clients_list)) {
1312 ALOGE("%s:[%d] no clients attached!!", __func__, st_ses->sm_handle);
1313 return NULL;
1314 }
1315 /*
1316 * If only single client exist, this detection is not for merged
1317 * sound model, hence return this as only available client
1318 */
1319 if (!check_for_multi_clients(st_ses)) {
1320 ALOGV("%s:[%d] single client detection", __func__, st_ses->sm_handle);
1321 node = list_head(&st_ses->clients_list);
1322 c_ses = node_to_item(node, st_session_t, hw_list_node);
1323 if (c_ses->state == ST_STATE_ACTIVE) {
1324 ALOGD("%s: detected c%d", __func__, c_ses->sm_handle);
1325 return c_ses;
1326 } else {
1327 ALOGE("%s: detected c%d is not active", __func__, c_ses->sm_handle);
1328 return NULL;
1329 }
1330 }
1331
1332 get_conf_levels_from_dsp_payload(st_ses, payload, payload_size,
1333 &conf_levels, &conf_levels_size);
1334 if (!conf_levels) {
1335 ALOGE("%s:[%d] no conf levels payload found!!", __func__,
1336 st_ses->sm_handle);
1337 return NULL;
1338 }
1339 if (conf_levels_size < st_ses->sm_info.num_keyphrases) {
1340 ALOGE("%s:[%d] detection conf levels size %d < num of keywords %d",
1341 __func__, st_ses->sm_handle, conf_levels_size,
1342 st_ses->sm_info.num_keyphrases);
1343 return NULL;
1344 }
1345
1346 /*
1347 * The DSP payload contains the keyword conf levels from the beginning.
1348 * Only one keyword conf level is expected to be non-zero from keyword
1349 * detection. Find non-zero conf level up to number of keyphrases and if
1350 * one is found, match it to the corresponding keyphrase from list of
1351 * clients to obtain the detected client.
1352 */
1353 for (i = 0; i < st_ses->sm_info.num_keyphrases; i++) {
1354 if (!conf_levels[i])
1355 continue;
1356 list_for_each(node, &st_ses->clients_list) {
1357 c_ses = node_to_item(node, st_session_t, hw_list_node);
1358 for (j = 0; j < c_ses->sm_info.num_keyphrases; j++) {
1359 if (!strcmp(st_ses->sm_info.keyphrases[i],
1360 c_ses->sm_info.keyphrases[j])) {
1361 if (c_ses->state == ST_STATE_ACTIVE) {
1362 ALOGV("%s: detected c%d", __func__, c_ses->sm_handle);
1363 return c_ses;
1364 } else {
1365 ALOGE("%s: detected c%d is not active", __func__,
1366 c_ses->sm_handle);
1367 return NULL;
1368 }
1369 }
1370 }
1371 }
1372 }
1373 return c_ses;
1374}
1375
1376static int fill_conf_levels_payload_from_rc_config
1377(
1378 const struct sound_trigger_phrase_sound_model *phrase_sm,
1379 const struct sound_trigger_recognition_config *rc_config,
1380 unsigned char *conf_levels,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001381 unsigned int total_num_users
1382)
1383{
1384 int status = 0;
1385 unsigned int user_level, user_id;
1386 unsigned int i = 0, j = 0;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001387 unsigned int num_conf_levels = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001388 unsigned char *user_id_tracker;
1389
Zhou Songdeddfcc2019-06-18 22:25:03 +08001390 if (!phrase_sm || !rc_config || !conf_levels) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001391 ALOGE("%s: ERROR. Invalid inputs",__func__);
1392 return -EINVAL;
1393 }
1394
Zhou Songdeddfcc2019-06-18 22:25:03 +08001395 if ((UINT32_MAX - total_num_users) > rc_config->num_phrases)
1396 num_conf_levels = total_num_users + rc_config->num_phrases;
1397
1398 if (!num_conf_levels) {
1399 ALOGE("%s: ERROR. Invalid num_conf_levels input", __func__);
1400 return -EINVAL;
1401 }
1402
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001403 /* Example: Say the recognition structure has 3 keywords with users
1404 * |kid|
1405 * [0] k1 |uid|
1406 * [3] u1 - 1st trainer
1407 * [4] u2 - 4th trainer
1408 * [6] u3 - 3rd trainer
1409 * [1] k2
1410 * [5] u2 - 2nd trainer
1411 * [7] u3 - 5th trainer
1412 * [2] k3
1413 * [8] u4 - 6th trainer
1414 *
1415 * Output confidence level array will be
1416 * [k1, k2, k3, u1k1, u2k1, u2k2, u3k1, u3k2, u4k3]
1417 */
1418
1419 user_id_tracker = calloc(1, num_conf_levels);
1420 if (!user_id_tracker) {
1421 ALOGE("%s: failed to allocate user_id_tracker", __func__);
1422 return -ENOMEM;
1423 }
1424
1425 for (i = 0; i < rc_config->num_phrases; i++) {
1426 ALOGV("%s: [%d] kw level %d", __func__, i,
1427 rc_config->phrases[i].confidence_level);
1428 for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
1429 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
1430 rc_config->phrases[i].levels[j].user_id,
1431 rc_config->phrases[i].levels[j].level);
1432 }
1433 }
1434
1435 for (i = 0; i < rc_config->num_phrases; i++) {
Zhou Songdeddfcc2019-06-18 22:25:03 +08001436 if (i < num_conf_levels) {
1437 conf_levels[i] = rc_config->phrases[i].confidence_level;
1438 } else {
1439 ALOGE("%s: ERROR. Invalid number of phrases", __func__);
1440 status = -EINVAL;
1441 goto exit;
1442 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001443 for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
1444 user_level = rc_config->phrases[i].levels[j].level;
1445 user_id = rc_config->phrases[i].levels[j].user_id;
1446 if ((user_id < rc_config->num_phrases) ||
1447 (user_id >= num_conf_levels)) {
1448 ALOGE("%s: ERROR. Invalid params user id %d>%d",
1449 __func__, user_id, total_num_users);
1450 status = -EINVAL;
1451 goto exit;
1452 } else {
1453 if (user_id_tracker[user_id] == 1) {
1454 ALOGE("%s: ERROR. Duplicate user id %d",
1455 __func__, user_id);
1456 status = -EINVAL;
1457 goto exit;
1458 }
1459 conf_levels[user_id] = (user_level < 100) ? user_level: 100;
1460 user_id_tracker[user_id] = 1;
1461 ALOGV("%s: user_conf_levels[%d] = %d", __func__,
1462 user_id, conf_levels[user_id]);
1463 }
1464 }
1465 }
1466
1467exit:
1468 free(user_id_tracker);
1469 return status;
1470}
1471
1472int generate_conf_levels_payload_from_rc_config
1473(
1474 const struct sound_trigger_phrase_sound_model *phrase_sm,
1475 const struct sound_trigger_recognition_config *rc_config,
1476 unsigned char **out_payload,
1477 unsigned int *out_payload_size
1478)
1479{
1480 int status = 0;
1481 unsigned int total_num_users = 0, num_conf_levels = 0;
1482 unsigned int i = 0, j = 0;
1483 unsigned char *conf_levels = NULL;
1484
1485 if (!phrase_sm || !rc_config || !out_payload || !out_payload_size) {
1486 ALOGE("%s: ERROR. Invalid inputs",__func__);
1487 status = -EINVAL;
1488 goto exit;
1489 }
1490 *out_payload = NULL;
1491 *out_payload_size = 0;
1492
1493 if((rc_config->num_phrases == 0) ||
1494 (rc_config->num_phrases > phrase_sm->num_phrases)) {
1495 ALOGE("%s: ERROR. Invalid phrases %d!=%d",__func__,
1496 rc_config->num_phrases, phrase_sm->num_phrases);
1497 status = -EINVAL;
1498 goto exit;
1499 }
1500 for (i = 0; i < rc_config->num_phrases; i++) {
1501 for (j = 0; j < rc_config->phrases[i].num_levels; j++)
1502 total_num_users++;
1503 }
1504
1505 num_conf_levels = total_num_users + rc_config->num_phrases;
1506 conf_levels = calloc(1, num_conf_levels);
1507 if (!conf_levels) {
1508 ALOGE("%s: ERROR. conf levels alloc failed",__func__);
1509 status = -ENOMEM;
1510 goto exit;
1511 }
1512
1513 status = fill_conf_levels_payload_from_rc_config(phrase_sm, rc_config,
Zhou Songdeddfcc2019-06-18 22:25:03 +08001514 conf_levels, total_num_users);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001515 if (status) {
1516 ALOGE("%s: fill config payload failed, error %d", __func__, status);
1517 goto exit;
1518 }
1519
1520 *out_payload = conf_levels;
1521 *out_payload_size = num_conf_levels;
1522
1523 return status;
1524
1525exit:
1526 if (conf_levels)
1527 free(conf_levels);
1528 return status;
1529}
1530
1531int generate_conf_levels_payload_from_rc_config_v2
1532(
1533 const struct sound_trigger_phrase_sound_model *phrase_sm,
1534 const struct sound_trigger_recognition_config *rc_config,
1535 unsigned char **out_payload,
1536 unsigned int *out_payload_size
1537)
1538{
1539 int status = 0;
1540 unsigned int total_num_users = 0, num_conf_levels = 0;
1541 unsigned char *conf_levels = NULL;
1542 unsigned int i = 0, j = 0;
1543
1544 ALOGV("%s: Enter...", __func__);
1545
1546 if (!phrase_sm || !rc_config || !out_payload || !out_payload_size) {
1547 ALOGE("%s: ERROR. Invalid inputs",__func__);
1548 status = -EINVAL;
1549 goto exit;
1550 }
1551 *out_payload = NULL;
1552 *out_payload_size = 0;
1553
1554 if((rc_config->num_phrases == 0) ||
1555 (rc_config->num_phrases > phrase_sm->num_phrases)) {
1556 ALOGE("%s: ERROR. Invalid phrases %d!=%d",__func__,
1557 rc_config->num_phrases, phrase_sm->num_phrases);
1558 status = -EINVAL;
1559 goto exit;
1560 }
1561 for (i = 0; i < rc_config->num_phrases; i++) {
1562 for (j = 0; j < rc_config->phrases[i].num_levels; j++)
1563 total_num_users++;
1564 }
1565
1566 num_conf_levels = total_num_users + rc_config->num_phrases;
1567 /*
1568 * allocate dsp payload w/additional 2 bytes for minor_version and
1569 * num_active_models and additional num_conf_levels for KW enable
1570 * fields
1571 */
1572 conf_levels = calloc(1, 2 + 2 * num_conf_levels);
1573 if (!conf_levels) {
1574 ALOGE("%s: ERROR. conf levels alloc failed",__func__);
1575 status = -ENOMEM;
1576 goto exit;
1577 }
1578
1579 conf_levels[0] = 1; /* minor version */
1580 conf_levels[1] = num_conf_levels; /* num_active_models */
1581 status = fill_conf_levels_payload_from_rc_config(phrase_sm, rc_config,
Zhou Songdeddfcc2019-06-18 22:25:03 +08001582 conf_levels + 2, total_num_users);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001583 if (status) {
1584 ALOGE("%s: fill config payload failed, error %d", __func__, status);
1585 goto exit;
1586 }
1587
1588 /*
1589 * set KW enable fields to 1 for now
1590 * TODO: set appropriately based on what client is passing in rc_config
1591 */
1592 memset(&conf_levels[num_conf_levels + 2], 0x1, num_conf_levels);
1593 ALOGV("%s: here", __func__);
1594 *out_payload = conf_levels;
1595 /* add size of minor version and num_active_models */
1596 *out_payload_size = 2 + 2 * num_conf_levels;
1597 return status;
1598
1599exit:
1600 if (conf_levels)
1601 free(conf_levels);
1602 return status;
1603}
1604
1605static int fill_sound_trigger_recognition_config_payload
1606(
1607 const void *sm_levels_generic,
1608 unsigned char *conf_levels,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001609 unsigned int total_num_users,
1610 uint32_t version
1611)
1612{
1613 int status = 0;
1614 unsigned int user_level = 0, user_id = 0;
1615 unsigned int i = 0, j = 0;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001616 unsigned int num_conf_levels = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001617 unsigned char *user_id_tracker = NULL;
1618 struct st_sound_model_conf_levels *sm_levels = NULL;
1619 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
1620
1621 /* Example: Say the recognition structure has 3 keywords with users
1622 * |kid|
1623 * [0] k1 |uid|
1624 * [3] u1 - 1st trainer
1625 * [4] u2 - 4th trainer
1626 * [6] u3 - 3rd trainer
1627 * [1] k2
1628 * [5] u2 - 2nd trainer
1629 * [7] u3 - 5th trainer
1630 * [2] k3
1631 * [8] u4 - 6th trainer
1632 *
1633 * Output confidence level array will be
1634 * [k1, k2, k3, u1k1, u2k1, u2k2, u3k1, u3k2, u4k3]
1635 */
1636
1637 if (version != CONF_LEVELS_INTF_VERSION_0002) {
1638 sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001639 if (!sm_levels || !conf_levels) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001640 ALOGE("%s: ERROR. Invalid inputs", __func__);
1641 return -EINVAL;
1642 }
Zhou Songdeddfcc2019-06-18 22:25:03 +08001643
1644 if ((UINT32_MAX - total_num_users) > sm_levels->num_kw_levels)
1645 num_conf_levels = total_num_users + sm_levels->num_kw_levels;
1646
1647 if (!num_conf_levels) {
1648 ALOGE("%s: ERROR. Invalid num_conf_levels input", __func__);
1649 return -EINVAL;
1650 }
1651
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001652 user_id_tracker = calloc(1, num_conf_levels);
1653 if (!user_id_tracker) {
1654 ALOGE("%s: failed to allocate user_id_tracker", __func__);
1655 return -ENOMEM;
1656 }
1657
1658 for (i = 0; i < sm_levels->num_kw_levels; i++) {
1659 ALOGV("%s: [%d] kw level %d", __func__, i,
1660 sm_levels->kw_levels[i].kw_level);
1661 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++) {
1662 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
1663 sm_levels->kw_levels[i].user_levels[j].user_id,
1664 sm_levels->kw_levels[i].user_levels[j].level);
1665 }
1666 }
1667
1668 for (i = 0; i < sm_levels->num_kw_levels; i++) {
Zhou Songdeddfcc2019-06-18 22:25:03 +08001669 if (i < num_conf_levels) {
1670 conf_levels[i] = sm_levels->kw_levels[i].kw_level;
1671 } else {
1672 ALOGE("%s: ERROR. Invalid numver of kw levels", __func__);
1673 status = -EINVAL;
1674 goto exit;
1675 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001676 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++) {
1677 user_level = sm_levels->kw_levels[i].user_levels[j].level;
1678 user_id = sm_levels->kw_levels[i].user_levels[j].user_id;
1679 if ((user_id < sm_levels->num_kw_levels) ||
1680 (user_id >= num_conf_levels)) {
1681 ALOGE("%s: ERROR. Invalid params user id %d>%d",
1682 __func__, user_id, total_num_users);
1683 status = -EINVAL;
1684 goto exit;
1685 } else {
1686 if (user_id_tracker[user_id] == 1) {
1687 ALOGE("%s: ERROR. Duplicate user id %d",
1688 __func__, user_id);
1689 status = -EINVAL;
1690 goto exit;
1691 }
1692 conf_levels[user_id] = (user_level < 100) ?
1693 user_level: 100;
1694 user_id_tracker[user_id] = 1;
1695 ALOGV("%s: user_conf_levels[%d] = %d", __func__,
1696 user_id, conf_levels[user_id]);
1697 }
1698 }
1699 }
1700 } else {
1701 sm_levels_v2 =
1702 (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
Zhou Songdeddfcc2019-06-18 22:25:03 +08001703 if (!sm_levels_v2 || !conf_levels) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001704 ALOGE("%s: ERROR. Invalid inputs", __func__);
1705 return -EINVAL;
1706 }
Zhou Songdeddfcc2019-06-18 22:25:03 +08001707
1708 if ((UINT32_MAX - total_num_users) > sm_levels_v2->num_kw_levels)
1709 num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
1710
1711 if (!num_conf_levels) {
1712 ALOGE("%s: ERROR. Invalid num_conf_levels input", __func__);
1713 return -EINVAL;
1714 }
1715
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001716 user_id_tracker = calloc(1, num_conf_levels);
1717 if (!user_id_tracker) {
1718 ALOGE("%s: failed to allocate user_id_tracker", __func__);
1719 return -ENOMEM;
1720 }
1721
1722 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
1723 ALOGV("%s: [%d] kw level %d", __func__, i,
1724 sm_levels_v2->kw_levels[i].kw_level);
1725 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++) {
1726 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
1727 sm_levels_v2->kw_levels[i].user_levels[j].user_id,
1728 sm_levels_v2->kw_levels[i].user_levels[j].level);
1729 }
1730 }
1731
1732 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
Zhou Songdeddfcc2019-06-18 22:25:03 +08001733 if (i < num_conf_levels) {
1734 conf_levels[i] = sm_levels_v2->kw_levels[i].kw_level;
1735 } else {
1736 ALOGE("%s: ERROR. Invalid numver of kw levels", __func__);
1737 status = -EINVAL;
1738 goto exit;
1739 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001740 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++) {
1741 user_level = sm_levels_v2->kw_levels[i].user_levels[j].level;
1742 user_id = sm_levels_v2->kw_levels[i].user_levels[j].user_id;
1743 if ((user_id < sm_levels_v2->num_kw_levels) ||
1744 (user_id >= num_conf_levels)) {
1745 ALOGE("%s: ERROR. Invalid params user id %d>%d",
1746 __func__, user_id, total_num_users);
1747 status = -EINVAL;
1748 goto exit;
1749 } else {
1750 if (user_id_tracker[user_id] == 1) {
1751 ALOGE("%s: ERROR. Duplicate user id %d",
1752 __func__, user_id);
1753 status = -EINVAL;
1754 goto exit;
1755 }
1756 conf_levels[user_id] = (user_level < 100) ?
1757 user_level: 100;
1758 user_id_tracker[user_id] = 1;
1759 ALOGV("%s: user_conf_levels[%d] = %d", __func__,
1760 user_id, conf_levels[user_id]);
1761 }
1762 }
1763 }
1764 }
1765
1766exit:
1767 free(user_id_tracker);
1768 return status;
1769}
1770
1771static int generate_sound_trigger_recognition_config_payload
1772(
1773 const void *sm_levels_generic,
1774 unsigned char **out_payload,
1775 unsigned int *out_payload_size,
1776 uint32_t version
1777)
1778{
1779 int status = 0;
1780 unsigned int total_num_users = 0, num_conf_levels = 0;
1781 unsigned char *conf_levels = NULL;
1782 unsigned int i = 0, j = 0;
1783 struct st_sound_model_conf_levels *sm_levels = NULL;
1784 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
1785
1786 ALOGV("%s: Enter...", __func__);
1787
1788 if (version != CONF_LEVELS_INTF_VERSION_0002) {
1789 sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
1790 if (!sm_levels || !out_payload || !out_payload_size) {
1791 ALOGE("%s: ERROR. Invalid inputs", __func__);
1792 status = -EINVAL;
1793 goto exit;
1794 }
1795 *out_payload = NULL;
1796 *out_payload_size = 0;
1797
1798 if (sm_levels->num_kw_levels == 0) {
1799 ALOGE("%s: ERROR. No confidence levels present", __func__);
1800 status = -EINVAL;
1801 goto exit;
1802 }
1803 for (i = 0; i < sm_levels->num_kw_levels; i++) {
1804 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++)
1805 total_num_users++;
1806 }
1807
1808 num_conf_levels = total_num_users + sm_levels->num_kw_levels;
1809 conf_levels = calloc(1, num_conf_levels);
1810 if (!conf_levels) {
1811 ALOGE("%s: ERROR. conf levels alloc failed", __func__);
1812 status = -ENOMEM;
1813 goto exit;
1814 }
1815 } else {
1816 sm_levels_v2 =
1817 (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
1818 if (!sm_levels_v2 || !out_payload || !out_payload_size) {
1819 ALOGE("%s: ERROR. Invalid inputs", __func__);
1820 status = -EINVAL;
1821 goto exit;
1822 }
1823 *out_payload = NULL;
1824 *out_payload_size = 0;
1825
1826 if (sm_levels_v2->num_kw_levels == 0) {
1827 ALOGE("%s: ERROR. No confidence levels present", __func__);
1828 status = -EINVAL;
1829 goto exit;
1830 }
1831 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
1832 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++)
1833 total_num_users++;
1834 }
1835
1836 num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
1837 conf_levels = calloc(1, num_conf_levels);
1838 if (!conf_levels) {
1839 ALOGE("%s: ERROR. conf levels alloc failed", __func__);
1840 status = -ENOMEM;
1841 goto exit;
1842 }
1843 }
1844
1845 status = fill_sound_trigger_recognition_config_payload(sm_levels_generic,
Zhou Songdeddfcc2019-06-18 22:25:03 +08001846 conf_levels, total_num_users, version);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001847 if (status) {
1848 ALOGE("%s: fill config payload failed, error %d", __func__, status);
1849 goto exit;
1850 }
1851
1852 *out_payload = conf_levels;
1853 *out_payload_size = num_conf_levels;
1854
1855 return status;
1856
1857exit:
1858 if (conf_levels)
1859 free(conf_levels);
1860
1861 return status;
1862}
1863
1864static int generate_sound_trigger_recognition_config_payload_v2
1865(
1866 const void *sm_levels_generic,
1867 unsigned char **out_payload,
1868 unsigned int *out_payload_size,
1869 uint32_t version
1870)
1871{
1872 int status = 0;
1873 unsigned int total_num_users = 0, num_conf_levels = 0;
1874 unsigned char *conf_levels = NULL;
1875 unsigned int i = 0, j = 0;
1876 struct st_sound_model_conf_levels *sm_levels = NULL;
1877 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
1878
1879 ALOGV("%s: Enter...", __func__);
1880
1881 if (version != CONF_LEVELS_INTF_VERSION_0002) {
1882 sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
1883 if (!sm_levels || !out_payload || !out_payload_size) {
1884 ALOGE("%s: ERROR. Invalid inputs", __func__);
1885 status = -EINVAL;
1886 goto exit;
1887 }
1888 *out_payload = NULL;
1889 *out_payload_size = 0;
1890
1891 if (sm_levels->num_kw_levels == 0) {
1892 ALOGE("%s: ERROR. No confidence levels present", __func__);
1893 status = -EINVAL;
1894 goto exit;
1895 }
1896 for (i = 0; i < sm_levels->num_kw_levels; i++) {
1897 for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++)
1898 total_num_users++;
1899 }
1900
1901 num_conf_levels = total_num_users + sm_levels->num_kw_levels;
1902 } else {
1903 sm_levels_v2 =
1904 (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
1905 if (!sm_levels_v2 || !out_payload || !out_payload_size) {
1906 ALOGE("%s: ERROR. Invalid inputs", __func__);
1907 status = -EINVAL;
1908 goto exit;
1909 }
1910 *out_payload = NULL;
1911 *out_payload_size = 0;
1912
1913 if (sm_levels_v2->num_kw_levels == 0) {
1914 ALOGE("%s: ERROR. No confidence levels present", __func__);
1915 status = -EINVAL;
1916 goto exit;
1917 }
1918 for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
1919 for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++)
1920 total_num_users++;
1921 }
1922 num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
1923 }
1924
1925 /*
1926 * allocate dsp payload w/additional 2 bytes for minor_version and
1927 * num_active_models and additional num_conf_levels for KW enable
1928 * fields
1929 */
1930 conf_levels = calloc(1, 2 + 2 * num_conf_levels);
1931 if (!conf_levels) {
1932 ALOGE("%s: ERROR. conf levels alloc failed", __func__);
1933 status = -ENOMEM;
1934 goto exit;
1935 }
1936
1937 conf_levels[0] = 1; /* minor version */
1938 conf_levels[1] = num_conf_levels; /* num_active_models */
1939 status = fill_sound_trigger_recognition_config_payload(sm_levels_generic,
Zhou Songdeddfcc2019-06-18 22:25:03 +08001940 conf_levels + 2, total_num_users, version);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001941 if (status) {
1942 ALOGE("%s: fill config payload failed, error %d", __func__, status);
1943 goto exit;
1944 }
1945
1946 /* set KW enable fields to 1 for now
1947 * TODO set appropriately based on what client is passing in rc_config
1948 */
1949 memset(&conf_levels[num_conf_levels + 2], 0x1, num_conf_levels);
1950 ALOGV("%s: here", __func__);
1951 *out_payload = conf_levels;
1952 /* add size of minor version and num_active_models */
1953 *out_payload_size = 2 + 2 * num_conf_levels;
1954
1955 return status;
1956
1957exit:
1958 if (conf_levels)
1959 free(conf_levels);
1960
1961 return status;
1962}
1963
1964static int parse_rc_config_key_conf_levels
1965(
1966 st_session_t *stc_ses,
1967 st_hw_session_t *st_hw_ses,
1968 void *opaque_conf_levels,
1969 unsigned char **out_conf_levels,
1970 unsigned int *out_num_conf_levels
1971)
1972{
1973 struct st_confidence_levels_info *conf_levels = NULL;
1974 struct st_confidence_levels_info_v2 *conf_levels_v2 = NULL;
1975 struct st_sound_model_conf_levels *sm_levels = NULL;
1976 struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
1977 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
1978 struct listnode *node = NULL;
1979 st_lsm_ss_config_t *ss_cfg = NULL;
1980 st_arm_second_stage_t *st_sec_stage = NULL;
1981 int status = 0;
1982 uint32_t i = 0;
1983 bool gmm_conf_found = false;
1984 uint8_t confidence_level = 0;
1985 int32_t confidence_level_v2 = 0;
1986 bool arm_second_stage = !list_empty(&stc_ses->second_stage_list);
1987 bool adsp_second_stage = (st_hw_ses == st_ses->hw_ses_adsp &&
1988 !list_empty(&st_hw_ses->lsm_ss_cfg_list));
1989
1990 if (arm_second_stage || adsp_second_stage) {
1991 if (stc_ses->rc_config->num_phrases > 1) {
1992 ALOGE("%s: Multi keyword is unsupported with 2nd stage detection",
1993 __func__);
1994 return -EINVAL;
1995 }
1996
1997 if (stc_ses->rc_config->phrases[0].num_levels > 1) {
1998 ALOGE("%s: Multi user is unsupported with 2nd stage detection",
1999 __func__);
2000 return -EINVAL;
2001 }
2002 }
2003
2004 if (stc_ses->st_conf_levels) {
2005 free(stc_ses->st_conf_levels);
2006 stc_ses->st_conf_levels = NULL;
2007 }
2008
2009 if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002) {
2010 conf_levels = (struct st_confidence_levels_info *)
2011 ((char *)opaque_conf_levels + sizeof(struct st_param_header));
2012
2013 stc_ses->st_conf_levels =
2014 calloc(1, sizeof(struct st_confidence_levels_info));
2015 if (!stc_ses->st_conf_levels) {
2016 ALOGE("%s: failed to alloc st_conf_levels", __func__);
2017 return -ENOMEM;
2018 }
2019 /* Cache to use during detection event processing */
2020 memcpy(stc_ses->st_conf_levels, (char *)conf_levels,
2021 sizeof(struct st_confidence_levels_info));
2022
2023 for (i = 0; i < conf_levels->num_sound_models; i++) {
2024 sm_levels = &conf_levels->conf_levels[i];
2025 if (sm_levels->sm_id == ST_SM_ID_SVA_GMM) {
2026 if ((st_ses->stdev->is_gcs) && (st_hw_ses == st_ses->hw_ses_cpe))
2027 status =
2028 generate_sound_trigger_recognition_config_payload_v2(
2029 (void *)sm_levels, out_conf_levels, out_num_conf_levels,
2030 stc_ses->conf_levels_intf_version);
2031 else
2032 status =
2033 generate_sound_trigger_recognition_config_payload(
2034 (void *)sm_levels, out_conf_levels, out_num_conf_levels,
2035 stc_ses->conf_levels_intf_version);
2036 gmm_conf_found = true;
2037 } else if ((sm_levels->sm_id == ST_SM_ID_SVA_CNN) ||
2038 (sm_levels->sm_id == ST_SM_ID_SVA_VOP)) {
2039 confidence_level = (sm_levels->sm_id == ST_SM_ID_SVA_CNN) ?
2040 sm_levels->kw_levels[0].kw_level:
2041 sm_levels->kw_levels[0].user_levels[0].level;
2042 if (arm_second_stage) {
2043 list_for_each(node, &stc_ses->second_stage_list) {
2044 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
2045 list_node);
2046 if (st_sec_stage->ss_info->sm_id == sm_levels->sm_id)
2047 st_sec_stage->ss_session->confidence_threshold =
2048 confidence_level;
2049 }
2050 } else if (adsp_second_stage) {
2051 list_for_each(node, &st_hw_ses->lsm_ss_cfg_list) {
2052 ss_cfg = node_to_item(node, st_lsm_ss_config_t,
2053 list_node);
2054 if (ss_cfg->ss_info->sm_id == sm_levels->sm_id)
2055 ss_cfg->confidence_threshold = confidence_level;
2056 }
2057 }
2058 } else {
2059 ALOGE("%s: Unsupported sm id (%d), exiting", __func__,
2060 sm_levels->sm_id);
2061 status = -EINVAL;
2062 break;
2063 }
2064 }
2065 } else {
2066 conf_levels_v2 = (struct st_confidence_levels_info_v2 *)
2067 ((char *)opaque_conf_levels + sizeof(struct st_param_header));
2068
2069 stc_ses->st_conf_levels =
2070 calloc(1, sizeof(struct st_confidence_levels_info_v2));
2071 if (!stc_ses->st_conf_levels) {
2072 ALOGE("%s: failed to alloc st_conf_levels", __func__);
2073 return -ENOMEM;
2074 }
2075 /* Cache to use during detection event processing */
2076 memcpy(stc_ses->st_conf_levels, (char *)conf_levels_v2,
2077 sizeof(struct st_confidence_levels_info_v2));
2078
2079 for (i = 0; i < conf_levels_v2->num_sound_models; i++) {
2080 sm_levels_v2 = &conf_levels_v2->conf_levels[i];
2081 if (sm_levels_v2->sm_id == ST_SM_ID_SVA_GMM) {
2082 if ((st_ses->stdev->is_gcs) &&
2083 (st_hw_ses == st_ses->hw_ses_cpe))
2084 status =
2085 generate_sound_trigger_recognition_config_payload_v2(
2086 (void *)sm_levels_v2, out_conf_levels, out_num_conf_levels,
2087 stc_ses->conf_levels_intf_version);
2088 else
2089 status =
2090 generate_sound_trigger_recognition_config_payload(
2091 (void *)sm_levels_v2, out_conf_levels,
2092 out_num_conf_levels, stc_ses->conf_levels_intf_version);
2093 gmm_conf_found = true;
2094 } else if ((sm_levels_v2->sm_id == ST_SM_ID_SVA_CNN) ||
2095 (sm_levels_v2->sm_id == ST_SM_ID_SVA_VOP)) {
2096 confidence_level_v2 =
2097 (sm_levels_v2->sm_id == ST_SM_ID_SVA_CNN) ?
2098 sm_levels_v2->kw_levels[0].kw_level:
2099 sm_levels_v2->kw_levels[0].user_levels[0].level;
2100 if (arm_second_stage) {
2101 list_for_each(node, &stc_ses->second_stage_list) {
2102 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
2103 list_node);
2104 if (st_sec_stage->ss_info->sm_id ==
2105 sm_levels_v2->sm_id)
2106 st_sec_stage->ss_session->confidence_threshold =
2107 confidence_level_v2;
2108 }
2109 } else if (adsp_second_stage) {
2110 list_for_each(node, &st_hw_ses->lsm_ss_cfg_list) {
2111 ss_cfg = node_to_item(node, st_lsm_ss_config_t,
2112 list_node);
2113 if (ss_cfg->ss_info->sm_id == sm_levels_v2->sm_id)
2114 ss_cfg->confidence_threshold = confidence_level_v2;
2115 }
2116 }
2117 } else {
2118 ALOGE("%s: Unsupported sm id (%d), exiting", __func__,
2119 sm_levels_v2->sm_id);
2120 status = -EINVAL;
2121 break;
2122 }
2123 }
2124 }
2125
2126 if (!gmm_conf_found) {
2127 ALOGE("%s: Did not receive GMM confidence threshold, error!", __func__);
2128 status = -EINVAL;
2129 }
2130
2131 if (status && stc_ses->st_conf_levels) {
2132 free(stc_ses->st_conf_levels);
2133 stc_ses->st_conf_levels = NULL;
2134 }
2135 return status;
2136}
2137
2138static int update_hw_config_on_start(st_session_t *stc_ses,
2139 st_hw_session_t *st_hw_ses)
2140{
2141 struct st_param_header *param_hdr = NULL;
2142 struct st_hist_buffer_info *hist_buf = NULL;
2143 struct st_det_perf_mode_info *det_perf_mode = NULL;
2144 struct sound_trigger_recognition_config *rc_config = stc_ses->rc_config;
2145 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
2146 struct st_vendor_info *v_info = NULL;
2147 struct st_hw_ses_config *sthw_cfg = NULL;
2148 unsigned char *conf_levels = NULL;
2149 unsigned int num_conf_levels = 0;
2150 uint8_t *opaque_ptr = NULL;
2151 unsigned int opaque_size = 0, conf_levels_payload_size = 0;
2152 int status = 0;
2153 bool enable_lab = false;
2154
2155
2156 ST_DBG_DECLARE(FILE *rc_opaque_fd = NULL; static int rc_opaque_cnt = 0);
2157 ST_DBG_FILE_OPEN_WR(rc_opaque_fd, ST_DEBUG_DUMP_LOCATION,
2158 "rc_config_opaque_data", "bin", rc_opaque_cnt++);
2159 ST_DBG_FILE_WRITE(rc_opaque_fd,
2160 (uint8_t *)rc_config + rc_config->data_offset,
2161 rc_config->data_size);
2162 ST_DBG_FILE_CLOSE(rc_opaque_fd);
2163
2164 if (!st_hw_ses) {
2165 ALOGE("%s: NULL hw session !!!", __func__);
2166 return -EINVAL;
2167 }
2168
2169 v_info = st_hw_ses->vendor_uuid_info;
2170
2171 if ((rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
2172 v_info->is_qcva_uuid) {
2173 stc_ses->client_req_det_mode = ST_DET_UNKNOWN_MODE;
2174
2175 opaque_ptr = (uint8_t *)rc_config + rc_config->data_offset;
2176 while (opaque_size < rc_config->data_size) {
2177 param_hdr = (struct st_param_header *)opaque_ptr;
2178 ALOGV("%s: key %d, payload size %d", __func__,
2179 param_hdr->key_id, param_hdr->payload_size);
2180
2181 switch(param_hdr->key_id) {
2182 case ST_PARAM_KEY_CONFIDENCE_LEVELS:
2183 stc_ses->conf_levels_intf_version =
2184 *(uint32_t *)(opaque_ptr + sizeof(struct st_param_header));
2185
2186 if (stc_ses->conf_levels_intf_version !=
2187 CONF_LEVELS_INTF_VERSION_0002) {
2188 conf_levels_payload_size =
2189 sizeof(struct st_confidence_levels_info);
2190 } else {
2191 conf_levels_payload_size =
2192 sizeof(struct st_confidence_levels_info_v2);
2193 }
2194 if (param_hdr->payload_size != conf_levels_payload_size) {
2195 ALOGE("%s: Conf level format error, exiting", __func__);
2196 return -EINVAL;
2197 }
2198 status = parse_rc_config_key_conf_levels(stc_ses, st_hw_ses,
2199 opaque_ptr, &conf_levels, &num_conf_levels);
2200 opaque_size += sizeof(struct st_param_header) +
2201 conf_levels_payload_size;
2202 opaque_ptr += sizeof(struct st_param_header) +
2203 conf_levels_payload_size;
2204 if (status) {
2205 ALOGE("%s: parsing conf levels failed(status=%d)",
2206 __func__, status);
2207 return -EINVAL;
2208 }
2209 break;
2210 case ST_PARAM_KEY_HISTORY_BUFFER_CONFIG:
2211 if (param_hdr->payload_size !=
2212 sizeof(struct st_hist_buffer_info)) {
2213 ALOGE("%s: History buffer config format error, exiting",
2214 __func__);
2215 return -EINVAL;
2216 }
2217 hist_buf = (struct st_hist_buffer_info *)(opaque_ptr +
2218 sizeof(struct st_param_header));
2219 stc_ses->hist_buf_duration =
2220 hist_buf->hist_buffer_duration_msec;
2221 stc_ses->preroll_duration = hist_buf->pre_roll_duration_msec;
2222 ALOGV("%s: recognition config history buf len = %d, "
2223 "preroll len = %d, minor version = %d",
2224 __func__, hist_buf->hist_buffer_duration_msec,
2225 hist_buf->pre_roll_duration_msec, hist_buf->version);
2226 opaque_size += sizeof(struct st_param_header) +
2227 sizeof(struct st_hist_buffer_info);
2228 opaque_ptr += sizeof(struct st_param_header) +
2229 sizeof(struct st_hist_buffer_info);
2230 break;
2231 case ST_PARAM_KEY_DETECTION_PERF_MODE:
2232 if (param_hdr->payload_size !=
2233 sizeof(struct st_det_perf_mode_info)) {
2234 ALOGE("%s: Opaque data format error, exiting", __func__);
2235 return -EINVAL;
2236 }
2237 det_perf_mode = (struct st_det_perf_mode_info *)(opaque_ptr +
2238 sizeof(struct st_param_header));
2239 ALOGV("set perf mode to %d", det_perf_mode->mode);
2240 stc_ses->client_req_det_mode = det_perf_mode->mode;
2241 opaque_size += sizeof(struct st_param_header) +
2242 sizeof(struct st_det_perf_mode_info);
2243 opaque_ptr += sizeof(struct st_param_header) +
2244 sizeof(struct st_det_perf_mode_info);
2245 break;
2246 default:
2247 ALOGE("%s: Unsupported opaque data key id, exiting", __func__);
2248 return -EINVAL;
2249 }
2250 }
2251 } else if (stc_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
2252 struct sound_trigger_phrase_sound_model *phrase_sm = stc_ses->phrase_sm;
2253
2254 ALOGV("%s: num_phrases=%d, id=%d", __func__,
2255 rc_config->num_phrases, rc_config->phrases[0].id);
2256
2257 if (st_ses->vendor_uuid_info->is_qcva_uuid ||
2258 st_ses->vendor_uuid_info->is_qcmd_uuid) {
2259 if (st_ses->stdev->is_gcs && st_hw_ses == st_ses->hw_ses_cpe)
2260 status = generate_conf_levels_payload_from_rc_config_v2(
2261 phrase_sm, rc_config, &conf_levels, &num_conf_levels);
2262 else
2263 status = generate_conf_levels_payload_from_rc_config(
2264 phrase_sm, rc_config, &conf_levels, &num_conf_levels);
2265 if (status || !conf_levels) {
2266 ALOGE("%s: failed to get conf levels from lib handle",
2267 __func__);
2268 return status;
2269 }
2270 } else {
2271 ALOGD("%s: No smlib, opaque data would be sent as is", __func__);
2272 }
2273 }
2274
2275 sthw_cfg = &st_hw_ses->sthw_cfg;
2276 enable_lab = stc_ses->rc_config->capture_requested ||
2277 !list_empty(&stc_ses->second_stage_list);
2278
2279 if (v_info->merge_fs_soundmodels) {
2280 /* merge_fs_soundmodels is true only for QC SVA UUID */
2281
2282 /*
2283 * Note:
2284 * For ADSP case, the generated conf levles size must be equal to
2285 * SML queried conf levels.
2286 * For WDSP gcs case, there is additional payload for KW enable
2287 * fields in generated conf_levels. If merge sound model is supported
2288 * on WDSP case, update logic here accordingly.
2289 */
2290 if (num_conf_levels != stc_ses->sm_info.cf_levels_size) {
2291 ALOGE("%s: Unexpected, client cf levels %d != sm_info cf levels %d",
2292 __func__, num_conf_levels, stc_ses->sm_info.cf_levels_size);
2293 return -EINVAL;
2294 }
2295
2296 /*
2297 * If any of the active clients requested capture or enabled the
2298 * second stage, the underlying hw session buffering needs to
2299 * be enabled. Ignore if it is already enabled.
2300 */
2301 if (!st_ses->lab_enabled && enable_lab)
2302 st_ses->lab_enabled = true;
2303
2304 /* Aggregate DSP configuration for highest client configuration */
2305
2306 /* SVA2.0 sound models */
2307 if (!stc_ses->hist_buf_duration &&
2308 stc_ses->rc_config->capture_requested &&
2309 (stc_ses->rc_config->data_size > 0)) {
2310 stc_ses->hist_buf_duration = st_ses->vendor_uuid_info->kw_duration;
2311 stc_ses->preroll_duration = 0;
2312 }
2313
2314 if (stc_ses->hist_buf_duration > sthw_cfg->client_req_hist_buf)
2315 sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
2316 if (stc_ses->preroll_duration > sthw_cfg->client_req_preroll)
2317 sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
2318
2319 ALOGV("%s: client hb_sz %d pr_sz %d, sthw lab %d hb_sz %d "
2320 "pr_sz %d", __func__, stc_ses->hist_buf_duration,
2321 stc_ses->preroll_duration, st_ses->lab_enabled,
2322 sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
2323
2324 /* Cache it to use when client restarts without config update or
2325 * during only one remaining client model as there won't be a
2326 * merged model yet.
2327 */
2328 memcpy(stc_ses->sm_info.cf_levels, conf_levels,
2329 stc_ses->sm_info.cf_levels_size);
2330
2331 status = update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
2332 conf_levels, num_conf_levels, true);
2333 free(conf_levels); /* Merged model conf levels will be used further */
2334 if (status)
2335 return status;
2336
2337 sthw_cfg->conf_levels = st_ses->sm_info.cf_levels;
2338 sthw_cfg->num_conf_levels = st_ses->sm_info.cf_levels_size;
2339 st_hw_ses->sthw_cfg_updated = true;
2340
2341 /*
2342 * Merging further unknown custom data is not needed, as
2343 * SVA doesn't support unkown custom data. if required in future,
2344 * handle here.
2345 * For now just copy the the current client data which is same
2346 * across SVA engines.
2347 */
2348 if (!sthw_cfg->custom_data) {
2349 sthw_cfg->custom_data = (char *)rc_config + rc_config->data_offset;
2350 if (rc_config->data_size)
2351 sthw_cfg->custom_data_size = rc_config->data_size;
2352 }
2353
2354 } else {
2355 st_ses->recognition_mode = stc_ses->recognition_mode;
2356 st_ses->lab_enabled = enable_lab;
2357
2358 sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
2359 sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
2360
2361 if (sthw_cfg->conf_levels)
2362 free(sthw_cfg->conf_levels);
2363 sthw_cfg->conf_levels = conf_levels;
2364 sthw_cfg->num_conf_levels = num_conf_levels;
2365
2366 sthw_cfg->custom_data = (char *)rc_config + rc_config->data_offset;
2367 sthw_cfg->custom_data_size = rc_config->data_size;
2368 }
2369 ALOGD("%s:[%d] lab enabled %d", __func__, st_ses->sm_handle,
2370 st_ses->lab_enabled);
2371
2372 return status;
2373}
2374
2375static void do_hw_sess_cleanup(st_proxy_session_t *st_ses,
2376 st_hw_session_t *hw_ses, enum hw_session_err_mask err)
Quinn Male2e883752019-03-22 11:28:54 -07002377{
2378 if (err & HW_SES_ERR_MASK_BUFFERING)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002379 hw_ses->fptrs->stop_buffering(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002380
2381 if (err & HW_SES_ERR_MASK_STARTED) {
2382 hw_ses->fptrs->stop(hw_ses);
2383 st_ses->hw_session_started = false;
2384 }
2385
2386 if (err & HW_SES_ERR_MASK_REG_SM_PARAM)
2387 hw_ses->fptrs->dereg_sm_params(hw_ses);
2388
2389 if (err & HW_SES_ERR_MASK_DEVICE_SET)
2390 hw_ses->fptrs->set_device(hw_ses, false);
2391
2392 if (err & HW_SES_ERR_MASK_REG_SM)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002393 hw_ses->fptrs->dereg_sm(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002394}
2395
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002396static void reg_hal_event_session(st_session_t *stc_ses,
2397 st_hw_session_t *hw_ses)
Quinn Male2e883752019-03-22 11:28:54 -07002398{
2399 struct sound_trigger_event_info event_info;
2400 /* Pass the pcm information to audio hal for capturing LAB */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002401 if ((stc_ses->rc_config &&
2402 stc_ses->rc_config->capture_requested) &&
2403 stc_ses->stdev->audio_hal_cb) {
2404 ALOGD("%s:[c%d] ST_EVENT_SESSION_REGISTER capture_handle %d",
2405 __func__, stc_ses->sm_handle, stc_ses->capture_handle);
2406 event_info.st_ses.p_ses = (void *)stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07002407 event_info.st_ses.config = hw_ses->config;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002408 event_info.st_ses.capture_handle = stc_ses->capture_handle;
Quinn Male2e883752019-03-22 11:28:54 -07002409 /*
2410 * set pcm to NULL as this version of st_hal doesn't pass pcm to
2411 * audio HAL
2412 */
2413 event_info.st_ses.pcm = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002414 stc_ses->stdev->audio_hal_cb(ST_EVENT_SESSION_REGISTER, &event_info);
Quinn Male2e883752019-03-22 11:28:54 -07002415 }
2416}
2417
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002418static void dereg_hal_event_session(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07002419{
2420 struct sound_trigger_event_info event_info;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002421 /* Indicate to audio hal that to stop reading LAB data */
2422 if ((stc_ses->rc_config &&
2423 stc_ses->rc_config->capture_requested) &&
2424 stc_ses->stdev->audio_hal_cb) {
2425 ALOGD("%s:[c%d] ST_EVENT_SESSION_DEREGISTER capture_handle %d",
2426 __func__, stc_ses->sm_handle, stc_ses->capture_handle);
2427 event_info.st_ses.p_ses = (void *)stc_ses;
2428 event_info.st_ses.capture_handle = stc_ses->capture_handle;
Quinn Male2e883752019-03-22 11:28:54 -07002429 event_info.st_ses.pcm = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002430 stc_ses->stdev->audio_hal_cb(ST_EVENT_SESSION_DEREGISTER, &event_info);
Quinn Male2e883752019-03-22 11:28:54 -07002431 }
2432}
2433
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002434static int start_hw_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
2435 bool load_sm)
Quinn Male2e883752019-03-22 11:28:54 -07002436{
2437 int status = 0, err = 0;
2438
2439 /*
Quinn Male3d7d9d42019-05-20 13:35:01 -07002440 * It is possible the BE LPI mode has been updated, but not the FE mode.
2441 * DSP requires both FE and BE to be in the same mode for any configuration
2442 * changes between LPI and non-LPI switch, so update the FE mode to the
2443 * same as BE mode by re-opening LSM session.
Quinn Male2e883752019-03-22 11:28:54 -07002444 */
Quinn Male3d7d9d42019-05-20 13:35:01 -07002445 if (hw_ses->lpi_enable != hw_ses->stdev->lpi_enable) {
2446 hw_ses->lpi_enable = hw_ses->stdev->lpi_enable;
Quinn Male2e883752019-03-22 11:28:54 -07002447 if (!load_sm) {
2448 load_sm = true;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002449 status = hw_ses->fptrs->dereg_sm(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002450 if (status)
2451 ALOGW("%s:[%d] failed to dereg_sm err %d", __func__,
2452 st_ses->sm_handle, status);
2453 }
2454 }
2455
2456 if (load_sm) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002457 status = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_info.sm_data,
2458 st_ses->sm_info.sm_size, st_ses->sm_info.sm_type);
Quinn Male2e883752019-03-22 11:28:54 -07002459 if (status) {
2460 ALOGE("%s:[%d] failed to reg_sm err %d", __func__,
2461 st_ses->sm_handle, status);
2462 goto cleanup;
2463 }
2464 err |= HW_SES_ERR_MASK_REG_SM;
2465 }
2466
2467 status = hw_ses->fptrs->set_device(hw_ses, true);
2468 if (status) {
2469 ALOGE("%s:[%d] failed to set_device err %d", __func__,
2470 st_ses->sm_handle, status);
2471 goto cleanup;
2472 }
2473 err |= HW_SES_ERR_MASK_DEVICE_SET;
2474
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002475 status = hw_ses->fptrs->reg_sm_params(hw_ses, st_ses->recognition_mode,
2476 st_ses->lab_enabled, st_ses->rc_config, st_ses->sm_info.sm_type,
2477 st_ses->sm_info.sm_data);
Quinn Male2e883752019-03-22 11:28:54 -07002478 if (status) {
2479 ALOGE("%s:[%d] failed to reg_sm_params err %d", __func__,
2480 st_ses->sm_handle, status);
2481 goto cleanup;
2482 }
2483 err |= HW_SES_ERR_MASK_REG_SM_PARAM;
2484
2485 status = hw_ses->fptrs->start(hw_ses);
2486 if (status) {
2487 ALOGE("%s:[%d] failed to start err %d", __func__,
2488 st_ses->sm_handle, status);
2489 goto cleanup;
2490 }
2491 err |= HW_SES_ERR_MASK_STARTED;
2492
2493 st_ses->hw_session_started = true;
2494 return status;
2495
2496cleanup:
2497 do_hw_sess_cleanup(st_ses, hw_ses, err);
2498 return status;
2499}
2500
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002501static int stop_hw_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
2502 bool unload_sm)
Quinn Male2e883752019-03-22 11:28:54 -07002503{
2504 int status = 0;
2505 int rc = 0;
2506
2507 status = hw_ses->fptrs->stop(hw_ses);
2508 if (status) {
2509 ALOGE("%s:[%d] failed to stop err %d", __func__,
2510 st_ses->sm_handle, status);
2511 rc = status;
2512 }
2513
2514 status = hw_ses->fptrs->dereg_sm_params(hw_ses);
2515 if (status) {
2516 ALOGE("%s:[%d] failed to dereg_sm_params err %d", __func__,
2517 st_ses->sm_handle, status);
2518 rc = status;
2519 }
2520
2521 status = hw_ses->fptrs->set_device(hw_ses, false);
2522 if (status) {
2523 ALOGE("%s:[%d] failed to set_device err %d", __func__,
2524 st_ses->sm_handle, status);
2525 rc = status;
2526 }
2527 if (unload_sm) {
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 ALOGE("%s:[%d] failed to dereg_sm, err %d", __func__,
2531 st_ses->sm_handle, status);
2532 rc = status;
2533 }
2534 }
2535
2536 /* This must be set to false irrespective as the above calls may
2537 * return error (esp for SSR)
2538 */
2539 st_ses->hw_session_started = false;
2540 return rc;
2541}
2542
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002543static int start_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
2544 bool load_sm)
Quinn Male2e883752019-03-22 11:28:54 -07002545{
2546 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002547
Quinn Male2e883752019-03-22 11:28:54 -07002548 if (st_ses->hw_session_started) {
2549 ALOGE("%s:[%d] already started", __func__, st_ses->sm_handle);
2550 return -1;
2551 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002552
Quinn Male2e883752019-03-22 11:28:54 -07002553 status = start_hw_session(st_ses, hw_ses, load_sm);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002554 hw_ses->sthw_cfg_updated = false;
2555
Quinn Male2e883752019-03-22 11:28:54 -07002556 return status;
2557}
2558
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002559static int restart_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses)
Quinn Male2e883752019-03-22 11:28:54 -07002560{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002561 int status = 0;
2562
2563 status = hw_ses->fptrs->restart(hw_ses, st_ses->recognition_mode,
2564 st_ses->rc_config, st_ses->sm_info.sm_type,
2565 st_ses->sm_info.sm_data);
Quinn Male2e883752019-03-22 11:28:54 -07002566 if (status == 0) {
2567 st_ses->hw_session_started = true;
2568 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002569 ALOGE("%s:[%d] failed to restart", __func__, st_ses->sm_handle);
2570 st_ses->hw_session_started = false;
Quinn Male2e883752019-03-22 11:28:54 -07002571 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002572
Quinn Male2e883752019-03-22 11:28:54 -07002573 return status;
2574}
2575
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002576static int stop_session(st_proxy_session_t *st_ses,
2577 st_hw_session_t *hw_ses, bool unload_sm)
Quinn Male2e883752019-03-22 11:28:54 -07002578{
2579 if (!st_ses->hw_session_started) {
2580 ALOGV("%s:[%d] already stopped", __func__, st_ses->sm_handle);
2581 return 0;
2582 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002583 st_ses->detection_requested = false;
Quinn Male2e883752019-03-22 11:28:54 -07002584 return stop_hw_session(st_ses, hw_ses, unload_sm);
2585}
2586
2587/*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002588 * This function gets the first stage detection keyword indices, which are
2589 * needed by the second stage sessions. If the legacy DSP is used, which does
2590 * not provide keyword indices, set the indices to include the entire keyword
2591 * duration. This function also gets the user confidence level if there is an
2592 * active voiceprint session.
Quinn Male2e883752019-03-22 11:28:54 -07002593 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002594static int get_first_stage_detection_params(st_proxy_session_t *st_ses,
2595 void *payload, size_t payload_size)
Quinn Male2e883752019-03-22 11:28:54 -07002596{
2597 size_t count_size = 0;
2598 uint8_t *payload_ptr = (uint8_t *)payload;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002599 uint8_t *cf_levels = NULL;
2600 uint32_t key_id = 0, key_payload_size = 0, cf_levels_size = 0;
Quinn Male2e883752019-03-22 11:28:54 -07002601 uint32_t kw_start_ms = 0, kw_end_ms = 0;
2602 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002603 struct listnode *node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07002604 st_arm_second_stage_t *st_sec_stage = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002605 st_session_t *stc_ses = st_ses->det_stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07002606 bool is_active_vop_session = false;
2607
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002608 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07002609 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002610 if (st_sec_stage->ss_info->sm_detection_type ==
2611 ST_SM_TYPE_USER_VERIFICATION) {
Quinn Male2e883752019-03-22 11:28:54 -07002612 is_active_vop_session = true;
2613 break;
2614 }
2615 }
2616
2617 if (hw_ses->is_generic_event) {
2618 /*
2619 * This case is for the generic detection event from the DSP. Set the
2620 * keyword start and end indices and user confidence level based on key
2621 * id, if applicable.
2622 */
2623 while (count_size < payload_size) {
2624 key_id = *(uint32_t *)payload_ptr;
2625 key_payload_size = *((uint32_t *)payload_ptr + 1);
2626
2627 switch (key_id) {
2628 case KEY_ID_CONFIDENCE_LEVELS:
2629 if (is_active_vop_session) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002630 /*
2631 * It is expected that VoP is supported with single KW/user
2632 * SVA3.0 model, hence get it directly with hard offset.
2633 */
2634 if (!st_ses->sm_info.sm_merged) {
2635 hw_ses->user_level = (int32_t)(*(payload_ptr +
2636 GENERIC_DET_EVENT_USER_LEVEL_OFFSET));
2637 } else {
2638 /* Extract from first stage merged conf levels */
2639 check_and_extract_det_conf_levels_payload(st_ses,
2640 payload_ptr + (4 * sizeof(uint32_t)),
2641 *((uint32_t *)payload_ptr + 3),
2642 &cf_levels, &cf_levels_size);
2643 if (!cf_levels || !cf_levels_size)
2644 break;
2645 hw_ses->user_level = cf_levels[1];
2646 ALOGV("%s:hw_ses->user_level %d at cf_levels[1]",
2647 __func__, hw_ses->user_level);
2648 }
Quinn Male2e883752019-03-22 11:28:54 -07002649 }
2650 break;
2651
2652 case KEY_ID_KEYWORD_POSITION_STATS:
2653 hw_ses->kw_start_idx = *((uint32_t *)payload_ptr +
2654 GENERIC_DET_EVENT_KW_START_OFFSET);
2655 hw_ses->kw_end_idx = *((uint32_t *)payload_ptr +
2656 GENERIC_DET_EVENT_KW_END_OFFSET);
2657 break;
2658
2659 default:
2660 ALOGW("%s: Unsupported generic detection event key id",
2661 __func__);
2662 break;
2663 }
2664 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
2665 payload_ptr += count_size;
2666 }
2667 } else {
2668 /*
2669 * This case is for the DSP detection events which are not the generic
2670 * detection event. There will be no keyword indices from first stage
2671 * detection, so the start index will be 0 and the end index will be the
2672 * buffer duration sent from the app. If this is not sent, the keyword
2673 * duration from platform xml will be used.
2674 */
2675 hw_ses->kw_start_idx = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002676 if (hw_ses->sthw_cfg.client_req_hist_buf) {
Quinn Male2e883752019-03-22 11:28:54 -07002677 hw_ses->kw_end_idx =
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002678 convert_ms_to_bytes(hw_ses->sthw_cfg.client_req_hist_buf,
Quinn Male2e883752019-03-22 11:28:54 -07002679 &hw_ses->config);
2680 } else {
2681 hw_ses->kw_end_idx =
2682 convert_ms_to_bytes(st_ses->vendor_uuid_info->kw_duration,
2683 &hw_ses->config);
2684 }
2685
2686 if (is_active_vop_session) {
2687 if ((st_ses->exec_mode == ST_EXEC_MODE_CPE) &&
2688 st_ses->stdev->is_gcs) {
2689 hw_ses->user_level = (int32_t)(*(payload_ptr +
2690 GCS_NON_GENERIC_USER_LEVEL_OFFSET));
2691 } else if ((st_ses->exec_mode == ST_EXEC_MODE_ADSP) ||
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002692 !st_ses->stdev->is_gcs) {
Quinn Male2e883752019-03-22 11:28:54 -07002693 hw_ses->user_level = (int32_t)(*(payload_ptr +
2694 LSM_NON_GENERIC_USER_LEVEL_OFFSET));
2695 }
2696 }
2697 }
2698
2699 kw_start_ms = convert_bytes_to_ms(hw_ses->kw_start_idx, &hw_ses->config);
2700 kw_end_ms = convert_bytes_to_ms(hw_ses->kw_end_idx, &hw_ses->config);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002701 ALOGD("%s:[%d] 1st stage kw_start = %dms, kw_end = %dms,"
2702 "is_generic_event %d", __func__, st_ses->sm_handle,
2703 kw_start_ms, kw_end_ms, hw_ses->is_generic_event);
Quinn Male2e883752019-03-22 11:28:54 -07002704
2705 return 0;
2706}
2707
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002708static inline int prepapre_second_stage_for_client(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07002709{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002710 struct listnode *node = NULL;
2711 st_arm_second_stage_t *st_sec_stage = NULL;
2712 int status = 0;
2713
2714 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
2715
2716 list_for_each(node, &stc_ses->second_stage_list) {
2717 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
2718 status = st_second_stage_prepare_session(st_sec_stage);
2719 }
2720 return status;
2721}
2722
2723static inline int start_second_stage_for_client(st_session_t *stc_ses)
2724{
2725 struct listnode *node = NULL;
2726 st_arm_second_stage_t *st_sec_stage = NULL;
2727 int status = 0;
2728
2729 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
2730
2731 list_for_each(node, &stc_ses->second_stage_list) {
2732 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
2733 status = st_second_stage_start_session(st_sec_stage);
2734 }
2735 return status;
2736}
2737
2738static inline void stop_second_stage_for_client(st_session_t *stc_ses)
2739{
2740 struct listnode *node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07002741 st_arm_second_stage_t *st_sec_stage = NULL;
2742
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002743 ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
2744
2745 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07002746 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
2747 st_second_stage_stop_session(st_sec_stage);
2748 }
2749}
2750
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002751static int generate_legacy_st_phrase_recognition_event
2752(
2753 const struct sound_trigger_phrase_sound_model *phrase_sm,
2754 const struct sound_trigger_recognition_config *rc_config,
2755 const void *payload,
2756 unsigned int payload_size,
2757 struct sound_trigger_phrase_recognition_event **out_rc_event
2758)
2759{
2760 struct sound_trigger_phrase_recognition_event *event;
2761 unsigned int i = 0, j = 0, user_id = 0;
2762
2763 ALOGD("%s: Enter payload_size %d", __func__, payload_size);
2764
2765 if(!payload || !phrase_sm || !rc_config || !out_rc_event) {
2766 ALOGE("%s: Null params", __func__);
2767 return -EINVAL;
2768 }
2769
2770 *out_rc_event = NULL;
2771 event = calloc(1, sizeof(*event) + payload_size);
2772 if (!event) {
2773 ALOGE("%s: event allocation failed size %d", __func__, payload_size);
2774 return -ENODEV;
2775 }
2776
2777 event->num_phrases = rc_config->num_phrases;
2778 event->common.data_offset = sizeof(*event);
2779 event->common.data_size = payload_size;
2780 memcpy((char *)event + event->common.data_offset, payload, payload_size);
2781
2782 /* fill confidence levels */
2783 for (i = 0; i < rc_config->num_phrases; i++) {
2784 event->phrase_extras[i].id = rc_config->phrases[i].id;
2785 event->phrase_extras[i].recognition_modes =
2786 phrase_sm->phrases[0].recognition_mode;
2787 event->phrase_extras[i].confidence_level = ((char *)payload)[i];
2788 event->phrase_extras[i].num_levels = rc_config->phrases[i].num_levels;
2789 for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
2790 user_id = rc_config->phrases[i].levels[j].user_id;
2791 event->phrase_extras[i].levels[j].user_id = user_id;
2792 event->phrase_extras[i].levels[j].level =
2793 ((char *)payload)[user_id];
2794 }
2795 }
2796
2797 *out_rc_event = event;
2798 return 0;
2799}
2800
2801/*
2802 * This function sets the opaque data size for the DSP's generic detection
2803 * events. This opaque data can now have varying size based on the requested
2804 * params.
2805 */
2806static size_t set_opaque_data_size(char *payload, size_t payload_size,
2807 uint32_t version)
2808{
2809 size_t count_size = 0, opaque_size = 0;
2810 uint32_t key_id = 0, key_payload_size = 0;
2811
2812 while (count_size < payload_size) {
2813 key_id = *(uint32_t *)payload;
2814 key_payload_size = *((uint32_t *)payload + 1);
2815
2816 switch (key_id) {
2817 case KEY_ID_CONFIDENCE_LEVELS:
2818 opaque_size += sizeof(struct st_param_header);
2819 if (version != CONF_LEVELS_INTF_VERSION_0002) {
2820 opaque_size +=
2821 sizeof(struct st_confidence_levels_info);
2822 } else {
2823 opaque_size +=
2824 sizeof(struct st_confidence_levels_info_v2);
2825 }
2826 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
2827 payload += count_size;
2828 break;
2829
2830 case KEY_ID_KEYWORD_POSITION_STATS:
2831 opaque_size += sizeof(struct st_param_header) +
2832 sizeof(struct st_keyword_indices_info);
2833 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
2834 payload += count_size;
2835 break;
2836
2837 default:
2838 ALOGE("%s: Unsupported generic detection event key id", __func__);
2839 }
2840 }
2841
2842 opaque_size += sizeof(struct st_param_header) +
2843 sizeof(struct st_timestamp_info);
2844
2845 return opaque_size;
2846}
2847
2848/*
2849 * This function packs the updated opaque data confidence levels which are
2850 * passed to the client via callback.
2851 */
2852static int pack_opaque_data_conf_levels(
2853 st_proxy_session_t *st_ses, void *opaque_data,
2854 uint8_t *payload,
2855 unsigned int payload_size)
2856{
2857 uint8_t *payload_ptr = payload;
2858 unsigned int i = 0, j = 0, k = 0, user_id = 0;
2859 st_arm_second_stage_t *st_sec_stage = NULL;
2860 struct listnode *node = NULL;
2861 struct st_confidence_levels_info *conf_levels = NULL;
2862 struct st_confidence_levels_info_v2 *conf_levels_v2 = NULL;
2863 st_session_t *stc_ses = st_ses->det_stc_ses;
2864 int32_t kw_level = 0, user_level = 0;
2865
2866 list_for_each(node, &stc_ses->second_stage_list) {
2867 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
2868 if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
2869 kw_level = st_sec_stage->ss_session->confidence_score;
2870 } else if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_VOP) {
2871 user_level = st_sec_stage->ss_session->confidence_score;
2872 }
2873 }
2874
2875 if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002) {
2876 conf_levels = (struct st_confidence_levels_info *)opaque_data;
2877 for (i = 0; i < conf_levels->num_sound_models; i++) {
2878 if (conf_levels->conf_levels[i].sm_id == ST_SM_ID_SVA_GMM) {
2879 for (j = 0;
2880 j < conf_levels->conf_levels[i].num_kw_levels; j++) {
2881 if (j <= payload_size)
2882 conf_levels->conf_levels[i].kw_levels[j].kw_level =
2883 payload_ptr[j];
2884 else
2885 ALOGE("%s: unexpected conf size %d < %d", __func__,
2886 payload_size, j);
2887 for (k = 0;
2888 k < conf_levels->conf_levels[i].kw_levels[j].num_user_levels;
2889 k++) {
2890 user_id =
2891 conf_levels->conf_levels[i].kw_levels[j].
2892 user_levels[k].user_id;
2893 if (user_id <= payload_size)
2894 conf_levels->conf_levels[i].kw_levels[j].
2895 user_levels[k].level = payload_ptr[user_id];
2896 else
2897 ALOGE("%s: Unexpected conf size %d < %d", __func__,
2898 payload_size, user_id);
2899 }
2900 }
2901 } else if (conf_levels->conf_levels[i].sm_id == ST_SM_ID_SVA_CNN) {
2902 conf_levels->conf_levels[i].kw_levels[0].kw_level = kw_level;
2903 } else if (conf_levels->conf_levels[i].sm_id == ST_SM_ID_SVA_VOP) {
2904 /*
2905 * Fill both the keyword and user confidence level with the
2906 * confidence score returned from the voiceprint algorithm.
2907 */
2908 conf_levels->conf_levels[i].kw_levels[0].kw_level =
2909 (uint8_t)user_level;
2910 conf_levels->conf_levels[i].kw_levels[0].user_levels[0].level =
2911 (uint8_t)user_level;
2912 }
2913 }
2914 } else {
2915 conf_levels_v2 = (struct st_confidence_levels_info_v2 *)opaque_data;
2916 for (i = 0; i < conf_levels_v2->num_sound_models; i++) {
2917 if (conf_levels_v2->conf_levels[i].sm_id == ST_SM_ID_SVA_GMM) {
2918 for (j = 0;
2919 j < conf_levels_v2->conf_levels[i].num_kw_levels; j++) {
2920 if (j <= payload_size)
2921 conf_levels_v2->conf_levels[i].kw_levels[j].kw_level =
2922 payload_ptr[j];
2923 else
2924 ALOGE("%s: unexpected conf size %d < %d", __func__,
2925 payload_size, j);
2926
2927 for (k = 0;
2928 k < conf_levels_v2->conf_levels[i].kw_levels[j].num_user_levels;
2929 k++) {
2930 user_id =
2931 conf_levels_v2->conf_levels[i].kw_levels[j].
2932 user_levels[k].user_id;
2933 if (user_id <= payload_size)
2934 conf_levels_v2->conf_levels[i].kw_levels[j].
2935 user_levels[k].level = payload_ptr[user_id];
2936 else
2937 ALOGE("%s: Unexpected conf size %d < %d", __func__,
2938 payload_size, user_id);
2939 }
2940 }
2941 } else if (conf_levels_v2->conf_levels[i].sm_id ==
2942 ST_SM_ID_SVA_CNN) {
2943 conf_levels_v2->conf_levels[i].kw_levels[0].kw_level = kw_level;
2944 } else if (conf_levels_v2->conf_levels[i].sm_id ==
2945 ST_SM_ID_SVA_VOP) {
2946 /*
2947 * Fill both the keyword and user confidence level with the
2948 * confidence score returned from the voiceprint algorithm.
2949 */
2950 conf_levels_v2->conf_levels[i].kw_levels[0].kw_level =
2951 user_level;
2952 conf_levels_v2->conf_levels[i].kw_levels[0].user_levels[0].level =
2953 user_level;
2954 }
2955 }
2956 }
2957
2958 return 0;
2959}
2960
2961/* This function packs the sound trigger API confidence levels */
2962static int pack_recognition_event_conf_levels(
2963 st_proxy_session_t *st_ses, uint8_t *payload,
2964 unsigned int payload_size,
2965 struct sound_trigger_phrase_recognition_event *local_event)
2966{
2967 unsigned int j = 0, k = 0, user_id = 0;
2968 st_arm_second_stage_t *st_sec_stage = NULL;
2969 struct listnode *node = NULL;
2970 st_session_t *stc_ses = st_ses->det_stc_ses;
2971 struct sound_trigger_phrase_sound_model *phrase_sm =
2972 (struct sound_trigger_phrase_sound_model *)stc_ses->phrase_sm;
2973
2974 /*
2975 * Fill in the GMM confidence levels to the sound trigger recognition event
2976 * APIs first. If any second stage session is enabled, overwrite the APIs
2977 * with the second stage confidence levels.
2978 */
2979 for (j = 0; j < stc_ses->rc_config->num_phrases; j++) {
2980 local_event->phrase_extras[j].id = stc_ses->rc_config->phrases[j].id;
2981 local_event->phrase_extras[j].recognition_modes =
2982 phrase_sm->phrases[j].recognition_mode;
2983 local_event->phrase_extras[j].num_levels =
2984 stc_ses->rc_config->phrases[j].num_levels;
2985 if (j <= payload_size)
2986 local_event->phrase_extras[j].confidence_level = payload[j];
2987 else
2988 ALOGE("%s: unexpected conf size %d < %d", __func__,
2989 payload_size, j);
2990
2991 for (k = 0; k < stc_ses->rc_config->phrases[j].num_levels; k++) {
2992 user_id = stc_ses->rc_config->phrases[j].levels[k].user_id;
2993 if (user_id <= payload_size) {
2994 local_event->phrase_extras[j].levels[k].user_id = user_id;
2995 local_event->phrase_extras[j].levels[k].level =
2996 payload[user_id];
2997 } else {
2998 ALOGE("%s: Unexpected conf size %d < %d", __func__,
2999 payload_size, user_id);
3000 }
3001 }
3002 }
3003
3004 list_for_each(node, &stc_ses->second_stage_list) {
3005 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
3006 if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
3007 local_event->phrase_extras[0].confidence_level =
3008 (uint8_t)st_sec_stage->ss_session->confidence_score;
3009 } else if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_VOP) {
3010 local_event->phrase_extras[0].levels[0].level =
3011 (uint8_t)st_sec_stage->ss_session->confidence_score;
3012 }
3013 }
3014 return 0;
3015}
3016
3017static int parse_generic_event_and_pack_opaque_data(
3018 st_proxy_session_t *st_ses, uint8_t *opaque_data,
3019 uint8_t *payload, size_t payload_size,
3020 struct sound_trigger_phrase_recognition_event *local_event)
3021{
3022 uint32_t key_id = 0, key_payload_size = 0;
3023 struct st_param_header *param_hdr = NULL;
3024 struct st_keyword_indices_info *kw_indices = NULL;
3025 struct st_timestamp_info *timestamps = NULL;
3026 size_t count_size = 0;
3027 st_arm_second_stage_t *st_sec_stage = NULL;
3028 struct listnode *node = NULL;
3029 st_session_t *stc_ses = st_ses->det_stc_ses;
3030 int status = 0;
3031 unsigned char *cf_levels = NULL;
3032 unsigned int cf_levels_size = 0;
3033
3034 while (count_size < payload_size) {
3035 key_id = *(uint32_t *)payload;
3036 key_payload_size = *((uint32_t *)payload + 1);
3037
3038 switch (key_id) {
3039 case KEY_ID_CONFIDENCE_LEVELS:
3040 /* Pack the opaque data confidence levels structure */
3041 param_hdr = (struct st_param_header *)(opaque_data);
3042 param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
3043 opaque_data += sizeof(struct st_param_header);
3044 if (stc_ses->conf_levels_intf_version !=
3045 CONF_LEVELS_INTF_VERSION_0002) {
3046 param_hdr->payload_size =
3047 sizeof(struct st_confidence_levels_info);
3048 } else {
3049 param_hdr->payload_size =
3050 sizeof(struct st_confidence_levels_info_v2);
3051 }
3052 check_and_extract_det_conf_levels_payload(st_ses,
3053 payload + (4 * sizeof(uint32_t)), *((uint32_t *)payload + 3),
3054 &cf_levels, &cf_levels_size);
3055 if (!cf_levels || !cf_levels_size) {
3056 status = -EINVAL;
3057 goto exit;
3058 }
3059 memcpy(opaque_data, stc_ses->st_conf_levels,
3060 param_hdr->payload_size);
3061 pack_opaque_data_conf_levels(st_ses, opaque_data,
3062 cf_levels, cf_levels_size);
3063 pack_recognition_event_conf_levels(st_ses, cf_levels,
3064 cf_levels_size, local_event);
3065 opaque_data += param_hdr->payload_size;
3066 break;
3067
3068 case KEY_ID_KEYWORD_POSITION_STATS:
3069 /* Pack the opaque data keyword indices structure */
3070 param_hdr = (struct st_param_header *)(opaque_data);
3071 param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
3072 param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
3073 opaque_data += sizeof(struct st_param_header);
3074 kw_indices = (struct st_keyword_indices_info *)(opaque_data);
3075 kw_indices->version = 0x1;
3076 kw_indices->start_index = *((uint32_t *)payload + 3);
3077 kw_indices->end_index = *((uint32_t *)payload + 4);
3078
3079 list_for_each(node, &stc_ses->second_stage_list) {
3080 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
3081 list_node);
3082 if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
3083 kw_indices->start_index =
3084 st_sec_stage->ss_session->kw_start_idx;
3085 kw_indices->end_index =
3086 st_sec_stage->ss_session->kw_end_idx;
3087 }
3088 }
3089 opaque_data += sizeof(struct st_keyword_indices_info);
3090 break;
3091
3092 default:
3093 ALOGE("%s: Unsupported generic detection event key id", __func__);
3094 status = -EINVAL;
3095 goto exit;
3096 }
3097 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
3098 payload += count_size;
3099 }
3100
3101 /* Pack the opaque data detection timestamp structure */
3102 param_hdr = (struct st_param_header *)(opaque_data);
3103 param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
3104 param_hdr->payload_size = sizeof(struct st_timestamp_info);
3105 opaque_data += sizeof(struct st_param_header);
3106 timestamps = (struct st_timestamp_info *)(opaque_data);
3107 timestamps->version = 0x1;
3108 timestamps->first_stage_det_event_time =
3109 st_ses->hw_ses_current->first_stage_det_event_time;
3110 if (!list_empty(&stc_ses->second_stage_list))
3111 timestamps->second_stage_det_event_time =
3112 st_ses->hw_ses_current->second_stage_det_event_time;
3113 opaque_data += sizeof(struct st_timestamp_info);
3114
3115exit:
3116 return status;
3117}
3118
3119static int parse_generic_event_without_opaque_data(
3120 st_proxy_session_t *st_ses, uint8_t *payload, size_t payload_size,
3121 struct sound_trigger_phrase_recognition_event *local_event)
3122{
3123 uint32_t key_id = 0, key_payload_size = 0;
3124 size_t count_size = 0;
3125 int status = 0;
3126 unsigned char *cf_levels = NULL;
3127 unsigned int cf_levels_size = 0;;
3128
3129 while (count_size < payload_size) {
3130 key_id = *(uint32_t *)payload;
3131 key_payload_size = *((uint32_t *)payload + 1);
3132
3133 switch (key_id) {
3134 case KEY_ID_CONFIDENCE_LEVELS:
3135 check_and_extract_det_conf_levels_payload(st_ses,
3136 payload + (4 * sizeof(uint32_t)), *((uint32_t *)payload + 3),
3137 &cf_levels, &cf_levels_size);
3138 if (!cf_levels || !cf_levels_size) {
3139 status = -EINVAL;
3140 return status;
3141 }
3142 pack_recognition_event_conf_levels(st_ses, cf_levels,
3143 cf_levels_size, local_event);
3144 return status;
3145
3146 case KEY_ID_KEYWORD_POSITION_STATS:
3147 count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
3148 payload += count_size;
3149 break;
3150
3151 default:
3152 ALOGE("%s: Unsupported generic detection event key id", __func__);
3153 status = -EINVAL;
3154 return status;
3155 }
3156 }
3157 return status;
3158}
3159
3160/*
3161 * This function handles detection payloads in the format of the DSP's
3162 * generic detection event.
3163 */
3164int process_detection_event_keyphrase_v2(
3165 st_proxy_session_t *st_ses, int detect_status,
3166 void *payload, size_t payload_size,
3167 struct sound_trigger_phrase_recognition_event **event)
3168{
3169 st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
3170 st_session_t *stc_ses = st_ses->det_stc_ses;
3171 unsigned int i = 0, j = 0;
3172 int status = 0;
3173 uint8_t *opaque_data = NULL;
3174 size_t opaque_size = 0;
3175 struct sound_trigger_phrase_recognition_event *local_event = NULL;
3176
3177 if (st_ses->vendor_uuid_info->is_qcva_uuid)
3178 opaque_size = set_opaque_data_size(payload, payload_size,
3179 stc_ses->conf_levels_intf_version);
3180 else
3181 opaque_size = payload_size;
3182
3183 local_event = calloc(1,
3184 sizeof(struct sound_trigger_phrase_recognition_event) + opaque_size);
3185 if (!local_event) {
3186 ALOGE("%s: local_event allocation failed, opaque data size = %d",
3187 __func__, (unsigned int)opaque_size);
3188 return -ENOMEM;
3189 }
3190
3191 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3192 local_event->common.data_offset =
3193 sizeof(struct sound_trigger_phrase_recognition_event);
3194 local_event->common.data_size = opaque_size;
3195 opaque_data = (uint8_t *)local_event + local_event->common.data_offset;
3196
3197 if (st_ses->vendor_uuid_info->is_qcva_uuid) {
3198 if (stc_ses->rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) {
3199 status = parse_generic_event_and_pack_opaque_data(st_ses,
3200 opaque_data, payload, payload_size, local_event);
3201 if (status) {
3202 ALOGE("%s: Failed to parse generic detection event with opaque"
3203 "data %d", __func__, status);
3204 goto exit;
3205 }
3206
3207 ST_DBG_DECLARE(FILE *opaque_fd = NULL; static int opaque_cnt = 0);
3208 ST_DBG_FILE_OPEN_WR(opaque_fd, ST_DEBUG_DUMP_LOCATION,
3209 "detection_opaque_data", "bin", opaque_cnt++);
3210 ST_DBG_FILE_WRITE(opaque_fd, opaque_data, opaque_size);
3211 ST_DBG_FILE_CLOSE(opaque_fd);
3212 } else {
3213 status = parse_generic_event_without_opaque_data(st_ses, payload,
3214 payload_size, local_event);
3215 if (status) {
3216 ALOGE("%s: Failed to parse generic detection event without"
3217 "opaque data %d", __func__, status);
3218 goto exit;
3219 }
3220 }
3221 } else {
3222 local_event = calloc(1, sizeof(*local_event) + payload_size);
3223 if (!local_event) {
3224 ALOGE("%s: event allocation failed, size %zd", __func__,
3225 payload_size);
3226 status = -ENOMEM;
3227 goto exit;
3228 }
3229 memcpy(local_event->phrase_extras,
3230 stc_ses->rc_config->phrases, stc_ses->rc_config->num_phrases *
3231 sizeof(struct sound_trigger_phrase_recognition_extra));
3232 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3233 local_event->common.data_offset = sizeof(*local_event);
3234 local_event->common.data_size = opaque_size;
3235 memcpy(opaque_data, payload, opaque_size);
3236 opaque_data += opaque_size;
3237 }
3238
3239 /*
3240 * fill the remaining recognition event parameters not specific
3241 * to soundmodel lib
3242 */
3243 local_event->common.status = detect_status;
3244 local_event->common.type = stc_ses->phrase_sm->common.type;
3245 local_event->common.model = stc_ses->sm_handle;
3246 local_event->common.capture_available =
3247 stc_ses->rc_config->capture_requested;
3248 local_event->common.capture_delay_ms = 0;
3249 local_event->common.capture_preamble_ms = 0;
3250 local_event->common.audio_config.sample_rate =
3251 SOUND_TRIGGER_SAMPLING_RATE_16000;
3252 local_event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
3253 local_event->common.audio_config.channel_mask =
3254 audio_channel_in_mask_from_count(st_hw_ses->config.channels);
3255
3256 for (i = 0; i < local_event->num_phrases; ++i) {
3257 ALOGV("%s: [%d] kw_id %d level %d", __func__, i,
3258 local_event->phrase_extras[i].id,
3259 local_event->phrase_extras[i].confidence_level);
3260 for (j = 0; j < local_event->phrase_extras[i].num_levels; ++j) {
3261 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
3262 local_event->phrase_extras[i].levels[j].user_id,
3263 local_event->phrase_extras[i].levels[j].level);
3264 }
3265 }
3266
3267 ALOGI("%s:[c%d]", __func__, stc_ses->sm_handle);
3268
3269 ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
3270 "num_phrases=%d id=%d", __func__, stc_ses->sm_handle,
3271 local_event->common.status, local_event->common.type,
3272 local_event->common.model, local_event->common.capture_available,
3273 local_event->num_phrases, local_event->phrase_extras[0].id);
3274
3275 *event = local_event;
3276 return 0;
3277
3278exit:
3279 if (local_event)
3280 free(local_event);
3281 return status;
3282}
3283
3284/*
3285 * This function handles detection payloads in the format of the DSP's
3286 * legacy (non-generic) detection event.
3287 * TODO: Deprecate this when DSP for all shared targets of this component
3288 * move to generic event.
3289 */
3290static int process_detection_event_keyphrase(
3291 st_proxy_session_t *st_ses, int detect_status,
3292 void *payload, size_t payload_size,
3293 struct sound_trigger_phrase_recognition_event **event)
3294{
3295 st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
3296 st_session_t *stc_ses = st_ses->det_stc_ses;
3297 unsigned int i = 0, j = 0;
3298 int status = 0;
3299 struct sound_trigger_phrase_recognition_event *local_event = NULL;
3300 size_t opaque_size = 0;
3301 uint8_t *opaque_data = NULL, *payload_ptr = NULL;
3302 struct st_param_header *param_hdr = NULL;
3303 st_arm_second_stage_t *st_sec_stage = NULL;
3304 struct listnode *node = NULL;
3305 struct st_keyword_indices_info *kw_indices = NULL;
3306 struct st_timestamp_info *timestamps = NULL;
3307 bool enable_kw_indices = false;
3308 unsigned char *cf_levels = NULL;
3309 unsigned int cf_levels_size = 0;
3310
3311 if ((stc_ses->rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
3312 st_ses->vendor_uuid_info->is_qcva_uuid) {
3313 /*
3314 * This logic is for the updated opaque data format. Sound trigger
3315 * recognition event APIs are filled along with the opaque data's
3316 * confidence levels, keyword indices, and timestamp parameters.
3317 */
3318 opaque_size = (2 * sizeof(struct st_param_header)) +
3319 sizeof(struct st_timestamp_info);
3320 if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002)
3321 opaque_size += sizeof(struct st_confidence_levels_info);
3322 else
3323 opaque_size += sizeof(struct st_confidence_levels_info_v2);
3324
3325 list_for_each(node, &stc_ses->second_stage_list) {
3326 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
3327 if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
3328 enable_kw_indices = true;
3329 opaque_size += sizeof(struct st_param_header) +
3330 sizeof(struct st_keyword_indices_info);
3331 break;
3332 }
3333 }
3334
3335 local_event = calloc(1,
3336 sizeof(struct sound_trigger_phrase_recognition_event) +
3337 opaque_size);
3338 if (!local_event) {
3339 ALOGE("%s: local_event allocation failed, opaque data size = %d",
3340 __func__, (unsigned int)opaque_size);
3341 return -ENOMEM;
3342 }
3343
3344 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3345 local_event->common.data_offset =
3346 sizeof(struct sound_trigger_phrase_recognition_event);
3347 local_event->common.data_size = opaque_size;
3348 opaque_data = (uint8_t *)local_event + local_event->common.data_offset;
3349 if ((st_ses->exec_mode == ST_EXEC_MODE_CPE) && st_ses->stdev->is_gcs) {
3350 payload_ptr = (uint8_t *)payload + 2;
3351 payload_size -= 2; /* Re-use */
3352 } else if ((st_ses->exec_mode == ST_EXEC_MODE_ADSP) ||
3353 !st_ses->stdev->is_gcs) {
3354 payload_ptr = (uint8_t *)payload;
3355 } else {
3356 ALOGE("%s: Invalid execution mode, exiting", __func__);
3357 status = -EINVAL;
3358 goto err_exit;
3359 }
3360
3361 /* Pack the opaque data confidence levels structure */
3362 param_hdr = (struct st_param_header *)opaque_data;
3363 param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
3364 opaque_data += sizeof(struct st_param_header);
3365 if (stc_ses->conf_levels_intf_version !=
3366 CONF_LEVELS_INTF_VERSION_0002) {
3367 param_hdr->payload_size =
3368 sizeof(struct st_confidence_levels_info);
3369 } else {
3370 param_hdr->payload_size =
3371 sizeof(struct st_confidence_levels_info_v2);
3372 }
3373 check_and_extract_det_conf_levels_payload(st_ses, payload_ptr,
3374 payload_size, &cf_levels, &cf_levels_size);
3375 if (!cf_levels || !cf_levels_size) {
3376 status = -EINVAL;
3377 goto err_exit;
3378 }
3379 memcpy(opaque_data, stc_ses->st_conf_levels, param_hdr->payload_size);
3380 pack_opaque_data_conf_levels(st_ses, opaque_data, cf_levels,
3381 cf_levels_size);
3382 pack_recognition_event_conf_levels(st_ses, cf_levels, cf_levels_size,
3383 local_event);
3384 opaque_data += param_hdr->payload_size;
3385
3386 /* Pack the opaque data keyword indices structure */
3387 if (enable_kw_indices) {
3388 param_hdr = (struct st_param_header *)opaque_data;
3389 param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
3390 param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
3391 opaque_data += sizeof(struct st_param_header);
3392 kw_indices = (struct st_keyword_indices_info *)opaque_data;
3393 kw_indices->version = 0x1;
3394 list_for_each(node, &stc_ses->second_stage_list) {
3395 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
3396 list_node);
3397 if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
3398 kw_indices->start_index =
3399 st_sec_stage->ss_session->kw_start_idx;
3400 kw_indices->end_index =
3401 st_sec_stage->ss_session->kw_end_idx;
3402 }
3403 }
3404 opaque_data += sizeof(struct st_keyword_indices_info);
3405 }
3406
3407 /* Pack the opaque data detection timestamp structure */
3408 param_hdr = (struct st_param_header *)opaque_data;
3409 param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
3410 param_hdr->payload_size = sizeof(struct st_timestamp_info);
3411 opaque_data += sizeof(struct st_param_header);
3412 timestamps = (struct st_timestamp_info *)opaque_data;
3413 timestamps->version = 0x1;
3414 timestamps->first_stage_det_event_time =
3415 st_hw_ses->first_stage_det_event_time;
3416 if (!list_empty(&stc_ses->second_stage_list))
3417 timestamps->second_stage_det_event_time =
3418 st_hw_ses->second_stage_det_event_time;
3419 opaque_data += sizeof(struct st_timestamp_info);
3420
3421 ST_DBG_DECLARE(FILE *opaque_fd = NULL; static int opaque_cnt = 0);
3422 ST_DBG_FILE_OPEN_WR(opaque_fd, ST_DEBUG_DUMP_LOCATION,
3423 "detection_opaque_data", "bin", opaque_cnt++);
3424 ST_DBG_FILE_WRITE(opaque_fd, (opaque_data - opaque_size), opaque_size);
3425 ST_DBG_FILE_CLOSE(opaque_fd);
3426
3427 } else {
3428 if (st_ses->vendor_uuid_info->is_qcva_uuid ||
3429 st_ses->vendor_uuid_info->is_qcmd_uuid) {
3430 if (st_ses->stdev->is_gcs &&
3431 ST_EXEC_MODE_CPE == st_ses->exec_mode &&
3432 !st_hw_ses->is_generic_event) {
3433 payload_ptr = payload;
3434 payload_ptr += 2; /* Skip minor_version and num_active_models */
3435 payload_size -= 2;
3436 } else {
3437 payload_ptr = payload;
3438 }
3439 status = generate_legacy_st_phrase_recognition_event(
3440 stc_ses->phrase_sm, stc_ses->rc_config, payload_ptr,
3441 payload_size, &local_event);
3442
3443 if (status)
3444 goto exit;
3445 } else {
3446 ALOGD("%s: Send detection payload as is", __func__);
3447
3448 local_event = calloc(1, sizeof(*local_event) + payload_size);
3449 if (!local_event) {
3450 ALOGE("%s: event allocation failed, size %zd", __func__,
3451 payload_size);
3452 status = -ENOMEM;
3453 goto exit;
3454 }
3455 memcpy(local_event->phrase_extras,
3456 stc_ses->rc_config->phrases, stc_ses->rc_config->num_phrases *
3457 sizeof(struct sound_trigger_phrase_recognition_extra));
3458 local_event->num_phrases = stc_ses->rc_config->num_phrases;
3459 local_event->common.data_offset = sizeof(*local_event);
3460 local_event->common.data_size = payload_size;
3461 memcpy((char *)local_event + local_event->common.data_offset,
3462 payload, payload_size);
3463 }
3464 }
3465
3466 /* fill the remaining recognition event parameters not specific
3467 to soundmodel lib */
3468 local_event->common.status = detect_status;
3469 local_event->common.type = stc_ses->phrase_sm->common.type;
3470 local_event->common.model = stc_ses->sm_handle;
3471 local_event->common.capture_available =
3472 stc_ses->rc_config->capture_requested;
3473 local_event->common.capture_delay_ms = 0;
3474 local_event->common.capture_preamble_ms = 0;
3475 local_event->common.audio_config.sample_rate =
3476 SOUND_TRIGGER_SAMPLING_RATE_16000;
3477 local_event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
3478 local_event->common.audio_config.channel_mask =
3479 audio_channel_in_mask_from_count(st_hw_ses->config.channels);
3480
3481 for (i = 0; i < local_event->num_phrases; ++i) {
3482 ALOGV("%s: [%d] kw_id %d level %d", __func__, i,
3483 local_event->phrase_extras[i].id,
3484 local_event->phrase_extras[i].confidence_level);
3485 for (j = 0; j < local_event->phrase_extras[i].num_levels; ++j) {
3486 ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
3487 local_event->phrase_extras[i].levels[j].user_id,
3488 local_event->phrase_extras[i].levels[j].level);
3489 }
3490 }
3491
3492 ALOGI("%s:[c%d]", __func__, stc_ses->sm_handle);
3493
3494 ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
3495 "num_phrases=%d id=%d", __func__, stc_ses->sm_handle,
3496 local_event->common.status, local_event->common.type,
3497 local_event->common.model, local_event->common.capture_available,
3498 local_event->num_phrases, local_event->phrase_extras[0].id);
3499
3500 *event = local_event;
3501 return 0;
3502
3503err_exit:
3504 if (local_event)
3505 free(local_event);
3506
3507exit:
3508 return status;
3509}
3510
3511static int process_detection_event_generic(st_proxy_session_t *st_ses,
3512 int detect_status,
3513 void *payload, size_t payload_size,
3514 struct sound_trigger_recognition_event **event)
3515{
3516 st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
3517 st_session_t *stc_ses = st_ses->det_stc_ses;
3518 struct st_vendor_info *v_info = st_ses->vendor_uuid_info;
3519 int status = 0;
3520 struct sound_trigger_recognition_event *local_event = NULL;
3521
3522 local_event = calloc(1, sizeof(*local_event) + payload_size);
3523 if (!local_event) {
3524 ALOGE("%s: event allocation failed, size %zd", __func__,
3525 payload_size);
3526 status = -ENOMEM;
3527 goto exit;
3528 }
3529
3530 local_event->status = detect_status;
3531 local_event->type = stc_ses->sm_type;
3532 local_event->model = stc_ses->sm_handle;
3533 local_event->capture_available = stc_ses->rc_config->capture_requested;
3534 local_event->capture_delay_ms = 0;
3535 local_event->capture_preamble_ms = 0;
3536 local_event->audio_config.sample_rate = v_info ?
3537 v_info->sample_rate : SOUND_TRIGGER_SAMPLING_RATE_16000;
3538 local_event->audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
3539 local_event->audio_config.channel_mask =
3540 audio_channel_in_mask_from_count(st_hw_ses->config.channels);
3541
3542 local_event->data_offset = sizeof(*local_event);
3543 local_event->data_size = payload_size;
3544 memcpy((char *)local_event + local_event->data_offset,
3545 payload, payload_size);
3546
3547 ALOGI("%s:[%d]", __func__, stc_ses->sm_handle);
3548 ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d",
3549 __func__, stc_ses->sm_handle, local_event->status,
3550 local_event->type, local_event->model,
3551 local_event->capture_available);
3552
3553 *event = local_event;
3554
3555exit:
3556 return status;
3557}
3558
3559static inline int process_detection_event(st_proxy_session_t *st_ses,
3560 uint64_t timestamp __unused,
3561 int detect_status,
3562 void *payload, size_t payload_size,
3563 struct sound_trigger_recognition_event **event)
3564{
3565 int ret;
3566 struct sound_trigger_phrase_recognition_event *phrase_event = NULL;
3567
3568 *event = NULL;
3569 if (st_ses->sm_info.sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
3570 if (sthw_extn_check_process_det_ev_support())
3571 ret = sthw_extn_process_detection_event_keyphrase(st_ses,
3572 timestamp, detect_status, payload, payload_size, &phrase_event);
3573 else if (st_ses->hw_ses_current->is_generic_event &&
3574 !st_ses->vendor_uuid_info->is_qcmd_uuid)
3575 ret = process_detection_event_keyphrase_v2(st_ses, detect_status,
3576 payload, payload_size, &phrase_event);
3577 else
3578 ret = process_detection_event_keyphrase(st_ses, detect_status,
3579 payload, payload_size, &phrase_event);
3580 if (phrase_event)
3581 *event = &phrase_event->common;
3582 } else {
3583 ret = process_detection_event_generic(st_ses, detect_status, payload,
3584 payload_size, event);
3585 }
3586 return ret;
3587}
3588
3589
3590/*
3591 * If the keyword detection session detects before the user verification
3592 * session, signal to process user verification. If the keyword detection
3593 * session rejects before the user verification session, signal to stop
3594 * processing user verification.
3595 */
3596static void handle_vop_pending_detection(st_arm_ss_session_t *ss_session,
3597 unsigned int det_status, unsigned int kw_det_buff_sz)
3598{
3599 if (det_status & KEYWORD_DETECTION_SUCCESS) {
3600 if (kw_det_buff_sz > ss_session->unread_bytes)
3601 ss_session->buff_sz = kw_det_buff_sz;
3602 else
3603 ss_session->buff_sz = ss_session->unread_bytes;
3604
3605 /*
3606 * It is possible that VOP started processing by already consuming
3607 * data from unread_bytes while CNN detects. In this case, it does
3608 * not need to be signaled.
3609 */
3610 if (ss_session->unread_bytes >= ss_session->buff_sz) {
3611 ALOGD("%s: Processing UV due to KW detection success", __func__);
3612 pthread_cond_signal(&ss_session->cond);
3613 }
3614 } else if (det_status & KEYWORD_DETECTION_REJECT) {
3615 ss_session->exit_buffering = true;
3616 ALOGD("%s: Exiting from UV due to KW detection rejection", __func__);
3617 pthread_cond_signal(&ss_session->cond);
3618 }
3619}
3620
3621/*
3622 * If the user verification session rejects before the keyword detection
3623 * session, signal to stop processing keyword detection.
3624 */
3625static void handle_cnn_pending_detection(st_arm_ss_session_t *ss_session,
3626 unsigned int det_status)
3627{
3628 if (det_status & USER_VERIFICATION_REJECT) {
3629 ss_session->exit_buffering = true;
3630 ALOGD("%s: Exiting from KW detection due to UV rejection", __func__);
3631 pthread_cond_signal(&ss_session->cond);
3632 }
3633}
3634
3635/*
3636 * This thread handles detection events from the second stage sessions
3637 * and aggregates them into 1 final decision. It will call the client callback
3638 * or restart the first stage session based on this decision.
3639 */
3640static void *aggregator_thread_loop(void *st_session)
3641{
3642 st_proxy_session_t *st_ses = (st_proxy_session_t *)st_session;
3643 st_session_t *stc_ses = NULL;
3644 recognition_callback_t callback = NULL;
3645 void *cookie = NULL;
3646 struct listnode *node = NULL;
3647 st_arm_second_stage_t *st_sec_stage = NULL;
3648 int status = 0, lock_status = 0;
3649 unsigned int kw_det_buff_sz = 0, det_status = 0;
3650 struct timespec tspec = {0};
3651 struct sound_trigger_recognition_event *event = NULL;
3652 bool capture_requested = false;
3653
3654 ALOGV("%s: Enter", __func__);
3655
3656 /*
3657 * For multi-clients it is expected only one of the clients detection
3658 * happens at a time. Continue processing on a run time detected client
3659 */
3660 pthread_mutex_lock(&st_ses->ss_detections_lock);
3661 while (!st_ses->exit_aggregator_loop) {
3662 det_status = 0;
3663 lock_status = 0;
3664 ALOGV("%s: waiting on cond", __func__);
3665 pthread_cond_wait(&st_ses->ss_detections_cond,
3666 &st_ses->ss_detections_lock);
3667 ALOGV("%s: done waiting on cond", __func__);
3668 if (st_ses->exit_aggregator_loop) {
3669 ALOGV("%s: exit", __func__);
3670 pthread_mutex_unlock(&st_ses->ss_detections_lock);
3671 return NULL;
3672 }
3673 if (!st_ses->det_stc_ses)
3674 continue;
3675 stc_ses = st_ses->det_stc_ses;
3676
3677 list_for_each(node, &stc_ses->second_stage_list) {
3678 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
3679 list_node);
3680
3681 pthread_mutex_lock(&st_sec_stage->ss_session->lock);
3682 det_status |= st_sec_stage->ss_session->det_status;
3683 if (st_sec_stage->ss_session->det_status ==
3684 KEYWORD_DETECTION_SUCCESS)
3685 kw_det_buff_sz = st_sec_stage->ss_session->bytes_processed;
3686 pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
3687 }
3688
3689 list_for_each(node, &stc_ses->second_stage_list) {
3690 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
3691 list_node);
3692
3693 pthread_mutex_lock(&st_sec_stage->ss_session->lock);
3694 if ((st_sec_stage->ss_info->sm_detection_type ==
3695 ST_SM_TYPE_USER_VERIFICATION) &&
3696 (det_status & USER_VERIFICATION_PENDING)) {
3697 handle_vop_pending_detection(st_sec_stage->ss_session,
3698 det_status, kw_det_buff_sz);
3699 } else if ((st_sec_stage->ss_info->sm_detection_type ==
3700 ST_SM_TYPE_KEYWORD_DETECTION) &&
3701 (det_status & KEYWORD_DETECTION_PENDING)) {
3702 handle_cnn_pending_detection(st_sec_stage->ss_session,
3703 det_status);
3704 }
3705 pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
3706 }
3707
3708 if (!IS_SS_DETECTION_PENDING(det_status)) {
3709 pthread_mutex_lock(&st_ses->lock);
3710 /*
3711 * If the client stops before 2nd stage finishes processing, or a
3712 * transition is in progress, the detection event should not be
3713 * handled.
3714 */
3715 if ((st_ses->current_state != buffering_state_fn) ||
3716 (st_ses->exec_mode == ST_EXEC_MODE_NONE)) {
3717 ALOGW("%s: First stage is not in a valid state, continuing",
3718 __func__);
3719 pthread_mutex_unlock(&st_ses->lock);
3720 continue;
3721 }
3722 if (IS_SS_DETECTION_SUCCESS(det_status)) {
3723 clock_gettime(CLOCK_MONOTONIC, &tspec);
3724 st_ses->hw_ses_current->second_stage_det_event_time =
3725 get_current_time_ns();
3726 ATRACE_ASYNC_END("sthal: detection success",
3727 st_ses->sm_handle);
3728
3729 status = process_detection_event(st_ses,
3730 st_ses->det_session_ev->payload.detected.timestamp,
3731 st_ses->det_session_ev->payload.detected.detect_status,
3732 st_ses->det_session_ev->payload.detected.detect_payload,
3733 st_ses->det_session_ev->payload.detected.payload_size,
3734 &event);
3735 if (status || !event) {
3736 ALOGE("%s:[%d] process_detection_event failed err %d",
3737 __func__, st_ses->sm_handle, status);
3738 /*
3739 * Stop buffering if this is not a successful detection and
3740 * LAB is triggered in hw automatically
3741 */
3742 st_ses->hw_ses_current->fptrs->stop_buffering(
3743 st_ses->hw_ses_current);
3744
3745 pthread_mutex_unlock(&st_ses->lock);
3746 if (event) {
3747 free(event);
3748 event = NULL;
3749 }
3750 goto exit;
3751 }
3752 callback = stc_ses->callback;
3753 capture_requested = stc_ses->rc_config->capture_requested;
3754 cookie = stc_ses->cookie;
3755 ALOGD("%s:[c%d] Second stage detected successfully, "
3756 "calling client callback", __func__, stc_ses->sm_handle);
3757 pthread_mutex_unlock(&st_ses->lock);
3758 ATRACE_BEGIN("sthal: client detection callback");
3759 callback(event, cookie);
3760 free(event);
3761 ATRACE_END();
3762
3763 /*
3764 * The client could unload the sound model during the callback,
3765 * which would join this thread and wait for this thread exit
3766 * as part of st_session_deinit() with st_session_lock held. By
3767 * this time, the state is also moved to idle. To avoid
3768 * deadlock, upon return from client callback, try acquiring
3769 * lock only if not in idle state, else exit right away.
3770 */
3771 do {
3772 lock_status = pthread_mutex_trylock(&st_ses->lock);
3773 } while (lock_status && (st_ses->current_state !=
3774 idle_state_fn));
3775
3776 if (st_ses->current_state == idle_state_fn) {
3777 ALOGV("%s:[%d] client unloaded after callback"
3778 ", lock status %d", __func__, st_ses->sm_handle,
3779 lock_status);
3780 if (!lock_status)
3781 pthread_mutex_unlock(&st_ses->lock);
3782 goto exit;
3783 }
3784 /*
3785 * If client has not requested capture data,
3786 * stop hw session buffering here to resume next
3787 * detection
3788 */
3789 if (!capture_requested)
3790 st_ses->hw_ses_current->fptrs->stop_buffering(
3791 st_ses->hw_ses_current);
3792 } else {
3793 ATRACE_ASYNC_END("sthal: detection reject",
3794 st_ses->sm_handle);
3795 ALOGD("%s: Second stage did NOT detect, restarting st_session",
3796 __func__);
3797 st_ses->hw_ses_current->fptrs->stop_buffering(
3798 st_ses->hw_ses_current);
3799 start_second_stage_for_client(stc_ses);
3800 st_session_ev_t ev = {.ev_id = ST_SES_EV_RESTART,
3801 .stc_ses = stc_ses};
3802 DISPATCH_EVENT(st_ses, ev, status);
3803 }
3804 pthread_mutex_unlock(&st_ses->lock);
3805 } else {
3806 ALOGV("%s: There is a second stage session pending, continuing",
3807 __func__);
3808 }
3809 }
3810exit:
3811 pthread_mutex_unlock(&st_ses->ss_detections_lock);
3812 ALOGV("%s: Exit", __func__);
3813 return NULL;
3814}
3815
3816static void init_det_event_aggregator(st_proxy_session_t *st_ses)
3817{
3818 int status = 0;
3819 pthread_condattr_t attr;
3820
3821 ALOGV("%s", __func__);
3822
3823 st_ses->exit_aggregator_loop = false;
3824 pthread_mutex_init(&st_ses->ss_detections_lock, NULL);
3825 pthread_condattr_init(&attr);
3826 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
3827 pthread_cond_init(&st_ses->ss_detections_cond, &attr);
3828 pthread_condattr_destroy(&attr);
3829 status = pthread_create(&st_ses->aggregator_thread, NULL,
3830 aggregator_thread_loop, st_ses);
3831 if (status) {
3832 ALOGE("%s: Error creating aggregator thread. status = %d",
3833 __func__, status);
3834 } else {
3835 st_ses->aggregator_thread_created = true;
3836 }
3837}
3838
3839static void destroy_det_event_aggregator(st_proxy_session_t *st_ses)
3840{
3841 int status = 0;
3842
3843 ALOGV("%s", __func__);
3844
3845 st_ses->exit_aggregator_loop = true;
3846 pthread_mutex_lock(&st_ses->ss_detections_lock);
3847 pthread_cond_signal(&st_ses->ss_detections_cond);
3848 pthread_mutex_unlock(&st_ses->ss_detections_lock);
3849 status = pthread_join(st_ses->aggregator_thread, NULL);
3850 if (status)
3851 ALOGE("%s: Error joining aggregator thread. status = %d",
3852 __func__, status);
3853 pthread_cond_destroy(&st_ses->ss_detections_cond);
3854 pthread_mutex_destroy(&st_ses->ss_detections_lock);
3855 st_ses->aggregator_thread_created = false;
3856}
3857
3858/* This function is called for multi-client */
3859static int handle_load_sm(st_proxy_session_t *st_ses, st_session_t *stc_ses)
3860{
3861 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
3862 int status = 0;
3863
3864 ALOGV("%s:[c%d-%d]", __func__, stc_ses->sm_handle, st_ses->sm_handle);
3865 if (!stc_ses->phrase_sm) {
3866 ALOGE("%s:[c%d] sound model data is not initialzed", __func__,
3867 stc_ses->sm_handle);
3868 return -EINVAL;
3869 }
3870
3871 if (!is_other_client_attached(st_ses, stc_ses)) {
3872 ALOGE("%s:[c%d] Unexpected without multi-clients", __func__,
3873 stc_ses->sm_handle);
3874 return -EINVAL;
3875 }
3876
3877 if (st_ses->current_state == buffering_state_fn)
3878 hw_ses->fptrs->stop_buffering(hw_ses);
3879
3880 if (st_ses->current_state == active_state_fn ||
3881 st_ses->current_state == detected_state_fn ||
3882 st_ses->current_state == buffering_state_fn) {
3883 status = stop_session(st_ses, hw_ses, false);
3884 if (status)
3885 ALOGE("%s:[%d] stop_session failed %d", __func__, st_ses->sm_handle,
3886 status);
3887 }
3888
3889 status = hw_ses->fptrs->dereg_sm(hw_ses);
3890 if (status) {
3891 ALOGE("%s:[%d] dereg_sm failed %d", __func__,
3892 st_ses->sm_handle, status);
3893 }
3894 /* Continue updating sound model resulting in merged model */
3895 status = update_sound_model(stc_ses, true);
3896 if (status) {
3897 ALOGE("%s:[c%d] update_sound_model add failed %d", __func__,
3898 stc_ses->sm_handle, status);
3899 goto exit;
3900 }
3901 hw_ses->sthw_cfg.conf_levels = st_ses->sm_info.cf_levels;
3902 hw_ses->sthw_cfg.num_conf_levels = st_ses->sm_info.cf_levels_size;
3903 hw_ses->sthw_cfg_updated = true;
3904 /*
3905 * Sound model merge would have changed the order of merge conf levels,
3906 * which need to be re-updated for all current active clients, if any.
3907 */
3908 status = update_merge_conf_levels_payload_with_active_clients(st_ses);
3909 if (status)
3910 goto exit_1;
3911
3912 /* Load merged sound model */
3913 status = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_info.sm_data,
3914 st_ses->sm_info.sm_size, st_ses->sm_info.sm_type);
3915 if (status) {
3916 ALOGE("%s:[%d] reg_sm failed %d", __func__,
3917 st_ses->sm_handle, status);
3918 goto exit_1;
3919 }
3920
3921 if (st_ses->current_state == active_state_fn ||
3922 st_ses->current_state == detected_state_fn ||
3923 st_ses->current_state == buffering_state_fn) {
3924
3925 status = start_session(st_ses, hw_ses, false);
3926 if (status)
3927 goto exit_2;
3928 STATE_TRANSITION(st_ses, active_state_fn);
3929 }
3930
3931 return 0;
3932
3933exit_2:
3934 if (!st_ses->stdev->ssr_offline_received)
3935 hw_ses->fptrs->dereg_sm(hw_ses);
3936
3937exit_1:
3938 if (!st_ses->stdev->ssr_offline_received) {
3939 update_sound_model(stc_ses, false);
3940 update_merge_conf_levels_payload_with_active_clients(st_ses);
3941 }
3942
3943exit:
3944 if (st_ses->stdev->ssr_offline_received) {
3945 STATE_TRANSITION(st_ses, ssr_state_fn);
3946 status = 0;
3947 }
3948 return status;
3949}
3950
3951/* This function is called for multi-client */
3952static int handle_unload_sm(st_proxy_session_t *st_ses, st_session_t *stc_ses)
3953{
3954 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
3955 int status = 0;
3956
3957 ALOGV("%s:[c%d-%d]", __func__, stc_ses->sm_handle, st_ses->sm_handle);
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__,
3974 st_ses->sm_handle, status);
3975 }
3976
3977 status = hw_ses->fptrs->dereg_sm(hw_ses);
3978 if (status)
3979 ALOGE("%s:[%d] dereg_sm failed %d", __func__, st_ses->sm_handle, status);
3980
3981 /* Continue deleting this model */
3982 status = update_sound_model(stc_ses, false);
3983 if (status)
3984 ALOGE("%s:[c%d] update_sound_model delete failed %d", __func__,
3985 stc_ses->sm_handle, status);
3986
3987 hw_ses->sthw_cfg.conf_levels = st_ses->sm_info.cf_levels;
3988 hw_ses->sthw_cfg.num_conf_levels = st_ses->sm_info.cf_levels_size;
3989 hw_ses->sthw_cfg_updated = true;
3990 /*
3991 * Sound model merge would have changed the order of merge conf levels,
3992 * which need to be re-updated for all current active clients, if any.
3993 */
3994 update_merge_conf_levels_payload_with_active_clients(st_ses);
3995
3996 /* Load remaining merged sound model */
3997 status = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_info.sm_data,
3998 st_ses->sm_info.sm_size, st_ses->sm_info.sm_type);
3999 if (status) {
4000 ALOGE("%s:[%d] reg_sm failed %d", __func__,
4001 st_ses->sm_handle, status);
4002 goto exit;
4003 }
4004
4005 if (st_ses->current_state == active_state_fn ||
4006 st_ses->current_state == detected_state_fn ||
4007 st_ses->current_state == buffering_state_fn) {
4008
4009 status = start_session(st_ses, hw_ses, false);
4010 if (status)
4011 goto exit;
4012 STATE_TRANSITION(st_ses, active_state_fn);
4013 }
4014 return 0;
4015
4016exit:
4017 if (st_ses->stdev->ssr_offline_received) {
4018 STATE_TRANSITION(st_ses, ssr_state_fn);
4019 status = 0;
4020 }
4021 return status;
4022}
4023
4024static int idle_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07004025{
4026 int status = 0;
4027 int ret = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004028 st_session_t *stc_ses = ev->stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07004029 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male2e883752019-03-22 11:28:54 -07004030
4031 /* skip parameter check as this is an internal funciton */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004032 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
4033 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07004034
4035 switch (ev->ev_id) {
4036 case ST_SES_EV_LOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004037 if (!stc_ses->phrase_sm) {
Quinn Male2e883752019-03-22 11:28:54 -07004038 ALOGE("%s: sound model data is not initialzed", __func__);
4039 status = -EINVAL;
4040 break;
4041 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004042 status = update_sound_model(stc_ses, true);
4043 if (status) {
4044 ALOGE("%s:[c%d] update sound model add failed %d", __func__,
4045 stc_ses->sm_handle, status);
4046 status = -EINVAL;
4047 break;
4048 }
Quinn Male2e883752019-03-22 11:28:54 -07004049
4050 /*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004051 * Do retry to handle a corner case that when ADSP SSR ONLINE is
4052 * received, sometimes ADSP is still not ready to receive cmd from HLOS
4053 * and thus fails, so try more times to recover the session from SSR
4054 * state.
Quinn Male2e883752019-03-22 11:28:54 -07004055 */
4056 for (int i = 0; i < REG_SM_RETRY_CNT; i++) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004057 status = ret = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_info.sm_data,
4058 st_ses->sm_info.sm_size, st_ses->sm_info.sm_type);
Quinn Male2e883752019-03-22 11:28:54 -07004059 if (ret) {
4060 if (st_ses->stdev->ssr_offline_received) {
Quinn Male2e883752019-03-22 11:28:54 -07004061 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07004062 status = 0;
4063 break;
4064 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004065 ALOGE("%s:[%d] failed to reg sm, err %d, retry cnt %d",
4066 __func__, st_ses->sm_handle, status, i);
Quinn Male2e883752019-03-22 11:28:54 -07004067 usleep(REG_SM_WAIT_TIME_MS * 1000);
4068 }
4069 } else {
4070 break;
4071 }
4072 }
4073 if (ret)
4074 break;
4075
Quinn Male2e883752019-03-22 11:28:54 -07004076 STATE_TRANSITION(st_ses, loaded_state_fn);
4077 break;
4078
4079 case ST_SES_EV_SET_EXEC_MODE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004080 stc_ses->exec_mode = ev->payload.exec_mode;
4081 if (ev->payload.exec_mode == st_ses->exec_mode)
4082 break;
4083
Quinn Male2e883752019-03-22 11:28:54 -07004084 st_ses->exec_mode = ev->payload.exec_mode;
4085 if (ST_EXEC_MODE_CPE == st_ses->exec_mode)
4086 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
4087 else if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
4088 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
4089 /* remain in current state */
4090 break;
4091
4092 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004093 stc_ses->paused = true;
Quinn Male2e883752019-03-22 11:28:54 -07004094 break;
4095
4096 case ST_SES_EV_RESUME:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004097 stc_ses->paused = false;
Quinn Male2e883752019-03-22 11:28:54 -07004098 break;
4099
4100 case ST_SES_EV_SSR_OFFLINE:
4101 STATE_TRANSITION(st_ses, ssr_state_fn);
4102 break;
4103
4104 case ST_SES_EV_SEND_CHMIX_COEFF:
4105 status = -EIO;
4106 break;
4107
4108 case ST_SES_EV_GET_PARAM_DATA:
4109 status = -EIO;
4110 break;
4111
4112 case ST_SES_EV_REQUEST_DET:
4113 ALOGE("%s:[%d] Event not supported in this state",
4114 __func__, st_ses->sm_handle);
4115 status = -EINVAL;
4116 break;
4117
4118 default:
4119 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
4120 break;
4121 };
4122
4123 return status;
4124}
4125
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004126static int loaded_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07004127{
4128 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004129 st_session_t *stc_ses = ev->stc_ses;
4130 struct listnode *node = NULL;
4131 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07004132 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
4133 st_hw_session_t *new_hw_ses = NULL;
4134 st_exec_mode_t new_exec_mode = 0;
Quinn Male2e883752019-03-22 11:28:54 -07004135
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004136 /* skip parameter check as this is an internal function */
4137 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
4138 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07004139
4140 switch (ev->ev_id) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004141 case ST_SES_EV_LOAD_SM:
4142 /* Valid only in multi-client session usecase */
4143 status = handle_load_sm(st_ses, stc_ses);
Quinn Male2e883752019-03-22 11:28:54 -07004144 break;
4145
4146 case ST_SES_EV_UNLOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004147 if (is_other_client_attached(st_ses, stc_ses)) {
4148 status = handle_unload_sm(st_ses, stc_ses);
4149 break;
Quinn Male2e883752019-03-22 11:28:54 -07004150 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004151
4152 status = hw_ses->fptrs->dereg_sm(hw_ses);
4153 if (status)
4154 ALOGE("%s:[%d] dereg_sm failed %d", __func__,
4155 st_ses->sm_handle, status);
4156
4157 status = update_sound_model(stc_ses, false);
4158 if (status)
4159 ALOGE("%s:[c%d] update_sound_model failed %d", __func__,
4160 stc_ses->sm_handle, status);
4161
4162 /* since this is a teardown scenario dont fail here */
4163 status = 0;
Quinn Male2e883752019-03-22 11:28:54 -07004164 STATE_TRANSITION(st_ses, idle_state_fn);
4165 break;
4166
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004167 case ST_SES_EV_RESUME:
4168 stc_ses->paused = false;
4169 if (!is_any_client_in_state(st_ses, ST_STATE_ACTIVE))
4170 break;
4171 /* Fall through */
4172 case ST_SES_EV_START:
4173 case ST_SES_EV_RESTART:
4174 if (ev->ev_id == ST_SES_EV_RESTART)
4175 update_hw_config_on_restart(st_ses, stc_ses);
4176
4177 /*
4178 * During Resume, the first active client will start the hw sesison.
4179 * During Start, check for any paused sessions to delay actual start
4180 * to Resume.
4181 */
4182 if ((ev->ev_id != ST_SES_EV_RESUME) && is_any_client_paused(st_ses))
4183 break;
4184
4185 status = start_session(st_ses, hw_ses, false);
4186 if (status) {
4187 if (st_ses->stdev->ssr_offline_received) {
4188 hw_ses->fptrs->dereg_sm(hw_ses);
4189 STATE_TRANSITION(st_ses, ssr_state_fn);
4190 status = 0;
4191 } else {
4192 ALOGE("%s:[%d] failed to start session, err %d", __func__,
4193 st_ses->sm_handle, status);
4194 }
4195 break;
4196 }
4197 STATE_TRANSITION(st_ses, active_state_fn);
4198 break;
4199
4200 case ST_SES_EV_STOP:
4201 /*
4202 * Valid in multi-client case.
4203 * Reconfig based off other active clients, if any, so that RESUME
4204 * can apply this reconfig.
4205 */
4206 update_hw_config_on_stop(st_ses, stc_ses);
4207 break;
4208
Quinn Male2e883752019-03-22 11:28:54 -07004209 case ST_SES_EV_SSR_OFFLINE:
Quinn Male2e883752019-03-22 11:28:54 -07004210 /* exec mode can be none if ssr occurs during a transition */
4211 if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004212 hw_ses->fptrs->dereg_sm(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07004213 STATE_TRANSITION(st_ses, ssr_state_fn);
4214 break;
4215
4216 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004217 stc_ses->paused = true;
Quinn Male2e883752019-03-22 11:28:54 -07004218 break;
4219
4220 case ST_SES_EV_SET_EXEC_MODE:
4221 new_exec_mode = ev->payload.exec_mode;
4222
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004223 if (new_exec_mode == st_ses->exec_mode) {
4224 stc_ses->exec_mode = st_ses->exec_mode;
4225 break;
Quinn Male2e883752019-03-22 11:28:54 -07004226 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004227
4228 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
4229 st_ses->exec_mode = ST_EXEC_MODE_NONE;
4230 list_for_each(node, &st_ses->clients_list) {
4231 c_ses = node_to_item(node, st_session_t, hw_list_node);
4232 c_ses->exec_mode = ST_EXEC_MODE_NONE;
4233 }
4234 /* unload sm for current hw session */
4235 status = hw_ses->fptrs->dereg_sm(hw_ses);
4236 if (status) {
4237 ALOGE("%s:[%d] dereg_sm failed with err %d", __func__,
4238 st_ses->sm_handle, status);
4239 break;
4240 }
4241 }
4242
4243 if (new_exec_mode == ST_EXEC_MODE_NONE)
4244 break;
4245
4246 /* load sm to new hw_ses */
4247 if (ST_EXEC_MODE_CPE == new_exec_mode) {
4248 new_hw_ses = st_ses->hw_ses_cpe;
4249 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
4250 new_hw_ses = st_ses->hw_ses_adsp;
4251 } else {
4252 ALOGE("%s: unknown execution mode %d", __func__,
4253 new_exec_mode);
4254 status = -EINVAL;
4255 break;
4256 }
4257
4258 status = new_hw_ses->fptrs->reg_sm(new_hw_ses,
4259 st_ses->sm_info.sm_data, st_ses->sm_info.sm_size,
4260 st_ses->sm_info.sm_type);
4261 if (status) {
4262 ALOGE("%s:[%d] reg_sm failed with err %d", __func__,
4263 st_ses->sm_handle, status);
4264 break;
4265 }
4266 /* switch hw sessions only if successful*/
4267 list_for_each(node, &st_ses->clients_list) {
4268 c_ses = node_to_item(node, st_session_t, hw_list_node);
4269 c_ses->exec_mode = new_exec_mode;
4270 if (c_ses->state == ST_STATE_ACTIVE) {
4271 dereg_hal_event_session(c_ses);
4272 reg_hal_event_session(c_ses, new_hw_ses);
4273 }
4274 }
4275 st_ses->exec_mode = new_exec_mode;
4276 st_ses->hw_ses_current = new_hw_ses;
4277 /* remain in current state */
Quinn Male2e883752019-03-22 11:28:54 -07004278 break;
4279
4280 case ST_SES_EV_SET_DEVICE:
4281 /*
4282 * This event handling is needed for certain graphs which
4283 * have multiple buffering modules with a single voice wakeup
4284 * module in each usecase.
4285 */
4286 if (!ev->payload.enable)
4287 status = hw_ses->fptrs->disable_device(hw_ses, false);
4288 else
4289 status = hw_ses->fptrs->enable_device(hw_ses, false);
4290
4291 break;
4292
4293 case ST_SES_EV_READ_PCM:
4294 /*
4295 * set status to failure this will tell AHAL to
4296 * provide zero buffers to client
4297 */
4298 status = -EIO;
4299 break;
4300
4301 case ST_SES_EV_SEND_CHMIX_COEFF:
4302 status = -EIO;
4303 break;
4304
4305 case ST_SES_EV_GET_PARAM_DATA:
4306 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004307 ev->payload.getparam.param, ev->payload.getparam.payload,
4308 ev->payload.getparam.payload_size,
4309 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07004310 break;
4311
4312 case ST_SES_EV_REQUEST_DET:
4313 ALOGE("%s:[%d] Event not supported in this state",
4314 __func__, st_ses->sm_handle);
4315 status = -EINVAL;
4316 break;
4317
4318 default:
4319 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
4320 break;
Quinn Male2e883752019-03-22 11:28:54 -07004321 };
4322
4323 return status;
Quinn Male2e883752019-03-22 11:28:54 -07004324}
4325
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004326static int active_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07004327{
4328 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004329 st_session_t *stc_ses = ev->stc_ses;
4330 struct listnode *node = NULL;
4331 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07004332 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Quinn Male2e883752019-03-22 11:28:54 -07004333 st_hw_session_t *new_hw_ses = NULL;
4334 st_exec_mode_t new_exec_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004335 st_arm_second_stage_t *st_sec_stage = NULL;
4336 struct sound_trigger_recognition_event *event = NULL;
4337 recognition_callback_t callback = NULL;
4338 void *cookie = NULL;
4339 bool lab_enabled = false, enable_second_stage = false, active = false;
Quinn Male2e883752019-03-22 11:28:54 -07004340
4341 /* skip parameter check as this is an internal funciton */
4342 ALOGD("%s:[%d] handle event id %d", __func__, st_ses->sm_handle, ev->ev_id);
4343
4344 switch (ev->ev_id) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004345 case ST_SES_EV_LOAD_SM:
4346 /* Valid in multi-client usecase */
4347 status = handle_load_sm(st_ses, stc_ses);
4348 break;
4349
4350 case ST_SES_EV_UNLOAD_SM:
4351 /* Valid in multi-client usecase */
4352 status = handle_unload_sm(st_ses, stc_ses);
4353 break;
4354
4355 case ST_SES_EV_RESTART:
4356 /* Valid in multi-client usecase */
4357 update_hw_config_on_restart(st_ses, stc_ses);
4358 /* Fall through */
4359 case ST_SES_EV_START:
4360 /* Valid in multi-client usecase */
4361 status = stop_session(st_ses, hw_ses, false);
4362 if (!status) {
4363 status = start_session(st_ses, hw_ses, false);
4364 if (status)
4365 ALOGE("%s:[%d] start_session failed %d", __func__,
4366 st_ses->sm_handle, status);
4367 } else {
4368 ALOGE("%s:[%d] stop_session failed %d", __func__,
4369 st_ses->sm_handle, status);
4370 }
4371 if (status & st_ses->stdev->ssr_offline_received) {
4372 hw_ses->fptrs->dereg_sm(hw_ses);
4373 STATE_TRANSITION(st_ses, ssr_state_fn);
4374 status = 0;
4375 }
4376 break;
4377
Quinn Male2e883752019-03-22 11:28:54 -07004378 case ST_SES_EV_SET_EXEC_MODE:
4379 new_exec_mode = ev->payload.exec_mode;
4380
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004381 if (new_exec_mode == st_ses->exec_mode) {
4382 stc_ses->exec_mode = st_ses->exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07004383 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004384 }
Quinn Male2e883752019-03-22 11:28:54 -07004385
4386 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
4387 ALOGV("%s: disable current session", __func__);
4388 st_ses->exec_mode = ST_EXEC_MODE_NONE;
4389 status = stop_session(st_ses, hw_ses, true);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004390 list_for_each(node, &st_ses->clients_list) {
4391 c_ses = node_to_item(node, st_session_t, hw_list_node);
4392 c_ses->exec_mode = ST_EXEC_MODE_NONE;
4393 }
Quinn Male2e883752019-03-22 11:28:54 -07004394 if (status)
4395 break;
4396 }
4397
4398 if (new_exec_mode == ST_EXEC_MODE_NONE)
4399 break;
4400
4401 if (ST_EXEC_MODE_CPE == new_exec_mode) {
4402 new_hw_ses = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07004403 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
4404 new_hw_ses = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07004405 } else {
4406 ALOGE("%s: unknown execution mode %d", __func__,
4407 new_exec_mode);
4408 status = -EINVAL;
4409 break;
4410 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004411 /*
4412 * hw session changed to/from WDSP/ADSP, hence update the
4413 * related config.
4414 * Not applicable for LPI<->non-LPI transtions as hw session
4415 * doesn't change.
4416 */
4417 status = update_hw_config_on_start(stc_ses, new_hw_ses);
4418 if (status) {
4419 ALOGE("%s: Update_hw_config_on_start failed %d",
4420 __func__, status);
4421 break;
4422 }
Quinn Male2e883752019-03-22 11:28:54 -07004423
4424 ALOGV("%s: enable current session", __func__);
4425 status = start_session(st_ses, new_hw_ses, true);
4426 if (status)
4427 break;
4428
4429 /* set new exec mode and current session */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004430 list_for_each(node, &st_ses->clients_list) {
4431 c_ses = node_to_item(node, st_session_t, hw_list_node);
4432 c_ses->exec_mode = new_exec_mode;
4433 if (c_ses->state == ST_STATE_ACTIVE) {
4434 dereg_hal_event_session(c_ses);
4435 reg_hal_event_session(c_ses, new_hw_ses);
4436 }
4437 }
Quinn Male2e883752019-03-22 11:28:54 -07004438 st_ses->exec_mode = new_exec_mode;
4439 st_ses->hw_ses_current = new_hw_ses;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004440
Quinn Male2e883752019-03-22 11:28:54 -07004441 ALOGV("%s: end transition", __func__);
4442 break;
4443
4444 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004445 /*
4446 * For multi-client, the first active pausing client stops the hw
4447 * session and moves to loaded state.
4448 */
4449 stc_ses->paused = true;
4450 if (stc_ses->state != ST_STATE_ACTIVE)
4451 break;
4452
Quinn Male2e883752019-03-22 11:28:54 -07004453 status = stop_session(st_ses, hw_ses, false);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004454
Quinn Male2e883752019-03-22 11:28:54 -07004455 if (status) {
4456 if (st_ses->stdev->ssr_offline_received) {
4457 STATE_TRANSITION(st_ses, ssr_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004458 hw_ses->fptrs->dereg_sm(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07004459 status = 0;
4460 } else {
4461 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
4462 st_ses->sm_handle, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004463 /* Move anyway to loaded state */
4464 STATE_TRANSITION(st_ses, loaded_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07004465 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004466 break;
Quinn Male2e883752019-03-22 11:28:54 -07004467 }
Quinn Male2e883752019-03-22 11:28:54 -07004468 STATE_TRANSITION(st_ses, loaded_state_fn);
4469 break;
4470
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004471 case ST_SES_EV_STOP:
4472 status = stop_session(st_ses, hw_ses, false);
4473 if (status)
4474 ALOGE("%s:[%d] start_session failed %d", __func__,
4475 st_ses->sm_handle, status);
Quinn Male2e883752019-03-22 11:28:54 -07004476
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004477 /* Continue to reconfig based off other active clients, if any */
4478 active = update_hw_config_on_stop(st_ses, stc_ses);
4479
4480 if (!status) {
4481 if (active) {
4482 ALOGD("%s: client c%d stopped, start %d due to reconfig",
4483 __func__, stc_ses->sm_handle, st_ses->sm_handle);
4484 status = start_session(st_ses, hw_ses, false);
4485 if (status)
4486 ALOGE("%s:[%d] start_session failed %d", __func__,
Quinn Male2e883752019-03-22 11:28:54 -07004487 st_ses->sm_handle, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004488 /* Stay in active state */
Quinn Male2e883752019-03-22 11:28:54 -07004489 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004490 STATE_TRANSITION(st_ses, loaded_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07004491 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004492 }
Quinn Male2e883752019-03-22 11:28:54 -07004493
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004494 if (status) {
4495 if (st_ses->stdev->ssr_offline_received) {
4496 hw_ses->fptrs->dereg_sm(hw_ses);
4497 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07004498 status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004499 } else {
4500 STATE_TRANSITION(st_ses, loaded_state_fn);
4501 }
4502 }
4503
4504 break;
4505
4506 case ST_SES_EV_DETECTED:
4507 /*
4508 * Find which client is this detection for.
4509 * Note that only one keyword detection can happen at a time.
4510 */
4511 stc_ses = get_detected_client(st_ses,
4512 ev->payload.detected.detect_payload,
4513 ev->payload.detected.payload_size);
4514
4515 if (!stc_ses) {
4516 ALOGW("%s:[%d] Couldn't find a matching client for detection",
4517 __func__, st_ses->sm_handle);
4518 /*
4519 * Though we set higest conf level 100 for inactive client in merged
4520 * sound model, it may be possible it still detects. In case the lab
4521 * is enabled due to other active client, stop hw buffering.
4522 */
4523 if (st_ses->lab_enabled)
4524 hw_ses->fptrs->stop_buffering(hw_ses);
4525 break;
4526 }
4527 st_ses->det_stc_ses = stc_ses;
4528 st_ses->hw_ses_current->enable_second_stage = false; /* Initialize */
4529
4530 if (list_empty(&stc_ses->second_stage_list) ||
4531 st_ses->detection_requested) {
4532 st_ses->detection_requested = false;
4533 status = process_detection_event(st_ses,
4534 ev->payload.detected.timestamp,
4535 ev->payload.detected.detect_status,
4536 ev->payload.detected.detect_payload,
4537 ev->payload.detected.payload_size,
4538 &event);
4539 if (status || !event) {
4540 ALOGE("%s:[%d] process_detection_event failed err %d", __func__,
4541 st_ses->sm_handle, status);
4542 /*
4543 * Stop buffering if this is not a successful detection and
4544 * LAB is triggered in hw automatically
4545 */
4546 hw_ses->fptrs->stop_buffering(hw_ses);
4547 if (event)
4548 free(event);
Quinn Male2e883752019-03-22 11:28:54 -07004549 break;
4550 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004551 } else {
4552 ALOGV("%s:[c%d] second stage enabled, list_empty %d,"
4553 "det_requested %d", __func__, stc_ses->sm_handle,
4554 list_empty(&stc_ses->second_stage_list),
4555 st_ses->detection_requested);
Quinn Male2e883752019-03-22 11:28:54 -07004556
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004557 enable_second_stage = true;
Quinn Male2e883752019-03-22 11:28:54 -07004558 /*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004559 * Before first stage starts buffering, update the second stage info
4560 * to first stage layer for further communication between first and
4561 * second stage layers.
Quinn Male2e883752019-03-22 11:28:54 -07004562 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004563 st_ses->hw_ses_current->enable_second_stage = true;
4564 st_ses->hw_ses_current->second_stage_list =
4565 &(stc_ses->second_stage_list);
Quinn Male2e883752019-03-22 11:28:54 -07004566
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004567 list_for_each(node, &stc_ses->second_stage_list) {
4568 st_sec_stage = node_to_item(node, st_arm_second_stage_t,
4569 list_node);
4570 st_sec_stage->ss_session->st_ses = st_ses;
4571 }
4572 get_first_stage_detection_params(st_ses,
4573 ev->payload.detected.detect_payload,
4574 ev->payload.detected.payload_size);
4575 memcpy(st_ses->det_session_ev, ev, sizeof(st_session_ev_t));
4576 }
4577 /*
4578 * change to new state before invoking user callback, this will
4579 * ensure that if user calls start_recognition immediately from the
4580 * callback it will be handled by one of the two states below
4581 */
4582 if (!status && st_ses->lab_enabled) {
4583 if (stc_ses->rc_config->capture_requested ||
4584 !list_empty(&stc_ses->second_stage_list)) {
4585 ST_DBG_FILE_OPEN_WR(st_ses->lab_fp, ST_DEBUG_DUMP_LOCATION,
4586 "lab_capture", "bin", file_cnt++);
4587 STATE_TRANSITION(st_ses, buffering_state_fn);
4588 lab_enabled = true;
4589 } else {
4590 /*
4591 * for merged model case the client detected may not have
4592 * requested the capture nor enabled the second stage, but the
4593 * hw lab could be enabled due to other client requested capture
4594 * or enabled second stage.
4595 */
4596 ALOGV("%s: stop buffering as c%d doesn't need", __func__,
4597 stc_ses->sm_handle);
4598 hw_ses->fptrs->stop_buffering(hw_ses);
4599 STATE_TRANSITION(st_ses, detected_state_fn);
4600 lab_enabled = false;
4601 }
4602 } else {
4603 STATE_TRANSITION(st_ses, detected_state_fn);
4604 }
4605
4606 if (!stc_ses->callback) {
4607 ALOGE("%s:[c%d] received detection event but no callback",
4608 __func__, stc_ses->sm_handle);
4609 status = -EINVAL;
4610 if (event)
Quinn Male2e883752019-03-22 11:28:54 -07004611 free(event);
4612 break;
4613 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004614 /*
4615 * callback to user, assumption is that client does not
4616 * block in the callback waiting for data otherwise will be a deadlock.
4617 * If second stage is enabled, the detection will be sent later when
4618 * second stage successfully detects.
4619 */
4620 if (!enable_second_stage) {
4621 callback = stc_ses->callback;
4622 cookie = stc_ses->cookie;
4623 ALOGD("%s:[c%d] invoking the client callback",
4624 __func__, stc_ses->sm_handle);
4625 ATRACE_ASYNC_END("sthal: detection success",
4626 st_ses->sm_handle);
4627 pthread_mutex_unlock(&st_ses->lock);
4628 ATRACE_BEGIN("sthal: client detection callback");
4629 callback(event, cookie);
4630 ATRACE_END();
4631 } else {
4632 pthread_mutex_unlock(&st_ses->lock);
4633 }
4634 if (event)
4635 free(event);
4636
4637 /*
4638 * TODO: Add RECOGNITION_STATUS_GET_STATE_RESPONSE to
4639 * the SoundTrigger API header.
4640 */
4641 if (lab_enabled &&
4642 ((ev->payload.detected.detect_status ==
4643 RECOGNITION_STATUS_SUCCESS) ||
4644 (ev->payload.detected.detect_status == 3))) {
4645 /* Cache lab data to internal buffers (blocking call) */
4646 hw_ses->fptrs->process_lab_capture(hw_ses);
4647 }
4648
4649 /*
4650 * It is possible that the client may start/stop/unload the session
4651 * with the same lock held, before we aqcuire lock here.
4652 * We need further processing only if client starts in detected state
4653 * or buffering state if lab was enabled, else return gracefully.
4654 * For multi-client scenario, only one client is assumed to be
4655 * detected/bufffering, so the logic remains same.
4656 */
4657 do {
4658 status = pthread_mutex_trylock(&st_ses->lock);
4659 } while (status && ((st_ses->current_state == detected_state_fn) ||
4660 (st_ses->current_state == buffering_state_fn)));
4661
4662 if (st_ses->current_state != detected_state_fn) {
4663 ALOGV("%s:[%d] client not in detected state, lock status %d",
4664 __func__, st_ses->sm_handle, status);
4665 if (!status) {
4666 /*
4667 * Stop session if still in buffering state and no pending
4668 * stop to be handled i.e. internally buffering was stopped.
4669 * This is required to avoid further detections in wrong state.
4670 * Client is expected to issue start recognition for current
4671 * detection event which will restart the session.
4672 */
4673 if ((st_ses->current_state == buffering_state_fn) &&
4674 !stc_ses->pending_stop) {
4675 ALOGD("%s:[%d] buffering stopped internally, post c%d stop",
4676 __func__, st_ses->sm_handle,
4677 st_ses->det_stc_ses->sm_handle);
4678 status = hw_session_notifier_enqueue(stc_ses->sm_handle,
4679 ST_SES_EV_DEFERRED_STOP,
4680 ST_SES_DEFERRED_STOP_SS_DELAY_MS);
4681 if (!status)
4682 stc_ses->pending_stop = true;
4683 }
4684 pthread_mutex_unlock(&st_ses->lock);
4685 }
4686 status = 0;
4687 break;
4688 }
4689
4690 /*
4691 * If we are not buffering (i.e capture is not requested), then
4692 * trigger a deferred stop. Most applications issue (re)start
4693 * almost immediately. Delaying stop allows unnecessary teardown
4694 * and reinitialization of backend.
4695 */
4696 if (!lab_enabled) {
4697 /*
4698 * Note that this event will only be posted to the detected state
4699 * The current state may switch to active if the client
4700 * issues start/restart before control of the callback thread
4701 * reaches this point.
4702 */
4703 st_session_ev_t deferred_ev = { .ev_id = ST_SES_EV_DEFERRED_STOP,
4704 .stc_ses = stc_ses};
4705 DISPATCH_EVENT(st_ses, deferred_ev, status);
4706 } else {
4707 ALOGE("%s:[%d] capture is requested but state is still detected!?",
4708 __func__, st_ses->sm_handle);
4709 }
4710 break;
Quinn Male2e883752019-03-22 11:28:54 -07004711
4712 case ST_SES_EV_SSR_OFFLINE:
Quinn Male2e883752019-03-22 11:28:54 -07004713 /* exec mode can be none if ssr occurs during a transition */
4714 if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004715 stop_session(st_ses, hw_ses, true);
4716 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07004717 break;
4718
4719 case ST_SES_EV_SEND_CHMIX_COEFF:
4720 status = hw_ses->fptrs->send_custom_chmix_coeff(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004721 ev->payload.chmix_coeff_str);
Quinn Male2e883752019-03-22 11:28:54 -07004722 break;
4723
4724 case ST_SES_EV_SET_DEVICE:
4725 if (!ev->payload.enable)
4726 status = hw_ses->fptrs->disable_device(hw_ses, true);
4727 else
4728 status = hw_ses->fptrs->enable_device(hw_ses, true);
4729
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004730 if (status && st_ses->stdev->ssr_offline_received) {
4731 STATE_TRANSITION(st_ses, ssr_state_fn);
4732 status = 0;
4733 }
Quinn Male2e883752019-03-22 11:28:54 -07004734 break;
4735
4736 case ST_SES_EV_READ_PCM:
4737 /*
4738 * buffering could have been stopped internally
4739 * and switched to active state ex: transitions.
4740 * set status to failure this will tell AHAL to
4741 * provide zero buffers to client
4742 */
4743 status = -EIO;
4744 break;
4745
4746 case ST_SES_EV_GET_PARAM_DATA:
4747 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004748 ev->payload.getparam.param, ev->payload.getparam.payload,
4749 ev->payload.getparam.payload_size,
4750 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07004751 break;
4752
4753 case ST_SES_EV_REQUEST_DET:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004754 if (!list_empty(&stc_ses->second_stage_list)) {
4755 ALOGE("%s:[%d] Event not supported with second stage enabled",
4756 __func__, st_ses->sm_handle);
4757 status = -EINVAL;
4758 break;
Quinn Male2e883752019-03-22 11:28:54 -07004759 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004760 status = hw_ses->fptrs->send_detection_request(hw_ses);
4761 if (!status)
4762 st_ses->detection_requested = true;
Quinn Male2e883752019-03-22 11:28:54 -07004763 break;
4764
4765 default:
4766 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
4767 break;
Quinn Male2e883752019-03-22 11:28:54 -07004768 };
4769
4770 return status;
4771}
4772
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004773static int detected_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07004774{
4775 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004776 st_exec_mode_t new_exec_mode = ST_EXEC_MODE_NONE;
4777 st_session_t *stc_ses = ev->stc_ses;
4778 struct listnode *node = NULL;
4779 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07004780 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
4781 st_hw_session_t *new_hw_ses = NULL;
4782
4783 /* skip parameter check as this is an internal funciton */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004784 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
4785 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07004786
4787 switch (ev->ev_id) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004788 case ST_SES_EV_LOAD_SM:
4789 /* Valid event only in multi-client usecase */
4790 /*
4791 * If a detected client deffered stop event is not handled yet,
4792 * handle here before moving out of detected state
4793 */
4794 if (st_ses->det_stc_ses && !st_ses->det_stc_ses->pending_stop) {
4795 ALOGD("%s:[%d] post deferred stop for c%d", __func__,
4796 st_ses->sm_handle, st_ses->det_stc_ses->sm_handle);
4797 status = hw_session_notifier_enqueue(
4798 st_ses->det_stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP,
4799 ST_SES_DEFERRED_STOP_DELAY_MS);
4800 if (!status)
4801 st_ses->det_stc_ses->pending_stop = true;
4802 }
4803 status = handle_load_sm(st_ses, stc_ses);
4804 break;
4805
4806 case ST_SES_EV_UNLOAD_SM:
4807 /* Valid event only in multi-client usecase */
4808 /*
4809 * If a detected client deffered stop event is not handled yet,
4810 * handle here before moving out of detected state
4811 */
4812 if (st_ses->det_stc_ses && !st_ses->det_stc_ses->pending_stop) {
4813 ALOGD("%s:[%d] post deferred stop for client c%d", __func__,
4814 st_ses->sm_handle, st_ses->det_stc_ses->sm_handle);
4815 status = hw_session_notifier_enqueue(
4816 st_ses->det_stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP,
4817 ST_SES_DEFERRED_STOP_DELAY_MS);
4818 if (!status)
4819 st_ses->det_stc_ses->pending_stop = true;
4820 }
4821 status = handle_unload_sm(st_ses, stc_ses);
4822 break;
4823
Quinn Male2e883752019-03-22 11:28:54 -07004824 case ST_SES_EV_START:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004825 /* For multi-client, other loaded client may start */
Quinn Male2e883752019-03-22 11:28:54 -07004826 STATE_TRANSITION(st_ses, active_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004827 DISPATCH_EVENT(st_ses, *ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07004828 break;
4829
4830 case ST_SES_EV_RESTART:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004831 status = restart_session(st_ses, hw_ses);
4832 if (status && !st_ses->stdev->ssr_offline_received)
4833 ALOGE("%s:[%d] failed to start session, err %d", __func__,
4834 st_ses->sm_handle, status);
4835
4836 if (st_ses->stdev->ssr_offline_received) {
4837 stop_session(st_ses, hw_ses, true);
4838 STATE_TRANSITION(st_ses, ssr_state_fn);
4839 status = 0;
4840 } else {
4841 /* Move anyways to allow client unload */
4842 STATE_TRANSITION(st_ses, active_state_fn);
4843 }
Quinn Male2e883752019-03-22 11:28:54 -07004844 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004845
Quinn Male2e883752019-03-22 11:28:54 -07004846 case ST_SES_EV_PAUSE:
Quinn Male2e883752019-03-22 11:28:54 -07004847 case ST_SES_EV_STOP:
4848 /*
4849 * It is possible that the client can issue stop after detection
4850 * callback. This even can be issued internally as part of
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004851 * deferred stop as well. For multi-client, it could be current
4852 * detected client stop or other client stop.
Quinn Male2e883752019-03-22 11:28:54 -07004853 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004854 STATE_TRANSITION(st_ses, active_state_fn);
4855 DISPATCH_EVENT(st_ses, *ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07004856 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004857
Quinn Male2e883752019-03-22 11:28:54 -07004858 case ST_SES_EV_SSR_OFFLINE:
Quinn Male2e883752019-03-22 11:28:54 -07004859 /*
4860 * Ignore return status during SSR handling
4861 * as the ADSP or CPE might be down so these
4862 * calls would fail. Exec mode can be none if
4863 * ssr occurs during a transition.
4864 */
4865 if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004866 stop_session(st_ses, hw_ses, true);
Quinn Male2e883752019-03-22 11:28:54 -07004867 STATE_TRANSITION(st_ses, ssr_state_fn);
4868 break;
4869
4870 case ST_SES_EV_SET_EXEC_MODE:
4871 new_exec_mode = ev->payload.exec_mode;
4872
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004873 if (new_exec_mode == st_ses->exec_mode) {
4874 stc_ses->exec_mode = st_ses->exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07004875 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004876 }
Quinn Male2e883752019-03-22 11:28:54 -07004877
4878 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
4879 st_ses->exec_mode = ST_EXEC_MODE_NONE;
4880 status = stop_session(st_ses, hw_ses, true);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004881 list_for_each(node, &st_ses->clients_list) {
4882 c_ses = node_to_item(node, st_session_t, hw_list_node);
4883 c_ses->exec_mode = new_exec_mode;
4884 }
Quinn Male2e883752019-03-22 11:28:54 -07004885 if (status)
4886 break;
4887 }
4888
4889 if (new_exec_mode == ST_EXEC_MODE_NONE)
4890 break;
4891
4892 /* switch to new hw session */
4893 if (ST_EXEC_MODE_CPE == new_exec_mode) {
4894 new_hw_ses = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07004895 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
4896 new_hw_ses = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07004897 } else {
4898 ALOGE("%s: unknown execution mode %d", __func__,
4899 new_exec_mode);
4900 status = -EINVAL;
4901 break;
4902 }
4903
4904 /*
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004905 * hw session changed to/from WDSP/ADSP, hence update the
4906 * related config.
4907 * Not applicable for LPI<->non-LPI transtions as hw session
4908 * doesn't change.
4909 */
4910 status = update_hw_config_on_start(stc_ses, new_hw_ses);
4911 if (status) {
4912 ALOGE("%s: Update_hw_config_on_start failed %d",
4913 __func__, status);
4914 break;
4915 }
4916 /*
Quinn Male2e883752019-03-22 11:28:54 -07004917 * start new hw session and stay in detected state as
4918 * client restart and stop concurrency scenarios are handled
4919 * in this state
4920 */
4921 status = start_session(st_ses, new_hw_ses, true);
4922 if (status)
4923 break;
4924
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004925 list_for_each(node, &st_ses->clients_list) {
4926 c_ses = node_to_item(node, st_session_t, hw_list_node);
4927 c_ses->exec_mode = new_exec_mode;
4928 if (c_ses->state == ST_STATE_ACTIVE) {
4929 dereg_hal_event_session(c_ses);
4930 reg_hal_event_session(c_ses, new_hw_ses);
4931 }
4932 }
Quinn Male2e883752019-03-22 11:28:54 -07004933 st_ses->exec_mode = new_exec_mode;
4934 st_ses->hw_ses_current = new_hw_ses;
4935 break;
4936
4937 case ST_SES_EV_SEND_CHMIX_COEFF:
4938 status = -EINVAL;
4939 break;
4940
4941 case ST_SES_EV_SET_DEVICE:
4942 /*
4943 * set device is a no-op in detected state due to the following reasons
4944 * A set device is a sequence of disable and enable device commands.
4945 * set device sequence is triggered with dev lock held. Therefore there
4946 * cannot be a concurrency with other client issued events.
4947 * As a deferred stop is posted prior to entering detected state,
4948 * one of the two events are possible
4949 * 1) timer expires and stop is issued : this implies stop_session
4950 * 2) timer is cancelled and start is issued by client: this implies
4951 * new device is set as part of start_session
4952 */
4953 break;
4954
4955 case ST_SES_EV_GET_PARAM_DATA:
4956 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004957 ev->payload.getparam.param, ev->payload.getparam.payload,
4958 ev->payload.getparam.payload_size,
4959 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07004960 break;
4961 case ST_SES_EV_DEFERRED_STOP:
4962 ALOGD("%s:[%d] post deferred stop from detected state", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004963 st_ses->sm_handle);
4964 status = hw_session_notifier_enqueue(stc_ses->sm_handle,
4965 ST_SES_EV_DEFERRED_STOP, ST_SES_DEFERRED_STOP_DELAY_MS);
Quinn Male2e883752019-03-22 11:28:54 -07004966 if (!status)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004967 stc_ses->pending_stop = true;
Quinn Male2e883752019-03-22 11:28:54 -07004968 break;
4969 case ST_SES_EV_REQUEST_DET:
4970 ALOGE("%s:[%d] Event not supported in this state",
4971 __func__, st_ses->sm_handle);
4972 status = -EINVAL;
4973 break;
4974 default:
4975 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
4976 break;
Quinn Male2e883752019-03-22 11:28:54 -07004977 };
Quinn Male2e883752019-03-22 11:28:54 -07004978 return status;
4979}
4980
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004981static int buffering_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07004982{
4983 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004984 st_session_t *stc_ses = ev->stc_ses;
4985 struct listnode *node = NULL;
4986 st_session_t *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07004987 st_hw_session_t *hw_ses = st_ses->hw_ses_current;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004988 st_exec_mode_t new_exec_mode = ST_EXEC_MODE_NONE;
Quinn Male2e883752019-03-22 11:28:54 -07004989 st_hw_session_t *new_hw_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07004990
4991 /* skip parameter check as this is an internal function */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004992 ALOGVV("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
4993 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07004994
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07004995 switch (ev->ev_id) {
4996 case ST_SES_EV_LOAD_SM:
4997 /* Valid in multi-client usecase */
4998 ALOGD("%s:[c%d-%d] load sm", __func__, stc_ses->sm_handle,
4999 st_ses->sm_handle);
5000
5001 status = handle_load_sm(st_ses, stc_ses);
5002 break;
5003
5004 case ST_SES_EV_UNLOAD_SM:
5005 ALOGD("%s:[c%d-%d] unload sm", __func__, stc_ses->sm_handle,
5006 st_ses->sm_handle);
5007
5008 status = handle_unload_sm(st_ses, stc_ses);
5009 break;
5010
5011 case ST_SES_EV_READ_PCM:
Quinn Male2e883752019-03-22 11:28:54 -07005012 /* Note: this function may block if there is no PCM data ready*/
5013 hw_ses->fptrs->read_pcm(hw_ses, ev->payload.readpcm.out_buff,
5014 ev->payload.readpcm.out_buff_size);
Quinn Male3d7d9d42019-05-20 13:35:01 -07005015 ST_DBG_FILE_WRITE(st_ses->lab_fp, ev->payload.readpcm.out_buff,
Quinn Male2e883752019-03-22 11:28:54 -07005016 ev->payload.readpcm.out_buff_size);
5017 break;
5018 case ST_SES_EV_END_BUFFERING:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005019 if (stc_ses == st_ses->det_stc_ses) {
5020 hw_ses->fptrs->stop_buffering(hw_ses);
5021 if (!stc_ses->pending_stop) {
5022 ALOGD("%s:[c%d] post deferred stop on buffering end", __func__,
5023 stc_ses->sm_handle);
5024 status = hw_session_notifier_enqueue(stc_ses->sm_handle,
5025 ST_SES_EV_DEFERRED_STOP, ST_SES_DEFERRED_STOP_DELAY_MS);
5026 if (!status)
5027 stc_ses->pending_stop = true;
5028 } else {
5029 ALOGD("%s:[c%d] skip deferred stop on buffering as already set",
5030 __func__, stc_ses->sm_handle);
5031 }
Quinn Male2e883752019-03-22 11:28:54 -07005032 }
5033 break;
Quinn Male2e883752019-03-22 11:28:54 -07005034
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005035 case ST_SES_EV_STOP:
5036 ALOGD("%s:[c%d-%d] handle event STOP", __func__, stc_ses->sm_handle,
5037 st_ses->sm_handle);
5038 if (stc_ses != st_ses->det_stc_ses) {
5039 ALOGD("%s: c%d buffering, delay c%d stop", __func__,
5040 st_ses->det_stc_ses->sm_handle, stc_ses->sm_handle);
5041 update_hw_config_on_stop(st_ses, stc_ses);
5042 break;
5043 }
5044 /* Fall through */
5045 case ST_SES_EV_PAUSE:
5046 hw_ses->fptrs->stop_buffering(hw_ses);
5047 STATE_TRANSITION(st_ses, active_state_fn);
5048 DISPATCH_EVENT(st_ses, *ev, status);
Quinn Male3d7d9d42019-05-20 13:35:01 -07005049 ST_DBG_FILE_CLOSE(st_ses->lab_fp);
Quinn Male2e883752019-03-22 11:28:54 -07005050 break;
5051
5052 case ST_SES_EV_SET_DEVICE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005053 ALOGD("%s:[c%d-%d] handle SET_DEVICE", __func__, stc_ses->sm_handle,
5054 st_ses->sm_handle);
Quinn Male2e883752019-03-22 11:28:54 -07005055 /*
5056 * Device switch will not wait for buffering to finish. It will instead
5057 * interrupt and stop the buffering and transition to the loaded state.
5058 * The loaded state will then take care of the device switch.
5059 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005060 hw_ses->fptrs->stop_buffering(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005061 status = stop_session(st_ses, hw_ses, false);
5062 if (status && !st_ses->stdev->ssr_offline_received) {
5063 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
5064 st_ses->sm_handle, status);
5065 break;
5066 }
5067 STATE_TRANSITION(st_ses, loaded_state_fn);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005068 DISPATCH_EVENT(st_ses, *ev, status);
5069 /*
5070 * The current detected client may or may not read buffer/restart
5071 * recognition. If no other clients are active, get to loaded state.
5072 * Otherwise, if any other client than the detected client is active,
5073 * we should move to active state for other client detections.
5074 */
5075 st_session_ev_t start_ev = {.ev_id = ST_SES_EV_START};
5076 if (check_and_get_other_active_client(st_ses, st_ses->det_stc_ses)) {
5077 start_ev.stc_ses = stc_ses;
5078 DISPATCH_EVENT(st_ses, start_ev, status);
5079 }
Quinn Male2e883752019-03-22 11:28:54 -07005080 break;
5081
5082 case ST_SES_EV_START:
5083 case ST_SES_EV_RESTART:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005084 ALOGD("%s:[c%d-%d] handle event START/RESTART", __func__,
5085 stc_ses->sm_handle, st_ses->sm_handle);
5086
5087 if (stc_ses != st_ses->det_stc_ses) {
5088 ALOGD("%s: c%d buffering, delay c%d start", __func__,
5089 st_ses->det_stc_ses->sm_handle, stc_ses->sm_handle);
5090 break;
5091 }
Quinn Male2e883752019-03-22 11:28:54 -07005092 /*
5093 * Client starts detection again.
5094 * This implies a previous deferred stop hasn't completed yet as
5095 * stop would have changed state to loaded.
5096 * For a restart event, issue stop buffering and restart the session
5097 * For a start event, stop buffering then stop and start the session
5098 * so that any new parameters take effect.
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005099 * For multi-client case while the detected is buffering,
5100 * the other client stop/start would have been deferred by updating
5101 * the config, and later when current detected client restarts after
5102 * buffreing is completed, check if hw config is updated due to other
5103 * client and stop->start the hw session to apply updated config.
Quinn Male2e883752019-03-22 11:28:54 -07005104 */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005105 hw_ses->fptrs->stop_buffering(hw_ses);
5106 if (hw_ses->sthw_cfg_updated || ev->ev_id == ST_SES_EV_START) {
Quinn Male2e883752019-03-22 11:28:54 -07005107 status = stop_session(st_ses, hw_ses, false);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005108 if (status) {
Quinn Male2e883752019-03-22 11:28:54 -07005109 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005110 st_ses->sm_handle, status);
5111 } else {
5112 status = start_session(st_ses, hw_ses, false);
5113 if (status) {
5114 ALOGE("%s:[%d] failed to start session, err %d", __func__,
5115 st_ses->sm_handle, status);
5116 }
Quinn Male2e883752019-03-22 11:28:54 -07005117 }
Quinn Male2e883752019-03-22 11:28:54 -07005118 } else {
5119 status = restart_session(st_ses, hw_ses);
5120 }
5121
5122 if (status) {
5123 if (st_ses->stdev->ssr_offline_received) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005124 hw_ses->fptrs->dereg_sm(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005125 STATE_TRANSITION(st_ses, ssr_state_fn);
Quinn Male2e883752019-03-22 11:28:54 -07005126 status = 0;
5127 } else {
Quinn Male2e883752019-03-22 11:28:54 -07005128 /* move to active anyways to allow unload sm */
5129 STATE_TRANSITION(st_ses, active_state_fn);
5130 }
5131 } else {
Quinn Male2e883752019-03-22 11:28:54 -07005132 STATE_TRANSITION(st_ses, active_state_fn);
5133 }
5134 break;
5135
5136 case ST_SES_EV_SSR_OFFLINE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005137 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5138 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005139 /*
5140 * Ignore return status during SSR handling
5141 * as the ADSP or CPE might be down so these
5142 * calls would fail. Exec mode can be none if
5143 * ssr occurs during a transition.
5144 */
5145 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005146 hw_ses->fptrs->stop_buffering(hw_ses);
5147 stop_session(st_ses, hw_ses, true);
Quinn Male2e883752019-03-22 11:28:54 -07005148 }
5149 STATE_TRANSITION(st_ses, ssr_state_fn);
5150 break;
5151
5152 case ST_SES_EV_SET_EXEC_MODE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005153 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5154 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005155
5156 new_exec_mode = ev->payload.exec_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005157 if (new_exec_mode == st_ses->exec_mode) {
5158 stc_ses->exec_mode = st_ses->exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07005159 break;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005160 }
Quinn Male2e883752019-03-22 11:28:54 -07005161
5162 if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
5163 st_ses->exec_mode = ST_EXEC_MODE_NONE;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005164 status = hw_ses->fptrs->stop_buffering(hw_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005165 if (status) {
5166 ALOGE("%s:[%d] failed to stop_buffering err %d", __func__,
5167 st_ses->sm_handle, status);
5168 break;
5169 }
Quinn Male2e883752019-03-22 11:28:54 -07005170 status = stop_session(st_ses, hw_ses, true);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005171 list_for_each(node, &st_ses->clients_list) {
5172 c_ses = node_to_item(node, st_session_t, hw_list_node);
5173 c_ses->exec_mode = new_exec_mode;
5174 }
Quinn Male2e883752019-03-22 11:28:54 -07005175 if (status) {
5176 ALOGE("%s:[%d] failed to stop session, err %d", __func__,
5177 st_ses->sm_handle, status);
5178 break;
5179 }
5180 }
5181
5182 if (new_exec_mode == ST_EXEC_MODE_NONE)
5183 break;
5184
5185 /* switch to new hw session */
5186 if (ST_EXEC_MODE_CPE == new_exec_mode) {
5187 new_hw_ses = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07005188 } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
5189 new_hw_ses = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07005190 } else {
5191 ALOGE("%s: unknown execution mode %d", __func__,
5192 new_exec_mode);
5193 status = -EINVAL;
5194 break;
5195 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005196 /*
5197 * hw session changed to/from WDSP/ADSP, hence update the
5198 * related config.
5199 * Not applicable for LPI<->non-LPI transtions as hw session
5200 * doesn't change.
5201 */
5202 status = update_hw_config_on_start(stc_ses, new_hw_ses);
5203 if (status) {
5204 ALOGE("%s: Update_hw_config_on_start failed %d",
5205 __func__, status);
5206 break;
5207 }
Quinn Male2e883752019-03-22 11:28:54 -07005208 status = start_session(st_ses, new_hw_ses, true);
5209 if (status) {
5210 ALOGE("%s:[%d] failed to start hw ses, err %d", __func__,
5211 st_ses->sm_handle, status);
5212 break;
5213 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005214 list_for_each(node, &st_ses->clients_list) {
5215 c_ses = node_to_item(node, st_session_t, hw_list_node);
5216 c_ses->exec_mode = new_exec_mode;
5217 if (c_ses->state == ST_STATE_ACTIVE) {
5218 dereg_hal_event_session(c_ses);
5219 reg_hal_event_session(c_ses, new_hw_ses);
5220 }
5221 }
Quinn Male2e883752019-03-22 11:28:54 -07005222 st_ses->exec_mode = new_exec_mode;
5223 st_ses->hw_ses_current = new_hw_ses;
5224 STATE_TRANSITION(st_ses, active_state_fn);
5225 break;
5226
5227 case ST_SES_EV_SEND_CHMIX_COEFF:
5228 status = hw_ses->fptrs->send_custom_chmix_coeff(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005229 ev->payload.chmix_coeff_str);
Quinn Male2e883752019-03-22 11:28:54 -07005230 break;
5231
5232 case ST_SES_EV_GET_PARAM_DATA:
5233 status = hw_ses->fptrs->get_param_data(hw_ses,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005234 ev->payload.getparam.param, ev->payload.getparam.payload,
5235 ev->payload.getparam.payload_size,
5236 ev->payload.getparam.param_data_size);
Quinn Male2e883752019-03-22 11:28:54 -07005237 break;
5238
5239 case ST_SES_EV_REQUEST_DET:
5240 ALOGE("%s:[%d] Event %d not supported in this state",
5241 __func__, st_ses->sm_handle, ev->ev_id);
5242 status = -EINVAL;
5243 break;
5244
5245 default:
5246 ALOGD("%s:[%d] unhandled event, id %d", __func__, st_ses->sm_handle,
5247 ev->ev_id);
5248 break;
Quinn Male2e883752019-03-22 11:28:54 -07005249 };
5250
5251 return status;
5252}
5253
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005254static int ssr_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
Quinn Male2e883752019-03-22 11:28:54 -07005255{
5256 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005257 st_session_t *stc_ses = ev->stc_ses;
5258 st_session_ev_t load_ev = {.ev_id = ST_SES_EV_LOAD_SM};
5259 st_session_ev_t start_ev = {.ev_id = ST_SES_EV_START};
5260 st_session_ev_t exec_mode_ev = {.ev_id = ST_SES_EV_SET_EXEC_MODE};
5261 bool active = false;
Quinn Male2e883752019-03-22 11:28:54 -07005262
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005263 /* skip parameter check as this is an internal function */
5264 ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
5265 st_ses->sm_handle, ev->ev_id);
Quinn Male2e883752019-03-22 11:28:54 -07005266
5267 switch (ev->ev_id) {
5268 case ST_SES_EV_SSR_ONLINE:
5269 ALOGV("%s:[%d] SSR ONLINE received", __func__, st_ses->sm_handle);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005270 /*
5271 * Load and start all clients at once instead of unload/loading
5272 * due to each subsequent client dispatch. It is expected the
5273 * upper layer calls SSR_ONLINE for all clients.
5274 */
5275 stc_ses->pending_load = true;
5276 if (is_any_client_not_pending_load(st_ses))
5277 break;
5278
5279 reset_clients_pending_load(st_ses);
Quinn Male2e883752019-03-22 11:28:54 -07005280
5281 STATE_TRANSITION(st_ses, idle_state_fn);
5282
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005283 if ((stc_ses->ssr_transit_exec_mode == ST_EXEC_MODE_CPE) ||
5284 (stc_ses->ssr_transit_exec_mode == ST_EXEC_MODE_ADSP)) {
5285 exec_mode_ev.stc_ses = stc_ses;
5286 exec_mode_ev.payload.exec_mode = stc_ses->ssr_transit_exec_mode;
Quinn Male2e883752019-03-22 11:28:54 -07005287 DISPATCH_EVENT(st_ses, exec_mode_ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005288 if (status)
5289 break;
5290 stc_ses->ssr_transit_exec_mode = ST_EXEC_MODE_NONE;
Quinn Male2e883752019-03-22 11:28:54 -07005291 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005292 active = is_any_client_in_state(st_ses, ST_STATE_ACTIVE);
5293 if (active || is_any_client_in_state(st_ses, ST_STATE_LOADED)) {
5294 load_ev.stc_ses = stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005295 DISPATCH_EVENT(st_ses, load_ev, status);
5296 if (status)
5297 break;
5298 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005299 if (active) {
5300 start_ev.stc_ses = stc_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005301 DISPATCH_EVENT(st_ses, start_ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07005302 }
5303
5304 break;
5305
5306 case ST_SES_EV_LOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005307 if (ST_STATE_IDLE == stc_ses->state) {
5308 status = update_sound_model(stc_ses, true);
5309 if (status) {
5310 ALOGE("%s:[c%d] update sound model add failed %d", __func__,
5311 stc_ses->sm_handle, status);
5312 status = -EINVAL;
5313 break;
5314 }
5315 prepapre_second_stage_for_client(stc_ses);
5316 stc_ses->state = ST_STATE_LOADED;
Quinn Male2e883752019-03-22 11:28:54 -07005317 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005318 ALOGE("%s: received unexpected event, client state = %d",
5319 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07005320 }
5321 break;
5322
5323 case ST_SES_EV_UNLOAD_SM:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005324 if (ST_STATE_LOADED == stc_ses->state) {
5325 status = update_sound_model(stc_ses, false);
5326 if (status)
5327 ALOGE("%s:[c%d] update sound_model failed %d", __func__,
5328 stc_ses->sm_handle, status);
5329 stop_second_stage_for_client(stc_ses);
5330 stc_ses->state = ST_STATE_IDLE;
Quinn Male2e883752019-03-22 11:28:54 -07005331 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005332 ALOGE("%s: received unexpected event, client state = %d",
5333 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07005334 }
5335 break;
5336
5337 case ST_SES_EV_START:
5338 case ST_SES_EV_RESTART:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005339 if (ST_STATE_LOADED == stc_ses->state) {
5340 if (ev->ev_id == ST_SES_EV_RESTART)
5341 update_hw_config_on_restart(st_ses, stc_ses);
5342 stc_ses->state = ST_STATE_ACTIVE;
Quinn Male2e883752019-03-22 11:28:54 -07005343 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005344 ALOGE("%s: received unexpected event, client state = %d",
5345 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07005346 }
5347 break;
5348
5349 case ST_SES_EV_STOP:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005350 if (ST_STATE_ACTIVE == stc_ses->state) {
5351 update_hw_config_on_stop(st_ses, stc_ses);
5352 stc_ses->state = ST_STATE_LOADED;
Quinn Male2e883752019-03-22 11:28:54 -07005353 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005354 ALOGE("%s: received unexpected event, client state = %d",
5355 __func__, stc_ses->state);
Quinn Male2e883752019-03-22 11:28:54 -07005356 }
5357 break;
5358
5359 case ST_SES_EV_PAUSE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005360 stc_ses->paused = true;
Quinn Male2e883752019-03-22 11:28:54 -07005361 break;
5362
5363 case ST_SES_EV_RESUME:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005364 stc_ses->paused = false;
Quinn Male2e883752019-03-22 11:28:54 -07005365 break;
5366
5367 case ST_SES_EV_READ_PCM:
5368 status = -EIO;
5369 break;
5370
5371 case ST_SES_EV_SEND_CHMIX_COEFF:
5372 status = -EIO;
5373 break;
5374
5375 case ST_SES_EV_GET_PARAM_DATA:
5376 status = -EIO;
5377 break;
5378
5379 case ST_SES_EV_SET_EXEC_MODE:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005380 stc_ses->exec_mode = ev->payload.exec_mode;
5381 if (ev->payload.exec_mode == st_ses->exec_mode)
5382 break;
5383
Quinn Male2e883752019-03-22 11:28:54 -07005384 st_ses->exec_mode = ev->payload.exec_mode;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005385
Quinn Male2e883752019-03-22 11:28:54 -07005386 if (ST_EXEC_MODE_CPE == st_ses->exec_mode)
5387 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
5388 else if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
5389 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
5390 /* remain in current state */
5391 break;
5392
5393 case ST_SES_EV_REQUEST_DET:
5394 ALOGE("%s:[%d] Event not supported in this state",
5395 __func__, st_ses->sm_handle);
5396 status = -EINVAL;
5397 break;
5398
5399 default:
5400 ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
5401 break;
5402 };
5403
5404 return status;
5405}
5406
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005407int st_session_load_sm(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005408{
5409 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005410
5411 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005412 return -EINVAL;
5413
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005414 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5415 st_session_loadsm_payload_t payload = { .phrase_sm = stc_ses->phrase_sm };
Quinn Male2e883752019-03-22 11:28:54 -07005416 st_session_ev_t ev = { .ev_id = ST_SES_EV_LOAD_SM,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005417 .payload.loadsm = payload, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005418
5419 pthread_mutex_lock(&st_ses->lock);
5420 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005421 if (!status) {
5422 prepapre_second_stage_for_client(stc_ses);
5423 stc_ses->state = ST_STATE_LOADED;
5424 }
Quinn Male2e883752019-03-22 11:28:54 -07005425 pthread_mutex_unlock(&st_ses->lock);
5426
5427 return status;
5428}
5429
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005430int st_session_unload_sm(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005431{
5432 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005433
5434 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005435 return -EINVAL;
5436
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005437 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5438 st_session_ev_t ev = { .ev_id = ST_SES_EV_UNLOAD_SM, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005439
5440 pthread_mutex_lock(&st_ses->lock);
5441 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005442 stop_second_stage_for_client(stc_ses);
5443 stc_ses->state = ST_STATE_IDLE;
Quinn Male2e883752019-03-22 11:28:54 -07005444 pthread_mutex_unlock(&st_ses->lock);
5445
5446 return status;
5447}
5448
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005449int st_session_start(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005450{
5451 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005452
5453 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005454 return -EINVAL;
5455
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005456 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5457 st_session_ev_t ev = { .ev_id = ST_SES_EV_START, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005458
Quinn Male2e883752019-03-22 11:28:54 -07005459 pthread_mutex_lock(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005460 if (stc_ses->pending_stop) {
5461 ALOGV("%s:[c%d] cancel ST_SES_EV_DEFERRED_STOP", __func__,
5462 stc_ses->sm_handle);
5463 hw_session_notifier_cancel(stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP);
5464 stc_ses->pending_stop = false;
5465 }
5466
Quinn Male2e883752019-03-22 11:28:54 -07005467 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005468 if (!status) {
5469 reg_hal_event_session(stc_ses, st_ses->hw_ses_current);
5470 start_second_stage_for_client(stc_ses);
5471 stc_ses->state = ST_STATE_ACTIVE;
5472 }
Quinn Male2e883752019-03-22 11:28:54 -07005473 pthread_mutex_unlock(&st_ses->lock);
5474 return status;
5475}
5476
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005477int st_session_stop(st_session_t *stc_ses)
5478{
5479 int status = 0;
5480
5481 if (!stc_ses || !stc_ses->hw_proxy_ses)
5482 return -EINVAL;
5483
5484 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5485 st_session_ev_t ev = { .ev_id = ST_SES_EV_STOP, .stc_ses = stc_ses };
5486
5487 pthread_mutex_lock(&st_ses->lock);
5488 DISPATCH_EVENT(st_ses, ev, status);
5489 dereg_hal_event_session(stc_ses);
5490 stc_ses->pending_stop = false;
5491 stc_ses->state = ST_STATE_LOADED;
5492 pthread_mutex_unlock(&st_ses->lock);
5493
5494 return status;
5495}
5496
5497int st_session_restart(st_session_t *stc_ses)
5498{
5499 int status = 0;
5500
5501 if (!stc_ses || !stc_ses->hw_proxy_ses)
5502 return -EINVAL;
5503
5504 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5505 st_session_ev_t ev = { .ev_id = ST_SES_EV_RESTART, .stc_ses = stc_ses };
5506
5507 pthread_mutex_lock(&st_ses->lock);
5508 if (stc_ses->pending_stop) {
5509 ALOGV("%s:[c%d] cancel ST_SES_EV_DEFERRED_STOP", __func__,
5510 stc_ses->sm_handle);
5511 hw_session_notifier_cancel(stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP);
5512 stc_ses->pending_stop = false;
5513 }
5514
5515 DISPATCH_EVENT(st_ses, ev, status);
5516 if (!status) {
5517 start_second_stage_for_client(stc_ses);
5518 stc_ses->state = ST_STATE_ACTIVE;
5519 } else {
5520 dereg_hal_event_session(stc_ses);
5521 stc_ses->state = ST_STATE_LOADED;
5522 }
5523 pthread_mutex_unlock(&st_ses->lock);
5524
5525 return status;
5526}
5527
5528int st_session_ssr_offline(st_session_t *stc_ses,
Quinn Male2e883752019-03-22 11:28:54 -07005529 enum ssr_event_status ssr_type)
5530{
5531 int status = 0;
5532
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005533 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005534 return -EINVAL;
5535
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005536 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005537 st_session_ev_t ev = { .ev_id = ST_SES_EV_SSR_OFFLINE,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005538 .payload.ssr = ssr_type, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005539
5540 pthread_mutex_lock(&st_ses->lock);
5541 /*
5542 * In typical usecases, handle SSR only if it occured on the core we are
5543 * currently using. In cases that have an SSR event during transitions,
5544 * the exec_mode can be NONE. For these cases, handle SSR on the core
5545 * which was in use prior to the transition. For example, if the
5546 * ssr_transit_exec_mode is ADSP, then the core prior to the transition
5547 * is CPE, so we handle the CPE SSR event.
5548 *
5549 * On 8909w BG uses CPE mode for detection. So add BG specific
5550 * conditon check to handle SSR event.
5551 */
5552 if (((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
5553 (CPE_STATUS_OFFLINE == ssr_type)) ||
5554 ((ST_EXEC_MODE_ADSP == st_ses->exec_mode) &&
5555 (SND_CARD_STATUS_OFFLINE == ssr_type)) ||
5556 ((ST_EXEC_MODE_NONE == st_ses->exec_mode) &&
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005557 (((ST_EXEC_MODE_CPE == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07005558 (SND_CARD_STATUS_OFFLINE == ssr_type)) ||
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005559 ((ST_EXEC_MODE_ADSP == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07005560 (CPE_STATUS_OFFLINE == ssr_type)))) ||
5561 ((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
5562 (SND_CARD_STATUS_OFFLINE == ssr_type) &&
5563 (st_ses->stdev->bg_kwd)))
5564 DISPATCH_EVENT(st_ses, ev, status);
5565 pthread_mutex_unlock(&st_ses->lock);
5566
5567 return status;
5568}
5569
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005570int st_session_ssr_online(st_session_t *stc_ses,
Quinn Male2e883752019-03-22 11:28:54 -07005571 enum ssr_event_status ssr_type)
5572{
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;
Quinn Male2e883752019-03-22 11:28:54 -07005579 st_session_ev_t ev = { .ev_id = ST_SES_EV_SSR_ONLINE,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005580 .payload.ssr = ssr_type, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005581
5582 pthread_mutex_lock(&st_ses->lock);
5583 /*
5584 * In typical usecases, handle SSR only if it occured on the core we are
5585 * currently using. In cases that have an SSR event during transitions,
5586 * the exec_mode can be NONE. For these cases, handle SSR on the core
5587 * which was in use prior to the transition. For example, if the
5588 * ssr_transit_exec_mode is ADSP, then the core prior to the transition
5589 * is CPE, so we handle the CPE SSR event.
5590 *
5591 * On 8909w BG uses CPE mode for detection. So add BG specific
5592 * conditon check to handle SSR event.
5593 */
5594 if (((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
5595 (CPE_STATUS_ONLINE == ssr_type)) ||
5596 ((ST_EXEC_MODE_ADSP == st_ses->exec_mode) &&
5597 (SND_CARD_STATUS_ONLINE == ssr_type)) ||
5598 ((ST_EXEC_MODE_NONE == st_ses->exec_mode) &&
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005599 (((ST_EXEC_MODE_CPE == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07005600 (SND_CARD_STATUS_ONLINE == ssr_type)) ||
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005601 ((ST_EXEC_MODE_ADSP == stc_ses->ssr_transit_exec_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -07005602 (CPE_STATUS_ONLINE == ssr_type)))) ||
5603 ((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
5604 (SND_CARD_STATUS_ONLINE == ssr_type) &&
5605 (st_ses->stdev->bg_kwd)))
5606 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005607
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_pause(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;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005619
5620 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5621 st_session_ev_t ev = { .ev_id = ST_SES_EV_PAUSE, .stc_ses = stc_ses };
5622
5623 pthread_mutex_lock(&stc_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07005624 DISPATCH_EVENT(st_ses, ev, status);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005625 pthread_mutex_unlock(&stc_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07005626 return status;
5627}
5628
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005629int st_session_resume(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005630{
5631 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005632
5633 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005634 return -EINVAL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005635
5636 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5637 st_session_ev_t ev = { .ev_id = ST_SES_EV_RESUME, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005638
5639 pthread_mutex_lock(&st_ses->lock);
5640 DISPATCH_EVENT(st_ses, ev, status);
5641 pthread_mutex_unlock(&st_ses->lock);
5642 return status;
5643}
5644
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005645int st_session_disable_device(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005646{
5647 int status = 0;
5648
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005649 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005650 return -EINVAL;
5651
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005652 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5653 st_session_ev_t ev = {.ev_id = ST_SES_EV_SET_DEVICE,
5654 .payload.enable = false, .stc_ses = stc_ses};
5655
5656 pthread_mutex_lock(&st_ses->lock);
5657 /*
5658 * Avoid dispatching for each attached multi-client, instead
5659 * defer it until last client
5660 */
5661 stc_ses->pending_set_device = true;
5662 if (is_any_client_not_pending_set_device(st_ses)) {
5663 pthread_mutex_unlock(&st_ses->lock);
5664 return status;
5665 }
5666 reset_clients_pending_set_device(st_ses);
5667
5668 DISPATCH_EVENT(st_ses, ev, status);
5669 pthread_mutex_unlock(&st_ses->lock);
5670 return status;
5671}
5672
5673int st_session_enable_device(st_session_t *stc_ses)
5674{
5675 int status = 0;
5676
5677 if (!stc_ses || !stc_ses->hw_proxy_ses)
5678 return -EINVAL;
5679
5680 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005681 st_session_ev_t ev = { .ev_id = ST_SES_EV_SET_DEVICE,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005682 .payload.enable = true, .stc_ses = stc_ses };
Quinn Male2e883752019-03-22 11:28:54 -07005683
5684 pthread_mutex_lock(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005685 /*
5686 * Avoid dispatching for each attached multi-client, instead
5687 * defer it until last client
5688 */
5689 stc_ses->pending_set_device = true;
5690 if (is_any_client_not_pending_set_device(st_ses)) {
5691 pthread_mutex_unlock(&st_ses->lock);
5692 return status;
5693 }
5694 reset_clients_pending_set_device(st_ses);
5695
Quinn Male2e883752019-03-22 11:28:54 -07005696 DISPATCH_EVENT(st_ses, ev, status);
5697 pthread_mutex_unlock(&st_ses->lock);
5698 return status;
5699}
5700
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005701bool st_session_is_detected(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005702{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005703 bool ret = false;
Quinn Male2e883752019-03-22 11:28:54 -07005704
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005705 if (!stc_ses || !stc_ses->hw_proxy_ses)
5706 return ret;
Quinn Male2e883752019-03-22 11:28:54 -07005707
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005708 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005709
5710 pthread_mutex_lock(&st_ses->lock);
5711 ret = (st_ses->current_state == detected_state_fn) ? true : false;
5712 pthread_mutex_unlock(&st_ses->lock);
5713
5714 return ret;
5715}
5716
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005717bool st_session_is_active(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005718{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005719 bool ret = false;
5720
5721 if (!stc_ses || !stc_ses->hw_proxy_ses)
5722 return ret;
5723
5724 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005725
5726 pthread_mutex_lock(&st_ses->lock);
5727 ret = (st_ses->current_state == active_state_fn) ? true : false;
5728 pthread_mutex_unlock(&st_ses->lock);
5729
5730 return ret;
5731}
5732
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005733bool st_session_is_buffering(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005734{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005735 bool ret = false;
5736
5737 if (!stc_ses || !stc_ses->hw_proxy_ses)
5738 return ret;
5739
5740 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005741
5742 pthread_mutex_lock(&st_ses->lock);
5743 ret = (st_ses->current_state == buffering_state_fn) ? true : false;
5744 pthread_mutex_unlock(&st_ses->lock);
5745
5746 return ret;
5747}
5748
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005749bool st_session_is_ssr_state(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005750{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005751 bool ret = false;
5752
5753 if (!stc_ses || !stc_ses->hw_proxy_ses)
5754 return ret;
5755
5756 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005757
5758 pthread_mutex_lock(&st_ses->lock);
5759 ret = (st_ses->current_state == ssr_state_fn) ? true : false;
5760 pthread_mutex_unlock(&st_ses->lock);
5761
5762 return ret;
5763}
5764
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005765int st_session_read_pcm(st_session_t *stc_ses, uint8_t *buff,
Quinn Male2e883752019-03-22 11:28:54 -07005766 size_t buff_size, size_t *read_size)
5767{
5768 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005769
5770 if (!stc_ses || !stc_ses->hw_proxy_ses || !buff || buff_size == 0 ||
5771 read_size == 0)
Quinn Male2e883752019-03-22 11:28:54 -07005772 return -EINVAL;
5773
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005774 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5775 st_session_readpcm_payload_t payload = {.out_buff = buff,
5776 .out_buff_size = buff_size, .actual_read_size = read_size};
Quinn Male2e883752019-03-22 11:28:54 -07005777
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005778 st_session_ev_t ev = {.ev_id = ST_SES_EV_READ_PCM,
5779 .payload.readpcm = payload, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07005780
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005781 /*
5782 * Do not lock when handling this event, this event
5783 * can go in parallel with other events as multiple
5784 * sessions can buffer in parallel.
5785 */
Quinn Male2e883752019-03-22 11:28:54 -07005786 DISPATCH_EVENT(st_ses, ev, status);
5787 return status;
5788}
5789
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005790int st_session_stop_lab(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005791{
5792 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005793
5794 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005795 return -EINVAL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005796
5797 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5798 st_session_ev_t ev = {.ev_id = ST_SES_EV_END_BUFFERING, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07005799
5800 pthread_mutex_lock(&st_ses->lock);
5801 DISPATCH_EVENT(st_ses, ev, status);
5802 pthread_mutex_unlock(&st_ses->lock);
5803 return status;
5804}
5805
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005806int st_session_set_exec_mode(st_session_t *stc_ses, st_exec_mode_t exec)
Quinn Male2e883752019-03-22 11:28:54 -07005807{
5808 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005809
5810 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005811 return -EINVAL;
5812
5813 ALOGV("%s: exec mode %d", __func__, exec);
5814
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005815 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5816 st_session_ev_t ev = {.ev_id = ST_SES_EV_SET_EXEC_MODE,
5817 .payload.exec_mode = exec, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07005818
5819 pthread_mutex_lock(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005820 if (st_ses->enable_trans)
5821 DISPATCH_EVENT(st_ses, ev, status);
Quinn Male2e883752019-03-22 11:28:54 -07005822 pthread_mutex_unlock(&st_ses->lock);
5823 return status;
5824}
5825
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005826int st_session_update_recongition_config(st_session_t *stc_ses)
5827{
5828
5829 int status = 0;
5830
5831 if (!stc_ses || !stc_ses->hw_proxy_ses)
5832 return -EINVAL;
5833
5834 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5835
5836 pthread_mutex_lock(&st_ses->lock);
5837 status = update_hw_config_on_start(stc_ses, st_ses->hw_ses_current);
5838 pthread_mutex_unlock(&st_ses->lock);
5839 return status;
5840
5841}
5842
5843int st_session_get_preroll(st_session_t *stc_ses)
5844{
5845 int val = 0;
5846
5847 if (!stc_ses || !stc_ses->hw_proxy_ses)
5848 return 0;
5849
5850 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5851
5852 pthread_mutex_lock(&st_ses->lock);
5853 val = st_ses->hw_ses_current->sthw_cfg.client_req_preroll;
5854 pthread_mutex_unlock(&st_ses->lock);
5855
5856 return val;
5857}
5858
5859int st_session_send_custom_chmix_coeff(st_session_t *stc_ses, char *str)
Quinn Male2e883752019-03-22 11:28:54 -07005860{
5861 int status = 0;
5862
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005863 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005864 return -EINVAL;
5865
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005866 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005867 st_session_ev_t ev = { .ev_id = ST_SES_EV_SEND_CHMIX_COEFF,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005868 .payload.chmix_coeff_str = str, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07005869
5870 pthread_mutex_lock(&st_ses->lock);
5871 if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
5872 DISPATCH_EVENT(st_ses, ev, status);
5873 pthread_mutex_unlock(&st_ses->lock);
5874 return status;
5875}
5876
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005877int st_session_get_config(st_session_t *stc_ses, struct pcm_config *config)
Quinn Male2e883752019-03-22 11:28:54 -07005878{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005879 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005880 return -EINVAL;
5881
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005882 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
5883
5884 pthread_mutex_lock(&st_ses->lock);
5885 memcpy(config, &st_ses->hw_ses_current->config, sizeof(struct pcm_config));
5886 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07005887
5888 return 0;
5889}
5890
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005891int st_session_get_param_data(st_session_t *stc_ses, const char *param,
5892 void *payload, size_t payload_size, size_t *param_data_size)
Quinn Male2e883752019-03-22 11:28:54 -07005893{
5894 int status = 0;
5895
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005896 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005897 return -EINVAL;
5898
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005899 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005900 st_session_getparam_payload_t getparam_payload = { .param = param,
5901 .payload = payload,
5902 .payload_size = payload_size,
5903 .param_data_size = param_data_size};
5904 st_session_ev_t ev = { .ev_id = ST_SES_EV_GET_PARAM_DATA,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005905 .payload.getparam = getparam_payload, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07005906
5907 pthread_mutex_lock(&st_ses->lock);
5908 /* Currently get param data supported for ARM & ADSP mode */
5909 if ((ST_EXEC_MODE_ARM == st_ses->exec_mode) ||
5910 (ST_EXEC_MODE_ADSP == st_ses->exec_mode))
5911 DISPATCH_EVENT(st_ses, ev, status);
5912 pthread_mutex_unlock(&st_ses->lock);
5913
5914 return status;
5915}
5916
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005917int st_session_ss_init(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005918{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005919 int status = 0;
5920 struct listnode *node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07005921 st_arm_second_stage_t *st_sec_stage = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005922 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005923
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005924 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07005925 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
5926 status = st_second_stage_module_init(st_sec_stage,
5927 (void *)st_sec_stage->ss_info->lib_name);
5928 if (status) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005929 ALOGE("%s:[c%d] initializing second stage session failed %d",
5930 __func__, stc_ses->sm_handle, status);
Quinn Male2e883752019-03-22 11:28:54 -07005931 goto ss_cleanup;
5932 }
5933 }
5934
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005935 pthread_mutex_lock(&st_ses->lock);
5936 if (st_ses->aggregator_thread_created) {
5937 pthread_mutex_unlock(&st_ses->lock);
5938 return 0;
5939 }
5940 /*
5941 * Aggregator is not maintatined per client as there is only one
5942 * client keyword detection happens at a time in multi-client scenario.
5943 * Instead use single aggregator thread at proxy level, processing the
5944 * second stage for detected client at run time.
5945 */
5946 init_det_event_aggregator(st_ses);
5947
Quinn Male2e883752019-03-22 11:28:54 -07005948 st_ses->det_session_ev = calloc(1, sizeof(st_session_ev_t));
5949 if (!st_ses->det_session_ev) {
5950 ALOGE("%s: Failed to allocate st_session_ev_t, exiting", __func__);
5951 status = -ENOMEM;
5952 goto ss_cleanup;
5953 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005954 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07005955 return 0;
5956
5957ss_cleanup:
5958 destroy_det_event_aggregator(st_ses);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005959 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07005960 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
5961 st_second_stage_module_deinit(st_sec_stage);
5962 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005963 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07005964 return status;
5965}
5966
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005967int st_session_ss_deinit(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07005968{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005969 struct listnode *node = NULL;
5970 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
Quinn Male2e883752019-03-22 11:28:54 -07005971 st_arm_second_stage_t *st_sec_stage = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005972 st_session_t *c_ses = NULL;
5973 bool aggregator_needed = false;
Quinn Male2e883752019-03-22 11:28:54 -07005974
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005975 list_for_each(node, &stc_ses->second_stage_list) {
Quinn Male2e883752019-03-22 11:28:54 -07005976 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
5977 st_second_stage_module_deinit(st_sec_stage);
5978 }
5979
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07005980 pthread_mutex_lock(&st_ses->lock);
5981 if (!st_ses->aggregator_thread_created) {
5982 pthread_mutex_unlock(&st_ses->lock);
5983 return 0;
5984 }
5985 /* If other client has second stage enabled, keep the aggregator */
5986 list_for_each(node, &st_ses->clients_list) {
5987 c_ses = node_to_item(node, st_session_t, hw_list_node);
5988 if (c_ses != stc_ses && !list_empty(&c_ses->second_stage_list)) {
5989 aggregator_needed = true;
5990 break;
5991 }
5992 }
5993 if (aggregator_needed) {
5994 pthread_mutex_unlock(&st_ses->lock);
5995 return 0;
5996 }
5997
5998 destroy_det_event_aggregator(st_ses);
5999
Quinn Male2e883752019-03-22 11:28:54 -07006000 if (st_ses->det_session_ev)
6001 free(st_ses->det_session_ev);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006002 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006003
6004 return 0;
6005}
6006
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006007int st_session_request_detection(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006008{
6009 int status = 0;
6010
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006011 if (!stc_ses || !stc_ses->hw_proxy_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006012 return -EINVAL;
6013
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006014 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6015 st_session_ev_t ev = {.ev_id = ST_SES_EV_REQUEST_DET, .stc_ses = stc_ses};
Quinn Male2e883752019-03-22 11:28:54 -07006016
6017 /* lock to serialize event handling */
6018 pthread_mutex_lock(&st_ses->lock);
6019 DISPATCH_EVENT(st_ses, ev, status);
6020 pthread_mutex_unlock(&st_ses->lock);
6021 return status;
6022}
6023
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006024int st_session_init(st_session_t *stc_ses, struct sound_trigger_device *stdev,
Quinn Male2e883752019-03-22 11:28:54 -07006025 st_exec_mode_t exec_mode, sound_model_handle_t sm_handle)
6026{
6027 int status = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006028 struct st_vendor_info *v_info = NULL;
6029 st_proxy_session_t *st_ses = NULL;
6030 struct listnode *node = NULL;
6031 struct st_session *c_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07006032 pthread_mutexattr_t attr;
6033
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006034 if (!stc_ses || !stdev)
6035 return -EINVAL;
Quinn Male2e883752019-03-22 11:28:54 -07006036
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006037 st_ses = calloc(1, sizeof(st_proxy_session_t));
6038 if (!st_ses) {
6039 ALOGE("%s: hw_proxy_ses allocation failed", __func__);
6040 return -ENOMEM;
6041 }
6042 st_ses->stdev = stc_ses->stdev = stdev;
6043 v_info = stc_ses->vendor_uuid_info;
Quinn Male2e883752019-03-22 11:28:54 -07006044
6045 if (v_info && (EXEC_MODE_CFG_DYNAMIC == v_info->exec_mode_cfg)) {
6046 st_ses->enable_trans = true;
Quinn Male2e883752019-03-22 11:28:54 -07006047 if (stdev->is_gcs) {
6048 /* alloc and init cpe session*/
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006049 st_ses->hw_ses_cpe =
6050 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
Quinn Male2e883752019-03-22 11:28:54 -07006051 if (!st_ses->hw_ses_cpe) {
6052 status = -ENOMEM;
6053 goto cleanup;
6054 }
6055 status = st_hw_sess_gcs_init(st_ses->hw_ses_cpe, hw_sess_cb,
6056 (void *)st_ses, ST_EXEC_MODE_CPE, v_info, sm_handle, stdev);
6057 if (status) {
6058 ALOGE("%s: initializing gcs hw session failed %d", __func__,
6059 status);
6060 goto cleanup;
6061 }
6062
6063 /* alloc and init adsp session*/
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006064 st_ses->hw_ses_adsp =
6065 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
Quinn Male2e883752019-03-22 11:28:54 -07006066 if (!st_ses->hw_ses_adsp) {
6067 st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
6068 status = -ENOMEM;
6069 goto cleanup;
6070 }
6071
6072 status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
6073 (void *)st_ses, ST_EXEC_MODE_ADSP, v_info, sm_handle, stdev);
6074 if (status) {
6075 ALOGE("%s: initializing lsm session failed", __func__);
6076 st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
6077 goto cleanup;
6078 }
6079
6080 } else {
6081 /* alloc and init cpe session*/
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006082 st_ses->hw_ses_cpe =
6083 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
Quinn Male2e883752019-03-22 11:28:54 -07006084 if (!st_ses->hw_ses_cpe) {
6085 status = -ENOMEM;
6086 goto cleanup;
6087 }
6088 status = st_hw_sess_lsm_init(st_ses->hw_ses_cpe, hw_sess_cb,
6089 (void *)st_ses, ST_EXEC_MODE_CPE, v_info, sm_handle, stdev);
6090 if (status) {
6091 ALOGE("%s: initialzing lsm hw session failed %d", __func__,
6092 status);
6093 goto cleanup;
6094 }
6095 /* alloc and init adsp session*/
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006096 st_ses->hw_ses_adsp =
6097 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
Quinn Male2e883752019-03-22 11:28:54 -07006098 if (!st_ses->hw_ses_adsp) {
6099 status = -ENOMEM;
6100 st_hw_sess_lsm_deinit(st_ses->hw_ses_cpe);
6101 goto cleanup;
6102 }
Quinn Male2e883752019-03-22 11:28:54 -07006103 status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
6104 (void *)st_ses, ST_EXEC_MODE_ADSP, v_info, sm_handle, stdev);
6105 if (status) {
6106 ALOGE("%s: initializing lsm session failed", __func__);
6107 st_hw_sess_lsm_deinit(st_ses->hw_ses_cpe);
6108 goto cleanup;
6109 }
6110 }
Quinn Male2e883752019-03-22 11:28:54 -07006111 /* set current hw_session */
6112 if (exec_mode == ST_EXEC_MODE_CPE)
6113 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
6114 else if (exec_mode == ST_EXEC_MODE_ADSP)
6115 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
Quinn Male2e883752019-03-22 11:28:54 -07006116 } else if (v_info && (EXEC_MODE_CFG_CPE == v_info->exec_mode_cfg)) {
6117 st_ses->enable_trans = false;
6118 if (stdev->is_gcs) {
6119 ALOGD("%s: initializing gcs hw session", __func__);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006120 st_ses->hw_ses_cpe =
6121 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
Quinn Male2e883752019-03-22 11:28:54 -07006122 if (!st_ses->hw_ses_cpe) {
6123 status = -ENOMEM;
6124 goto cleanup;
6125 }
6126 status = st_hw_sess_gcs_init(st_ses->hw_ses_cpe, hw_sess_cb,
6127 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6128 if (status) {
6129 ALOGE("%s: initializing gcs hw session failed %d",
6130 __func__, status);
6131 goto cleanup;
6132 }
6133 } else {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006134 st_ses->hw_ses_cpe =
6135 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
Quinn Male2e883752019-03-22 11:28:54 -07006136 if (!st_ses->hw_ses_cpe) {
6137 status = -ENOMEM;
6138 goto cleanup;
6139 }
6140 status = st_hw_sess_lsm_init(st_ses->hw_ses_cpe, hw_sess_cb,
6141 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6142 if (status) {
6143 ALOGE("%s: initializing lsm hw session failed %d",
6144 __func__, status);
6145 goto cleanup;
6146 }
6147 }
6148 st_ses->hw_ses_current = st_ses->hw_ses_cpe;
Quinn Male2e883752019-03-22 11:28:54 -07006149 } else if (v_info && (EXEC_MODE_CFG_APE == v_info->exec_mode_cfg)) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006150 /*
6151 * Check for merge sound model support and return the existing hw
6152 * session. If any other clients have already created it.
6153 */
6154 if (v_info->merge_fs_soundmodels) {
6155 if (!v_info->is_qcva_uuid) {
6156 ALOGE("%s: merge sound model not supported for non SVA engines",
6157 __func__);
6158 status = -ENOSYS;
6159 goto cleanup;
6160 }
6161 list_for_each(node, &stdev->sound_model_list) {
6162 c_ses = node_to_item(node, st_session_t, list_node);
6163 if ((c_ses != stc_ses) &&
6164 c_ses->vendor_uuid_info->is_qcva_uuid &&
6165 c_ses->vendor_uuid_info->merge_fs_soundmodels) {
6166 stc_ses->hw_proxy_ses = c_ses->hw_proxy_ses;
6167 list_add_tail(&stc_ses->hw_proxy_ses->clients_list,
6168 &stc_ses->hw_list_node);
6169 ALOGD("%s: another client attached: h%d <-- c%d", __func__,
6170 stc_ses->hw_proxy_ses->sm_handle, sm_handle);
6171 free(st_ses);
6172 st_ses = NULL;
6173 break;
6174 }
6175 }
6176 }
6177 if (st_ses) { /* If no other client exist */
6178 st_ses->hw_ses_adsp =
6179 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
6180 if (!st_ses->hw_ses_adsp) {
6181 status = -ENOMEM;
6182 goto cleanup;
6183 }
6184 status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
6185 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6186 if (status) {
6187 ALOGE("%s: initializing lsm hw session failed %d",
6188 __func__, status);
6189 goto cleanup;
6190 }
6191 st_ses->hw_ses_current = st_ses->hw_ses_adsp;
6192 }
Quinn Male2e883752019-03-22 11:28:54 -07006193 } else if (v_info && (EXEC_MODE_CFG_ARM == v_info->exec_mode_cfg)) {
6194 st_ses->enable_trans = false;
6195 st_ses->hw_ses_arm = calloc(1, sizeof(st_hw_session_pcm_t));
6196 if (!st_ses->hw_ses_arm) {
6197 status = -ENOMEM;
6198 goto cleanup;
6199 }
6200 status = st_hw_sess_pcm_init(st_ses->hw_ses_arm, hw_sess_cb,
6201 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6202 if (status) {
6203 ALOGE("%s: initializing pcm hw session failed %d",
6204 __func__, status);
6205 goto cleanup;
6206 }
6207 st_ses->hw_ses_current = st_ses->hw_ses_arm;
6208 } else if (!v_info) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006209 st_ses->hw_ses_cpe =
6210 (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
Quinn Male2e883752019-03-22 11:28:54 -07006211 if (!st_ses->hw_ses_cpe) {
6212 status = -ENOMEM;
6213 goto cleanup;
6214 }
6215 status = st_hw_sess_lsm_init(st_ses->hw_ses_cpe, hw_sess_cb,
6216 (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
6217 if (status) {
6218 ALOGE("%s: initializing lsm hw session failed %d",
6219 __func__, status);
6220 goto cleanup;
6221 }
6222 }
6223
6224 pthread_mutexattr_init(&attr);
6225 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006226 pthread_mutex_init(&stc_ses->lock, (const pthread_mutexattr_t *)&attr);
Quinn Male2e883752019-03-22 11:28:54 -07006227
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006228 stc_ses->exec_mode = exec_mode;
6229 stc_ses->sm_handle = sm_handle;
6230 stc_ses->ssr_transit_exec_mode = ST_EXEC_MODE_NONE;
6231 stc_ses->client_req_det_mode = ST_DET_UNKNOWN_MODE;
6232 stc_ses->state = ST_STATE_IDLE;
Quinn Male2e883752019-03-22 11:28:54 -07006233
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006234 if (st_ses) { /* Could get freed if other client exists */
6235 st_ses ->vendor_uuid_info = v_info;
6236 st_ses->exec_mode = exec_mode;
6237 st_ses->sm_handle = sm_handle;
6238 st_ses->lab_fp = NULL;
6239 pthread_mutex_init(&st_ses->lock, (const pthread_mutexattr_t *)&attr);
Quinn Male2e883752019-03-22 11:28:54 -07006240
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006241 stc_ses->hw_proxy_ses = st_ses;
6242 list_init(&st_ses->clients_list);
6243 list_add_tail(&st_ses->clients_list, &stc_ses->hw_list_node);
6244 ALOGD("%s: client attached: h%d <-- c%d", __func__,
6245 st_ses->sm_handle, sm_handle);
6246
6247 if (!stdev->ssr_offline_received) {
6248 STATE_TRANSITION(st_ses, idle_state_fn);
6249 } else {
6250 STATE_TRANSITION(st_ses, ssr_state_fn);
6251 status = 0;
6252 }
6253 }
Quinn Male2e883752019-03-22 11:28:54 -07006254 return status;
6255
6256cleanup:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006257 if (st_ses) {
6258 if (st_ses->hw_ses_cpe)
6259 free(st_ses->hw_ses_cpe);
6260 if (st_ses->hw_ses_adsp)
6261 free(st_ses->hw_ses_adsp);
6262 free(st_ses);
6263 }
Quinn Male2e883752019-03-22 11:28:54 -07006264 return status;
6265}
6266
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006267int st_session_deinit(st_session_t *stc_ses)
Quinn Male2e883752019-03-22 11:28:54 -07006268{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006269 st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
6270
6271 pthread_mutex_lock(&st_ses->lock);
6272 list_remove(&stc_ses->hw_list_node);
6273 ALOGV("%s: client detatched: h%d <-- c%d", __func__, st_ses->sm_handle,
6274 stc_ses->sm_handle);
6275 if (stc_ses == st_ses->det_stc_ses)
6276 st_ses->det_stc_ses = NULL;
6277
6278 if (!list_empty(&st_ses->clients_list)) {
6279 pthread_mutex_unlock(&st_ses->lock);
6280 return 0;
6281 }
Quinn Male2e883752019-03-22 11:28:54 -07006282 /* deinit cpe session */
6283 if (st_ses->hw_ses_cpe) {
6284 if (st_ses->stdev->is_gcs)
6285 st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
6286 else
6287 st_hw_sess_lsm_deinit(st_ses->hw_ses_cpe);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006288 free(st_ses->hw_ses_cpe);
Quinn Male2e883752019-03-22 11:28:54 -07006289 st_ses->hw_ses_cpe = NULL;
6290 }
Quinn Male2e883752019-03-22 11:28:54 -07006291 /* deinit adsp session */
6292 if (st_ses->hw_ses_adsp) {
6293 st_hw_sess_lsm_deinit(st_ses->hw_ses_adsp);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006294 free(st_ses->hw_ses_adsp);
Quinn Male2e883752019-03-22 11:28:54 -07006295 st_ses->hw_ses_adsp = NULL;
6296 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006297 pthread_mutex_unlock(&st_ses->lock);
Quinn Male2e883752019-03-22 11:28:54 -07006298 pthread_mutex_destroy(&st_ses->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07006299 free(stc_ses->hw_proxy_ses);
6300 stc_ses->hw_proxy_ses = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07006301
6302 return 0;
6303}