blob: 4a659917c4b0374a9df7574667b66db2549236c3 [file] [log] [blame]
Quinn Male2e883752019-03-22 11:28:54 -07001/* sound_trigger_hw.c
2 *
3 * This file contains the API to load sound models with
4 * DSP and start/stop detection of associated key phrases.
5 *
Quinn Male2bfe13b2020-08-27 16:53:51 -07006 * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved.
Quinn Male2e883752019-03-22 11:28:54 -07007 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of The Linux Foundation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * Not a Contribution.
34 *
35 * Copyright (C) 2011 The Android Open Source Project
36 *
37 * Licensed under the Apache License, Version 2.0 (the "License");
38 * you may not use this file except in compliance with the License.
39 * You may obtain a copy of the License at
40 *
41 * http://www.apache.org/licenses/LICENSE-2.0
42 *
43 * Unless required by applicable law or agreed to in writing, software
44 * distributed under the License is distributed on an "AS IS" BASIS,
45 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
46 * See the License for the specific language governing permissions and
47 * limitations under the License.
48 */
49#define LOG_TAG "sound_trigger_hw"
50#define ATRACE_TAG (ATRACE_TAG_HAL)
51/* #define LOG_NDEBUG 0 */
52#define LOG_NDDEBUG 0
53
54#include <errno.h>
55#include <stdlib.h>
56#include <dlfcn.h>
57#include <fcntl.h>
58#include <sys/resource.h>
59#include <sys/prctl.h>
60#include <sys/ioctl.h>
61#include <cutils/log.h>
62#include <cutils/atomic.h>
63#include <cutils/trace.h>
64#include <system/thread_defs.h>
65#include <hardware/sound_trigger.h>
66#include <cutils/str_parms.h>
67
68#include "st_common_defs.h"
69#include "sound_trigger_platform.h"
70#include "sound_trigger_hw.h"
71#include "st_session.h"
72#include "st_hw_common.h"
73#include "st_hw_extn.h"
74#include "st_hw_defs.h"
75
76#define XSTR(x) STR(x)
77#define STR(x) #x
78
79/* count of sound trigger hal clients */
80static unsigned int stdev_ref_cnt = 0;
81static pthread_mutex_t stdev_init_lock;
82static struct sound_trigger_device *stdev = NULL;
83
Harshal Ahire89337992020-07-13 02:38:14 +053084static struct sound_trigger_properties_extended_1_3 hw_properties_extended;
85
Quinn Male2e883752019-03-22 11:28:54 -070086/* default properties which will later be updated based on platform configuration */
87static struct sound_trigger_properties hw_properties = {
88 "QUALCOMM Technologies, Inc", // implementor
89 "Sound Trigger HAL", // description
90 1, // version
91 { 0x68ab2d40, 0xe860, 0x11e3, 0x95ef, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
92 1, // max_sound_models
93 1, // max_key_phrases
94 1, // max_users
95 RECOGNITION_MODE_VOICE_TRIGGER | RECOGNITION_MODE_GENERIC_TRIGGER, // recognition_modes
96 true, // capture_transition
97 0, // max_capture_ms
98 false, // concurrent_capture
99 false, //trigger_in_event
100 0 // power_consumption_mw
101};
102
103/* vendor uuid that the client passes for LPMA feature */
104static const sound_trigger_uuid_t lpma_uuid =
105 { 0x57CADDB1, 0xACDB, 0x4DCE, 0x8CB0, { 0x2E, 0x95, 0xA2, 0x31, 0x3A, 0xEE } };
106
107static void update_available_phrase_info(st_session_t *p_ses,
108 struct sound_trigger_phrase_sound_model *phrase_sm,
109 bool add);
110static int stdev_reconfig_backend_on_stop(st_session_t *stopped_ses);
111
112static int stop_recognition_l(st_session_t *st_session)
113{
114 int status = 0;
115
116 st_session_stop_lab(st_session);
117 status = st_session_stop(st_session);
118
119 pthread_mutex_lock(&st_session->lock);
120 st_session->callback = NULL;
121
122 if (st_session->rc_config) {
123 free(st_session->rc_config);
124 st_session->rc_config = NULL;
125 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700126 if (st_session->st_conf_levels) {
127 free(st_session->st_conf_levels);
128 st_session->st_conf_levels = NULL;
129 }
130
Quinn Male2e883752019-03-22 11:28:54 -0700131 pthread_mutex_unlock(&st_session->lock);
132 stdev_reconfig_backend_on_stop(st_session);
133 return status;
134}
135
136void update_hw_mad_exec_mode(st_exec_mode_t mode, st_profile_type_t profile_type)
137{
138 if (stdev->exec_mode != mode) {
139 platform_stdev_connect_mad(stdev->platform, mode, profile_type);
140 stdev->exec_mode = mode;
141 ALOGV("%s: new exec_mode 0x%x", __func__, mode);
142 }
143}
144
145unsigned int get_num_sessions()
146{
147 struct listnode *ses_node;
148 st_session_t *p_ses;
149 unsigned int num_sessions = 0;
150
151 if ((list_head(&stdev->sound_model_list) == NULL) ||
152 (list_tail(&stdev->sound_model_list) == NULL)) {
153 ALOGE("%s: sound model list is yet to be initialized", __func__);
154 return num_sessions;
155 }
156
157 list_for_each(ses_node, &stdev->sound_model_list) {
158 p_ses = node_to_item(ses_node, st_session_t, list_node);
159 num_sessions++;
160 }
161
162 return num_sessions;
163}
164
165unsigned int get_num_sessions_in_exec_mode(st_exec_mode_t mode)
166{
167 struct listnode *ses_node;
168 st_session_t *p_ses;
169 unsigned int num_sessions = 0;
170
171 if ((list_head(&stdev->sound_model_list) == NULL) ||
172 (list_tail(&stdev->sound_model_list) == NULL)) {
173 ALOGE("%s: sound model list is yet to be initialized", __func__);
174 return num_sessions;
175 }
176
177 list_for_each(ses_node, &stdev->sound_model_list) {
178 p_ses = node_to_item(ses_node, st_session_t, list_node);
179 if (p_ses->exec_mode == mode)
180 num_sessions++;
181 }
182
183 return num_sessions;
184}
185
186static bool check_phrases_users_available(struct st_vendor_info *v_info,
187 unsigned int num_phrases, unsigned int num_users,
188 st_exec_mode_t exec_mode, bool transit)
189{
190 bool available = false;
191
192 if (!v_info) {
193 ALOGE("%s: NULL vendor info", __func__);
194 return false;
195 }
196
197 if (!transit) {
198 if (exec_mode == ST_EXEC_MODE_CPE) {
199 if ((num_phrases <= v_info->avail_cpe_phrases) &&
200 (num_users <= v_info->avail_cpe_users))
201 available = true;
202 }
203
204 if (exec_mode == ST_EXEC_MODE_ADSP) {
205 if ((num_phrases <= v_info->avail_ape_phrases) &&
206 (num_users <= v_info->avail_ape_users))
207 available = true;
208 }
209 } else {
210 if (exec_mode == ST_EXEC_MODE_CPE) {
211 if ((num_phrases <= v_info->avail_transit_cpe_phrases) &&
212 (num_users <= v_info->avail_transit_cpe_users))
213 available = true;
214 }
215
216 if (exec_mode == ST_EXEC_MODE_ADSP) {
217 if ((num_phrases <= v_info->avail_transit_ape_phrases) &&
218 (num_users <= v_info->avail_transit_ape_users))
219 available = true;
220 }
221 }
222
223 ALOGV("%s: exec mode %d, transit %d, available %d",
224 __func__, exec_mode, transit, available);
225 return available;
226}
227
228static int parse_exec_mode_config(char *value,
229 st_exec_mode_t *exec_mode,
230 sound_model_handle_t *sm_handle)
231{
232 int ret = -EINVAL;
233 char *id, *test_r;
234
235 if (!value || !exec_mode || !sm_handle) {
236 ALOGE("%s: Invalid params passed", __func__);
237 return ret;
238 }
239
240 /*
241 * <exec_mode>,<sound_model_handle>
242 * sound model handle is optional. Valid set param values are:
243 * 1. "0" -> exec mode is set and sound model handle to default value 0
244 * 2. "1,2" -> exec mode and sound model handle are set to passed values
245 * sound model handle as 0 is treated as a global set parameter.
246 */
247
248 id = strtok_r(value, ", ", &test_r);
249 if (!id) {
250 ALOGE("%s: incorrect exec mode passed", __func__);
251 return ret;
252 }
253 *exec_mode = atoi(id);
254
255 id = strtok_r(NULL, ", ", &test_r);
256 if (!id) {
257 ALOGD("%s: No session id passed, treat as global set param", __func__);
258 *sm_handle = 0;
259 } else {
260 *sm_handle = atoi(id);
261 }
262
263 ALOGD("%s: mode %d, sm handle %d", __func__, *exec_mode, *sm_handle);
264 return 0;
265}
266
267static bool is_any_session_buffering()
268{
269 struct listnode *p_ses_node;
270 st_session_t *p_ses;
271
272 list_for_each(p_ses_node, &stdev->sound_model_list) {
273 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
274 if (st_session_is_buffering(p_ses)) {
275 ALOGD("%s:[%d] session is buffering", __func__, p_ses->sm_handle);
276 return true;
277 }
278 }
279 return false;
280}
281
282static bool is_any_session_ssr_state()
283{
284 struct listnode *p_ses_node;
285 st_session_t *p_ses;
286
287 list_for_each(p_ses_node, &stdev->sound_model_list) {
288 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
289 if (st_session_is_ssr_state(p_ses)) {
290 ALOGD("%s:[%d] session is in ssr state", __func__, p_ses->sm_handle);
291 return true;
292 }
293 }
294 return false;
295}
296
297static int check_and_transit_cpe_ses_to_ape(st_session_t *cur_ses)
298{
299 st_session_t *p_ses = NULL;
300 struct listnode *node = NULL;
301 unsigned int num_sessions = 0;
302 struct st_vendor_info *ses_v_info = NULL;
303 struct listnode transit_sound_model_list;
304 int ret = -EINVAL;
305
306 /* Switch sessions from CPE to ADSP
307 * 1. If cur_ses is NULL, all existing sessions are switched to ADSP.
308 * 2. If cur_ses is valid, cur_ses is the session requested to transit.
309 * In such cases, switch sessions if they share same backend with
310 * cur_ses.
311 */
312 ALOGD("%s: enter: current ses %p", __func__, cur_ses);
313
Quinn Male24daf422019-05-29 16:12:55 -0700314 if (stdev->platform_lpi_enable != ST_PLATFORM_LPI_NONE) {
315 ret = 0;
316 goto exit;
317 }
318
Quinn Male2e883752019-03-22 11:28:54 -0700319 if (0 == get_num_sessions_in_exec_mode(ST_EXEC_MODE_CPE)) {
320 ret = 0;
321 goto exit;
322 }
323
324 if (cur_ses && (cur_ses->exec_mode != ST_EXEC_MODE_CPE)) {
325 ALOGE("%s: Invalid mode set for current session %d",
326 __func__, cur_ses->exec_mode);
327 goto exit;
328 }
329
330 /* Initialize transit ape phrases/users for all CPE sessions */
331 list_for_each(node, &stdev->sound_model_list) {
332 p_ses = node_to_item(node, st_session_t, list_node);
333 if (p_ses->exec_mode == ST_EXEC_MODE_CPE) {
334 ses_v_info = p_ses->vendor_uuid_info;
335 ses_v_info->avail_transit_ape_phrases = ses_v_info->avail_ape_phrases;
336 ses_v_info->avail_transit_ape_users = ses_v_info->avail_ape_users;
337 }
338 }
339
340 list_init(&transit_sound_model_list);
341 /*
342 * check if the existing CPE sessions can be moved to ADSP
343 * Add sessions to be switched to transit list.
344 */
345 list_for_each(node, &stdev->sound_model_list) {
346 p_ses = node_to_item(node, st_session_t, list_node);
347 if (p_ses->exec_mode == ST_EXEC_MODE_CPE) {
348 /* check for sessions to keep on WDSP mode if requested by APP */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700349 if (ST_DET_LOW_POWER_MODE == p_ses->client_req_det_mode) {
Quinn Male2e883752019-03-22 11:28:54 -0700350 ALOGV("%s:[%d] session is requested on WDSP mode, skip",
351 __func__, p_ses->sm_handle);
352 continue;
353 }
354 /* check for sessions that match backend with current session */
355 if (cur_ses && (cur_ses != p_ses) &&
356 !platform_stdev_check_backends_match(stdev->platform,
357 cur_ses->exec_mode,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700358 cur_ses->hw_proxy_ses->hw_ses_current->st_device,
Quinn Male2e883752019-03-22 11:28:54 -0700359 p_ses->exec_mode,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700360 p_ses->hw_proxy_ses->hw_ses_current->st_device)) {
Quinn Male2e883752019-03-22 11:28:54 -0700361 ALOGV("%s:[%d] session not sharing backend",
362 __func__, p_ses->sm_handle);
363 continue;
364 }
365
366 if (++num_sessions > stdev->max_ape_sessions) {
367 ALOGE("%s: ERROR. sessions exceed max supported", __func__);
368 goto exit;
369 }
370
371 ses_v_info = p_ses->vendor_uuid_info;
372 if (ses_v_info->exec_mode_cfg != EXEC_MODE_CFG_DYNAMIC) {
373 ALOGE("%s:[%d] ERROR. exec mode cfg %d not set to Dynamic",
374 __func__, p_ses->sm_handle, ses_v_info->exec_mode_cfg);
375 goto exit;
376 }
377
378 if (p_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
379 if (check_phrases_users_available(ses_v_info, p_ses->num_phrases,
380 p_ses->num_users, ST_EXEC_MODE_ADSP, true)) {
381 ses_v_info->avail_transit_ape_phrases -= p_ses->num_phrases;
382 ses_v_info->avail_transit_ape_users -= p_ses->num_users;
383 } else {
384 ALOGE("%s: ERROR. phrases/users exceed max supported", __func__);
385 goto exit;
386 }
387 }
388 /* Add the session to transit sound models list */
389 list_add_tail(&transit_sound_model_list,
390 &p_ses->transit_list_node);
391 }
392 }
393
394 ALOGV("%s: transit list empty: %s", __func__,
395 list_empty(&transit_sound_model_list) ? "true" : "false");
396
397 /*
398 * During switching, below order is followed to ensure teardown
399 * of all sessions happens first and then are started in new exec mode.
400 * This helps avoid issues during multisession backend switching.
401 * 1. Teardown the sessions by calling set_exec_mode with NONE.
402 * 2. Bring up the sessions in ADSP mode.
403 */
404
405 /* Move sessions present in transit sound model list to NONE */
406 list_for_each(node, &transit_sound_model_list) {
407 p_ses = node_to_item(node, st_session_t, transit_list_node);
408
409 if (p_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700410 update_available_phrase_info(p_ses, p_ses->phrase_sm, true);
Quinn Male2e883752019-03-22 11:28:54 -0700411
412 ALOGD("%s:[%d] switch session to NONE", __func__, p_ses->sm_handle);
413 ret = st_session_set_exec_mode(p_ses, ST_EXEC_MODE_NONE);
414 if (ret) {
415 if (stdev->ssr_offline_received) {
416 goto ssr_exit;
417 } else {
418 /* TODO: Handle error during transitions */
419 ALOGE("%s:[%d] ERROR. could not set NONE", __func__, p_ses->sm_handle);
420 goto exit;
421 }
422 }
423 }
424
425 /* Move sessions present in transit sound model list to ADSP */
426 list_for_each(node, &transit_sound_model_list) {
427 p_ses = node_to_item(node, st_session_t, transit_list_node);
428
429 ALOGD("%s:[%d] switch session to ADSP mode", __func__, p_ses->sm_handle);
430 ret = st_session_set_exec_mode(p_ses, ST_EXEC_MODE_ADSP);
431 if (ret) {
432 if (stdev->ssr_offline_received) {
433 goto ssr_exit;
434 } else {
435 /* TODO: Handle error during transitions */
436 ALOGE("%s:[%d] ERROR. could not set ADSP mode", __func__, p_ses->sm_handle);
437 goto exit;
438 }
439 }
440
441 if (p_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700442 update_available_phrase_info(p_ses, p_ses->phrase_sm, false);
Quinn Male2e883752019-03-22 11:28:54 -0700443 }
444
445ssr_exit:
446 /* Set target exec mode to be used during ssr online handling */
447 list_for_each(node, &transit_sound_model_list) {
448 p_ses = node_to_item(node, st_session_t, transit_list_node);
449 p_ses->ssr_transit_exec_mode = ST_EXEC_MODE_ADSP;
450 }
451 sthw_extn_lpma_notify_event(LPMA_EVENT_TRANSIT_CPE_TO_APE);
452exit:
453 ALOGD("%s: exit: ret %d", __func__, ret);
454 return ret;
455}
456
457static int check_and_transit_ape_ses_to_cpe(st_session_t *cur_ses)
458{
459 st_session_t *p_ses = NULL;
460 struct listnode *node;
461 unsigned int num_sessions = 0, max_sessions;
462 struct st_vendor_info *ses_v_info = NULL;
463 struct listnode transit_sound_model_list;
464 int ret = -EINVAL;
465
466 /* Switch sessions from ADSP to CPE
467 * 1. If cur_ses is NULL, all existing sessions are switched to CPE.
468 * 2. If cur_ses is valid, cur_ses is the session requested to transit.
469 * In such cases, switch sessions if they share same backend with
470 * cur_ses.
471 */
472 ALOGD("%s: enter: current ses %p", __func__, cur_ses);
473
Quinn Male24daf422019-05-29 16:12:55 -0700474 if (stdev->platform_lpi_enable != ST_PLATFORM_LPI_NONE) {
475 ret = 0;
476 goto exit;
477 }
478
Quinn Male2e883752019-03-22 11:28:54 -0700479 if (0 == get_num_sessions_in_exec_mode(ST_EXEC_MODE_ADSP)) {
480 ret = 0;
481 goto exit;
482 }
483
484 if (cur_ses && (cur_ses->exec_mode != ST_EXEC_MODE_ADSP)) {
485 ALOGE("%s: Invalid mode set for current session %d",
486 __func__, cur_ses->exec_mode);
487 goto exit;
488 }
489
Quinn Male9a345522020-03-12 17:49:25 -0700490 max_sessions = stdev->max_wdsp_sessions;
Quinn Male2e883752019-03-22 11:28:54 -0700491
492 /* Initialize transit cpe phrases/users for all ADSP sessions */
493 list_for_each(node, &stdev->sound_model_list) {
494 p_ses = node_to_item(node, st_session_t, list_node);
495 if (p_ses->exec_mode == ST_EXEC_MODE_ADSP) {
496 ses_v_info = p_ses->vendor_uuid_info;
497 ses_v_info->avail_transit_cpe_phrases = ses_v_info->avail_cpe_phrases;
498 ses_v_info->avail_transit_cpe_users = ses_v_info->avail_cpe_users;
499 }
500 }
501
502 list_init(&transit_sound_model_list);
503 /*
504 * check if the existing ADSP sessions can be moved to CPE
505 * Add sessions to be switched to transit list.
506 */
507 list_for_each(node, &stdev->sound_model_list) {
508 p_ses = node_to_item(node, st_session_t, list_node);
509 if (p_ses->exec_mode == ST_EXEC_MODE_ADSP) {
510 /* check for sessions to keep on ADSP mode if requested by APP */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700511 if (ST_DET_HIGH_PERF_MODE == p_ses->client_req_det_mode) {
Quinn Male2e883752019-03-22 11:28:54 -0700512 ALOGV("%s:[%d] session is requested on ADSP mode, skip",
513 __func__, p_ses->sm_handle);
514 continue;
515 }
516 /* check for sessions that match backend with current session */
517 if (cur_ses && (cur_ses != p_ses) &&
518 !platform_stdev_check_backends_match(stdev->platform,
519 cur_ses->exec_mode,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700520 cur_ses->hw_proxy_ses->hw_ses_current->st_device,
Quinn Male2e883752019-03-22 11:28:54 -0700521 p_ses->exec_mode,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700522 p_ses->hw_proxy_ses->hw_ses_current->st_device)) {
Quinn Male2e883752019-03-22 11:28:54 -0700523 ALOGV("%s:[%d] session not sharing backend",
524 __func__, p_ses->sm_handle);
525 continue;
526 }
527
528 if (++num_sessions > max_sessions) {
529 ALOGE("%s: ERROR. sessions exceed max supported", __func__);
530 goto exit;
531 }
532
533 ses_v_info = p_ses->vendor_uuid_info;
534 if (ses_v_info->exec_mode_cfg != EXEC_MODE_CFG_DYNAMIC) {
535 ALOGE("%s: [%d] ERROR. exec mode cfg %d not set to Dynamic",
536 __func__, p_ses->sm_handle, ses_v_info->exec_mode_cfg);
537 goto exit;
538 }
539
540 if (p_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
541 if (check_phrases_users_available(ses_v_info, p_ses->num_phrases,
542 p_ses->num_users, ST_EXEC_MODE_CPE, true)) {
543 ses_v_info->avail_transit_cpe_phrases -= p_ses->num_phrases;
544 ses_v_info->avail_transit_cpe_users -= p_ses->num_users;
545 } else {
546 ALOGE("%s: ERROR. phrases/users exceed max supported", __func__);
547 goto exit;
548 }
549 }
550 /* Add the session to transit sound models list */
551 list_add_tail(&transit_sound_model_list,
552 &p_ses->transit_list_node);
553 }
554 }
555
556 ALOGV("%s: transit list empty: %s", __func__,
557 list_empty(&transit_sound_model_list) ? "true" : "false");
558
559 /*
560 * During switching, below order is followed to ensure teardown
561 * of all sessions happens first and then are started in new exec mode.
562 * This helps avoid issues during multisession backend switching.
563 * 1. Teardown the sessions by calling set_exec_mode with NONE.
564 * 2. Bring up the sessions in CPE mode.
565 */
566
567 /* Move sessions present in transit sound model list to NONE */
568 list_for_each(node, &transit_sound_model_list) {
569 p_ses = node_to_item(node, st_session_t, transit_list_node);
570
571 if (p_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700572 update_available_phrase_info(p_ses, p_ses->phrase_sm, true);
Quinn Male2e883752019-03-22 11:28:54 -0700573
574 ALOGD("%s:[%d] switch session to NONE", __func__, p_ses->sm_handle);
575 ret = st_session_set_exec_mode(p_ses, ST_EXEC_MODE_NONE);
576 if (ret) {
577 if (stdev->ssr_offline_received) {
578 goto ssr_exit;
579 } else {
580 /* TODO: Handle error during transitions */
581 ALOGE("%s:[%d] ERROR. could not set NONE", __func__, p_ses->sm_handle);
582 goto exit;
583 }
584 }
585 }
586
587 /* Move sessions present in transit sound model list to CPE */
588 list_for_each(node, &transit_sound_model_list) {
589 p_ses = node_to_item(node, st_session_t, transit_list_node);
590
591 ALOGD("%s:[%d] switch session to CPE mode", __func__, p_ses->sm_handle);
592 ret = st_session_set_exec_mode(p_ses, ST_EXEC_MODE_CPE);
593 if (ret) {
594 if (stdev->ssr_offline_received) {
595 goto ssr_exit;
596 } else {
597 /* TODO: Handle error during transitions */
598 ALOGE("%s:[%d] ERROR. could not set CPE mode", __func__, p_ses->sm_handle);
599 goto exit;
600 }
601 }
602
603 if (p_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700604 update_available_phrase_info(p_ses, p_ses->phrase_sm, false);
Quinn Male2e883752019-03-22 11:28:54 -0700605 }
606
607ssr_exit:
608 /* Set target exec mode to be used during ssr online handling */
609 list_for_each(node, &transit_sound_model_list) {
610 p_ses = node_to_item(node, st_session_t, transit_list_node);
611 p_ses->ssr_transit_exec_mode = ST_EXEC_MODE_CPE;
612 }
613 sthw_extn_lpma_notify_event(LPMA_EVENT_TRANSIT_APE_TO_CPE);
614
615exit:
616 ALOGD("%s: exit: ret %d", __func__, ret);
617 return ret;
618}
619
620static void notify_ssr_to_lpma(enum ssr_event_status event)
621{
622 enum sthw_extn_lpma_event_type lpma_event;
623
624 switch (event) {
625 case CPE_STATUS_OFFLINE:
626 lpma_event = LPMA_EVENT_CPE_STATUS_OFFLINE;
627 break;
628 case CPE_STATUS_ONLINE:
629 lpma_event = LPMA_EVENT_CPE_STATUS_ONLINE;
630 break;
631 case SLPI_STATUS_OFFLINE:
632 lpma_event = LPMA_EVENT_SLPI_STATUS_OFFLINE;
633 break;
634 case SLPI_STATUS_ONLINE:
635 lpma_event = LPMA_EVENT_SLPI_STATUS_ONLINE;
636 break;
637 default:
638 return;
639 }
640 sthw_extn_lpma_notify_event(lpma_event);
641}
642
643static void handle_ssr_online(enum ssr_event_status event)
644{
645 struct listnode *p_ses_node;
646 st_session_t *p_ses;
647
648 ALOGD("%s: Enter", __func__);
649 stdev->ssr_offline_received = false;
650 ATRACE_BEGIN("sthal: handle_ssr_online");
651 pthread_mutex_lock(&stdev->lock);
652
653 /* Events allowed: SND_CARD ONLINE or CPE ONLINE */
654
655 /*
656 * During SSR offline, all the custom topology info is wiped off from
657 * ADSP. Audio HAL can send these topologies during SSR online, but if
658 * Audio Hal handles SSR online event later than sthal handles SSR
659 * online, LSM session open fails with no matching topology found in
660 * ADSP. Fix it by sending common custom topologies, that includes LSM
661 * topologies, during SSR online.
662 */
663 if (event == SND_CARD_STATUS_ONLINE) {
664 ALOGV("%s: sending common custom topology", __func__);
665 if (platform_stdev_send_common_topology(stdev->platform))
666 ALOGE("%s: sending common topology failed" ,__func__);
667 }
668
669 /* reload and reactive each previously active session */
670 list_for_each(p_ses_node, &stdev->sound_model_list) {
671 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
672 st_session_ssr_online(p_ses, event);
673 }
674 if (sthw_extn_lpma_present())
675 notify_ssr_to_lpma(event);
676
677 pthread_cond_broadcast(&stdev->cond);
678
679 pthread_mutex_unlock(&stdev->lock);
680 ATRACE_END();
681 ALOGD("%s: Exit event %d", __func__, event);
682}
683
684static void handle_ssr_offline(enum ssr_event_status event)
685{
686 struct listnode *p_ses_node;
687 st_session_t *p_ses;
688
689 ALOGD("%s: Enter", __func__);
690 stdev->ssr_offline_received = true;
691 ATRACE_BEGIN("sthal: handle_ssr_offline");
692 pthread_mutex_lock(&stdev->lock);
693
694 /* Events allowed: SND_CARD OFFLINE or CPE OFFLINE */
695
696 /* teardown each session */
697 list_for_each(p_ses_node, &stdev->sound_model_list) {
698 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
699 st_session_ssr_offline(p_ses, event);
700 }
701 if (sthw_extn_lpma_present())
702 notify_ssr_to_lpma(event);
703
704 pthread_mutex_unlock(&stdev->lock);
705 ATRACE_END();
706 ALOGD("%s: Exit event %d", __func__, event);
707}
708
709static void check_sessions_transition(audio_event_type_t event_type)
710{
711 int status;
712
713 if ((AUDIO_EVENT_PLAYBACK_STREAM_ACTIVE == event_type) ||
714 ((AUDIO_EVENT_BATTERY_STATUS_CHANGED == event_type) && stdev->is_charging)) {
715 /* Transition to ADSP */
716 if (is_any_session_buffering() ||
717 is_any_session_ssr_state()) {
718 stdev->transit_dir = TRANSIT_CPE_TO_APE;
719 pthread_cond_signal(&stdev->transitions_cond);
720 } else {
721 status = check_and_transit_cpe_ses_to_ape(NULL);
722 if (status)
723 ALOGE("%s: Transition to ADSP failed, ignore", __func__);
724 }
725 } else if ((AUDIO_EVENT_PLAYBACK_STREAM_INACTIVE == event_type) ||
726 ((AUDIO_EVENT_BATTERY_STATUS_CHANGED == event_type) && !stdev->is_charging)) {
727 stdev->transit_dir = TRANSIT_APE_TO_CPE;
728 pthread_cond_signal(&stdev->transitions_cond);
729 }
730}
731
732static void handle_audio_ec_ref_enabled(audio_event_info_t* config)
733{
734 if (config == NULL) {
735 ALOGE("%s: null config event received!", __func__);
736 return;
737 }
738 ALOGD("%s: Enter", __func__);
739 pthread_mutex_lock(&stdev->lock);
740 stdev->audio_ec_enabled = config->u.audio_ec_ref_enabled;
741 pthread_mutex_unlock(&stdev->lock);
742 ALOGD("%s: Exit audio ec ref=%d", __func__, stdev->audio_ec_enabled);
743}
744
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700745static void handle_audio_concurrency(audio_event_type_t event_type,
746 audio_event_info_t* config)
Quinn Male2e883752019-03-22 11:28:54 -0700747{
Quinn Maled409e412019-12-09 14:50:48 -0800748 struct listnode *p_ses_node = NULL, *node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -0700749 st_session_t *p_ses = NULL;
Quinn Malecc1affd2019-07-18 16:13:31 -0700750 bool conc_allowed = false, lpi_changed = false, barge_in_mode = false;
Quinn Male2e883752019-03-22 11:28:54 -0700751 unsigned int num_sessions = 0;
Quinn Maled409e412019-12-09 14:50:48 -0800752 struct audio_device_info *item = NULL;
Quinn Male2e883752019-03-22 11:28:54 -0700753
Quinn Malea8019d12020-06-22 13:36:41 -0700754 if (config == NULL) {
755 ALOGE("%s: Config is NULL, exiting", __func__);
756 return;
757 }
758
759 list_for_each (node, &config->device_info.devices) {
760 item = node_to_item(node, struct audio_device_info, list);
761 ALOGV("%s: Audio device = 0x%x", __func__, item->type);
Quinn Maled409e412019-12-09 14:50:48 -0800762 }
Quinn Male2e883752019-03-22 11:28:54 -0700763
764 /*
765 UC1:
766 1. start_recognition
767 2. audio record_active
768 3. audio_record_inactive
769 4. stop_recognition
770 UC1:
771 1. start_recognition
772 2. audio record_active
773 3. stop_recognition
774 4. audio_record_inactive
775 UC2:
776 1. audio_record_active
777 2. start_recognition
778 3. stop_recogntion
779 4. audio_record_inactive
780 UC3:
781 1. audio_record_active
782 2. start_recognition
783 3. audio_record_inactive
784 4. stop_recogntion
785 */
786 pthread_mutex_lock(&stdev->lock);
787 num_sessions = get_num_sessions();
788 conc_allowed = platform_stdev_check_and_update_concurrency(stdev->platform,
789 event_type, config, num_sessions);
790
791 if (!conc_allowed)
792 sthw_extn_lpma_notify_event(LPMA_EVENT_AUDIO_CONCURRENCY);
793
794 if (!num_sessions) {
795 stdev->session_allowed = conc_allowed;
Quinn Male893c4742020-09-21 14:32:10 -0700796 /*
797 * This is needed for the following usecase:
798 *
799 * 1. LPI and NLPI have different number of MICs (different devices).
800 * 2. ST session is stopped from app and unloaded while Tx active.
801 * 3. Tx stops.
802 * 4. ST session started again from app on LPI.
803 *
804 * The device disablement is missed in step 3 because the st_session was
805 * deinitialized. Thus, it is handled here.
806 */
807 if (event_type == AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE &&
808 !platform_stdev_is_dedicated_sva_path(stdev->platform) &&
809 platform_stdev_backend_reset_allowed(stdev->platform))
810 platform_stdev_disable_stale_devices(stdev->platform);
Quinn Male2e883752019-03-22 11:28:54 -0700811 pthread_mutex_unlock(&stdev->lock);
812 return;
813 }
814 if (stdev->transit_to_adsp_on_playback)
815 check_sessions_transition(event_type);
816
Zhou Songd18c6712019-06-10 11:20:10 +0800817 if (platform_stdev_is_dedicated_sva_path(stdev->platform)) {
Quinn Male2e883752019-03-22 11:28:54 -0700818 /*
819 * When SVA has dedicated tx path, ignore capture events when concurrency
820 * is allowed with this capture event.
821 * But need to handle capture events to pause VA sessions when concurrency
822 * is not allowed but previously allowed, and also do resume when concurrency
823 * is allowed but previously not allowed.
824 */
825 if (event_type == AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE ||
826 event_type == AUDIO_EVENT_CAPTURE_DEVICE_ACTIVE ||
827 event_type == AUDIO_EVENT_CAPTURE_STREAM_INACTIVE ||
828 event_type == AUDIO_EVENT_CAPTURE_STREAM_ACTIVE) {
829 if (conc_allowed != stdev->session_allowed) {
830 stdev->session_allowed = conc_allowed;
831 if (!conc_allowed) {
832 list_for_each(p_ses_node, &stdev->sound_model_list) {
833 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
834 st_session_pause(p_ses);
835 }
836 } else {
837 list_for_each(p_ses_node, &stdev->sound_model_list) {
838 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
839 st_session_resume(p_ses);
840 }
841 }
842 } else {
843 ALOGV("%s: Ignore capture events as sva has dedicated path", __func__);
844 }
Zhou Song9b208f12019-12-12 14:41:34 +0800845 if (!conc_allowed) {
846 pthread_mutex_unlock(&stdev->lock);
847 return;
848 }
Quinn Male2e883752019-03-22 11:28:54 -0700849 }
850 } else {
851 /*
852 * 1. When concurrency is NOT allowed, pause VA sessions.
853 * 2. When concurrency is allowed on:
854 * a. audio capture enabling - do nothing as the tx paths can be shared
855 * for both VA and audio capture.
856 * b. audio capture disabling - due to tx path was previously disabled
857 * by audio capture usecase, so need to do session pause->resume
858 * to resume tx path.
859 */
Zhou Song12aa6502020-03-27 21:10:04 +0800860 if (!conc_allowed) {
Quinn Male2e883752019-03-22 11:28:54 -0700861 list_for_each(p_ses_node, &stdev->sound_model_list) {
862 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
863 st_session_pause(p_ses);
864 }
865 } else {
866 if (event_type == AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE) {
Quinn Male893c4742020-09-21 14:32:10 -0700867 /*
868 * The reset_backend flag allows the backend device to be disabled. This should
869 * only be disallowed when in non-dedicated path mode and there is an active
870 * audio input stream.
871 */
872 stdev->reset_backend = platform_stdev_backend_reset_allowed(stdev->platform);
873 st_hw_check_and_update_lpi(stdev, p_ses);
874 stdev->vad_enable = st_hw_check_vad_support(stdev, p_ses, stdev->lpi_enable);
875
Quinn Male2e883752019-03-22 11:28:54 -0700876 list_for_each(p_ses_node, &stdev->sound_model_list) {
877 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
878 ALOGD("%s:[%d] Capture device is disabled, pause SVA session",
879 __func__, p_ses->sm_handle);
880 st_session_pause(p_ses);
881 }
Quinn Male893c4742020-09-21 14:32:10 -0700882 /*
883 * This is needed when the session goes to loaded state, then
884 * LPI/NLPI switch happens due to Rx event.
885 */
886 platform_stdev_disable_stale_devices(stdev->platform);
Quinn Male2e883752019-03-22 11:28:54 -0700887 list_for_each(p_ses_node, &stdev->sound_model_list) {
888 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
889 ALOGD("%s:[%d] Capture device is disabled, resume SVA session",
890 __func__, p_ses->sm_handle);
891 st_session_resume(p_ses);
892 }
893 } else if (event_type == AUDIO_EVENT_CAPTURE_DEVICE_ACTIVE) {
894 ALOGD("Audio HAL has a capture session ON, don't disable the device");
895 }
896 }
897 stdev->session_allowed = conc_allowed;
Zhou Song9b208f12019-12-12 14:41:34 +0800898 if (!conc_allowed) {
899 pthread_mutex_unlock(&stdev->lock);
900 return;
901 }
Quinn Male2e883752019-03-22 11:28:54 -0700902 }
903
904 /*
905 * lpi/vad decision might have changed based on the capture and playback
906 * usecases becoming active/inactive. So check and update the lpi/vad
907 * configuration which will be used during device backend setting as part
908 * of session's start/resume.
909 */
Quinn Malecc1affd2019-07-18 16:13:31 -0700910 barge_in_mode = stdev->barge_in_mode;
911 st_hw_check_and_update_lpi(stdev, p_ses);
912 lpi_changed = stdev->lpi_enable != platform_get_lpi_mode(stdev->platform);
Quinn Male2e883752019-03-22 11:28:54 -0700913 stdev->vad_enable = st_hw_check_vad_support(stdev, p_ses, stdev->lpi_enable);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -0700914
Quinn Malecc1affd2019-07-18 16:13:31 -0700915 /*
916 * Usecase 1: Playback enabled without display on/battery charging:
917 * lpi_changed = true, so transition occurs.
918 * Usecase 2: Playback enabled with display on/battery charging:
919 * lpi_changed = false, and barge_in_mode changes from false to
920 * true. Dynamic EC update or transition will occur depending
921 * on the flag.
922 * Usecase 3: Playback disabled without display on/battery charging:
923 * lpi_changed = true, so transition occurs.
924 * Usecase 4: Playback disabled with display on/battery charging:
925 * lpi_changed = false, and barge_in_mode changes from true to
926 * false. Dynamic EC update or transition will occur depending
927 * on the flag.
928 */
929 if ((lpi_changed || barge_in_mode != stdev->barge_in_mode) &&
Quinn Male2e883752019-03-22 11:28:54 -0700930 !is_any_session_buffering()) {
Quinn Malecc1affd2019-07-18 16:13:31 -0700931 if (!lpi_changed && stdev->support_dynamic_ec_update) {
932 platform_stdev_update_ec_effect(stdev->platform,
933 stdev->barge_in_mode);
934 } else {
935 list_for_each(p_ses_node, &stdev->sound_model_list) {
936 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
937 if (p_ses && p_ses->exec_mode == ST_EXEC_MODE_ADSP) {
938 ALOGD("%s:[%d] LPI: pause SVA session",
939 __func__, p_ses->sm_handle);
940 st_session_pause(p_ses);
941 }
Quinn Male2e883752019-03-22 11:28:54 -0700942 }
Quinn Malecc1affd2019-07-18 16:13:31 -0700943
Quinn Malecc1affd2019-07-18 16:13:31 -0700944 list_for_each(p_ses_node, &stdev->sound_model_list) {
945 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
946 if (p_ses && p_ses->exec_mode == ST_EXEC_MODE_ADSP) {
947 ALOGD("%s:[%d] LPI: resume SVA session",
948 __func__, p_ses->sm_handle);
949 st_session_resume(p_ses);
950 }
Quinn Male2e883752019-03-22 11:28:54 -0700951 }
952 }
953 }
Quinn Male893c4742020-09-21 14:32:10 -0700954 /*
955 * The device can be disabled within this thread upon reception of the device
956 * active event because audio hal does not enable the device until after returning
957 * from this callback. After this thread exits, device disablement will be
958 * disallowed until the device inactive event is received.
959 */
960 if (event_type == AUDIO_EVENT_CAPTURE_DEVICE_ACTIVE &&
961 !platform_stdev_is_dedicated_sva_path(stdev->platform))
962 stdev->reset_backend = platform_stdev_backend_reset_allowed(stdev->platform);
Quinn Male2e883752019-03-22 11:28:54 -0700963 pthread_mutex_unlock(&stdev->lock);
964 ALOGV("%s: Exit", __func__);
965}
966
967static void *transitions_thread_loop(void * context __unused)
968{
969 int status = 0;
970 int in_ssr = 0, ssr_retry = 0;
971 /*
972 * This thread is used for audio playback transitions from ADSP
973 * to WDSP. This is needed for hotword detections on ADSP because
974 * the app pauses music playback during buffering and resumes when
975 * buffering stops. An audio playback inactive event sends the
976 * signal to this thread to begin looping while playback is paused.
977 * When both buffering and and audio playback are inactive, it is
978 * assumed to be a stoppage of audio playback NOT due to a hotword
979 * detection.
980 * This also handles battery charging use case, when the battery
981 * is not in charging status, sessions need to be transited back
982 * to WDSP.
983 * These two cases will transition to WDSP.
984 */
985 pthread_mutex_lock(&stdev->lock);
986 if (stdev->transit_wait_time <= 0)
987 stdev->transit_wait_time = TRANSIT_MIN_SLEEP_TIME_SEC;
988
989 while (!stdev->stop_transitions_thread_loop) {
990 /* Avoid spurious wake ups unncessarily acquiring wakelock later */
991 while ((stdev->transit_dir == TRANSIT_NONE) &&
992 !stdev->stop_transitions_thread_loop)
993 pthread_cond_wait(&stdev->transitions_cond, &stdev->lock);
994 if (stdev->stop_transitions_thread_loop) {
995 pthread_mutex_unlock(&stdev->lock);
996 return NULL;
997 }
998 acquire_wake_lock(PARTIAL_WAKE_LOCK, TRANSIT_WAKE_LOCK_NAME);
999 ssr_retry = TRANSIT_SSR_TIMEOUT_SEC / stdev->transit_wait_time;
1000 if (stdev->transit_dir == TRANSIT_APE_TO_CPE) {
Quinn Male3d7d9d42019-05-20 13:35:01 -07001001 while (1) {
Quinn Male2e883752019-03-22 11:28:54 -07001002 pthread_mutex_unlock(&stdev->lock);
1003 sleep(stdev->transit_wait_time);
1004 pthread_mutex_lock(&stdev->lock);
Quinn Male3d7d9d42019-05-20 13:35:01 -07001005 bool keep_ape_mode = (stdev->rx_concurrency_active &&
1006 stdev->transit_to_adsp_on_playback) ||
1007 (stdev->is_charging &&
1008 stdev->transit_to_adsp_on_battery_charging);
Quinn Male2e883752019-03-22 11:28:54 -07001009 if (stdev->transit_dir != TRANSIT_APE_TO_CPE) {
1010 ALOGD("transit_dir change to %d", stdev->transit_dir);
1011 goto release_wl;
Quinn Male3d7d9d42019-05-20 13:35:01 -07001012 } else if (keep_ape_mode) {
1013 ALOGD("%s:No need to transit to CPE", __func__);
1014 stdev->transit_dir = TRANSIT_NONE;
1015 goto release_wl;
Quinn Male2e883752019-03-22 11:28:54 -07001016 }
1017
1018 in_ssr = is_any_session_ssr_state();
1019 if (!is_any_session_buffering() &&
Quinn Male2e883752019-03-22 11:28:54 -07001020 !in_ssr) {
1021 /* Transition to WDSP */
1022 ATRACE_BEGIN("sthal: check_and_transit_ape_ses_to_cpe");
1023 status = check_and_transit_ape_ses_to_cpe(NULL);
1024 ATRACE_END();
1025 if (status)
1026 ALOGE("%s: Transition to WDSP failed, ignore", __func__);
1027 stdev->transit_dir = TRANSIT_NONE;
1028 break;
1029 } else if (in_ssr && (ssr_retry-- <= 0)) {
1030 ALOGE("%s: can't transit to cpe due to ssr", __func__);
1031 stdev->transit_dir = TRANSIT_NONE;
1032 goto release_wl;
1033 }
1034 }
1035 /*
1036 * It is possible that another rx is active or device is charging
1037 * before entering while loop which doesn't require transit to cpe.
1038 * Go back and wait for next transit event which will be not charging
1039 * or rx inactive -> transit to ape.
1040 */
1041 } else if (stdev->transit_dir == TRANSIT_CPE_TO_APE) {
1042 while (1) {
1043 pthread_mutex_unlock(&stdev->lock);
1044 sleep(stdev->transit_wait_time);
1045 pthread_mutex_lock(&stdev->lock);
1046
1047 if (stdev->transit_dir != TRANSIT_CPE_TO_APE) {
1048 ALOGD("transit_dir change to %d", stdev->transit_dir);
1049 goto release_wl;
1050 }
1051
1052 in_ssr = is_any_session_ssr_state();
1053 if (!is_any_session_buffering() && !in_ssr) {
1054 /* Transition to ADSP */
1055 ATRACE_BEGIN("sthal: check_and_transit_cpe_ses_to_ape");
1056 status = check_and_transit_cpe_ses_to_ape(NULL);
1057 ATRACE_END();
1058 if (status)
1059 ALOGE("%s: Transition to ADSP failed, ignore", __func__);
1060 stdev->transit_dir = TRANSIT_NONE;
1061 break;
1062 } else if (in_ssr && (ssr_retry-- <= 0)) {
1063 ALOGE("%s: can't transit to ape due to ssr", __func__);
1064 stdev->transit_dir = TRANSIT_NONE;
1065 goto release_wl;
1066 }
1067 }
1068 } else {
1069 ALOGE("%s: Invalid transit direction %d", __func__, stdev->transit_dir);
1070 }
1071 release_wl:
1072 release_wake_lock(TRANSIT_WAKE_LOCK_NAME);
1073 }
1074 pthread_mutex_unlock(&stdev->lock);
1075 return NULL;
1076}
1077
1078static void init_transitions_thread()
1079{
1080 int status = 0;
1081
1082 stdev->stop_transitions_thread_loop = false;
1083 stdev->transit_dir = TRANSIT_NONE;
1084 status = pthread_create(&stdev->transitions_thread, NULL,
1085 transitions_thread_loop, NULL);
1086 if (status)
1087 ALOGE("%s: Error creating transitions thread. status = %d",
1088 __func__, status);
1089}
1090
1091static void switch_device()
1092{
1093 struct listnode *p_ses_node = NULL;
1094 st_session_t *p_ses = NULL;
1095
1096 if (!get_num_sessions()) {
1097 ALOGV("%s: no sessions remaining, exiting", __func__);
1098 return;
1099 }
1100
1101 /* Start switching the device.
1102 * Disable all use cases followed by disabling the current device.
1103 * Enable new device followed by enabling all use cases .
1104 */
1105 list_for_each(p_ses_node, &stdev->sound_model_list) {
1106 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
1107 st_session_disable_device(p_ses);
1108 }
1109 sthw_extn_lpma_notify_event(LPMA_EVENT_DISABLE_DEVICE);
1110
1111 list_for_each(p_ses_node, &stdev->sound_model_list) {
1112 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
1113 st_session_enable_device(p_ses);
1114 }
1115 sthw_extn_lpma_notify_event(LPMA_EVENT_ENABLE_DEVICE);
1116}
1117
1118static void handle_device_switch(bool connect, audio_event_info_t* config)
1119{
1120 audio_devices_t device = config->u.value;
1121 audio_devices_t cur_device = 0;
1122
1123 cur_device = platform_stdev_get_capture_device(stdev->platform);
1124
1125 ALOGD("%s: device 0x%x %s", __func__, device,
1126 connect? "Connected":"Disconnected");
1127 ATRACE_BEGIN("sthal: handle_device_switch");
1128
1129 if (!stdev->support_dev_switch ||
1130 !ST_CAPTURE_DEVICE_IS_SUPPORTED(device)) {
1131 ATRACE_END();
1132 ALOGV("%s: unsupported", __func__);
1133 return;
1134 }
1135
1136 pthread_mutex_lock(&stdev->lock);
1137
1138 /* Update this device to available list of internal devices. At the time
1139 * of enabling the device for a use case, actual device will be selected
1140 * based on internal device selection policy
1141 */
Quinn Maled409e412019-12-09 14:50:48 -08001142 platform_stdev_update_device_list(device, "", &stdev->available_devices,
1143 connect);
Quinn Male2e883752019-03-22 11:28:54 -07001144
1145 if ((connect && (cur_device == device)) ||
1146 (!connect && (cur_device != device))) {
1147 ATRACE_END();
1148 ALOGV("%s: device 0x%x already %s", __func__,
1149 device, connect ? "enabled" : "disabled");
1150 pthread_mutex_unlock(&stdev->lock);
1151 return;
1152 }
1153 /*
1154 * If buffering or audio concurrency present, device switch will
1155 * interrupt and happen anyway. Session will already be in the loaded
1156 * state so device switch will set up the next session with the
1157 * new device to be started later
1158 */
1159 switch_device();
1160
1161 pthread_mutex_unlock(&stdev->lock);
1162 ATRACE_END();
1163 ALOGV("%s: Exit", __func__);
1164}
1165
Quinn Malecc1affd2019-07-18 16:13:31 -07001166static void handle_screen_status_change(audio_event_info_t* config)
1167{
1168 unsigned int num_sessions = 0;
1169 struct listnode *p_ses_node = NULL;
1170 st_session_t *p_ses = NULL;
1171
1172 pthread_mutex_lock(&stdev->lock);
1173 stdev->screen_off = config->u.value;
1174 ALOGD("%s: screen %s", __func__, stdev->screen_off ? "off" : "on");
1175
1176 num_sessions = get_num_sessions();
1177 if (!num_sessions) {
1178 pthread_mutex_unlock(&stdev->lock);
1179 return;
1180 }
1181
1182 st_hw_check_and_update_lpi(stdev, p_ses);
1183
1184 if (stdev->lpi_enable != platform_get_lpi_mode(stdev->platform) &&
Zhou Song9b208f12019-12-12 14:41:34 +08001185 !is_any_session_buffering() && stdev->session_allowed) {
Quinn Malecc1affd2019-07-18 16:13:31 -07001186 list_for_each(p_ses_node, &stdev->sound_model_list) {
1187 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
1188 if (p_ses && p_ses->exec_mode == ST_EXEC_MODE_ADSP) {
1189 ALOGD("%s:[%d] LPI: pause SVA session",
1190 __func__, p_ses->sm_handle);
1191 st_session_pause(p_ses);
1192 }
1193 }
1194
Quinn Malecc1affd2019-07-18 16:13:31 -07001195 list_for_each(p_ses_node, &stdev->sound_model_list) {
1196 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
1197 if (p_ses && p_ses->exec_mode == ST_EXEC_MODE_ADSP) {
1198 ALOGD("%s:[%d] LPI: resume SVA session",
1199 __func__, p_ses->sm_handle);
1200 st_session_resume(p_ses);
1201 }
1202 }
1203 }
1204 pthread_mutex_unlock(&stdev->lock);
1205 ALOGV("%s: Exit", __func__);
1206}
1207
Quinn Male2e883752019-03-22 11:28:54 -07001208static void handle_battery_status_change(audio_event_info_t* config)
1209{
1210 unsigned int num_sessions;
1211 struct listnode *p_ses_node = NULL;
1212 st_session_t *p_ses = NULL;
1213
1214 pthread_mutex_lock(&stdev->lock);
1215 stdev->is_charging = config->u.value;
1216 ALOGD("%s: battery status changed to %d", __func__, stdev->is_charging);
1217
1218 num_sessions = get_num_sessions();
1219 if (!num_sessions) {
1220 pthread_mutex_unlock(&stdev->lock);
1221 return;
1222 }
1223
1224 if (stdev->transit_to_adsp_on_battery_charging)
1225 check_sessions_transition(AUDIO_EVENT_BATTERY_STATUS_CHANGED);
1226
1227 /*
1228 * lpi/vad decision might have changed based on the battery status change.
1229 * So check and update the lpi/vad configuration which will be used during
1230 * device backend setting as part of session's start/resume.
1231 */
Quinn Malecc1affd2019-07-18 16:13:31 -07001232 st_hw_check_and_update_lpi(stdev, p_ses);
Quinn Male2e883752019-03-22 11:28:54 -07001233 stdev->vad_enable = st_hw_check_vad_support(stdev, p_ses,
1234 stdev->lpi_enable);
1235 if (stdev->lpi_enable != platform_get_lpi_mode(stdev->platform) &&
Zhou Song9b208f12019-12-12 14:41:34 +08001236 !is_any_session_buffering() && stdev->session_allowed &&
Quinn Male2e883752019-03-22 11:28:54 -07001237 stdev->transit_to_non_lpi_on_battery_charging) {
1238 list_for_each(p_ses_node, &stdev->sound_model_list) {
1239 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
1240 if (p_ses && p_ses->exec_mode == ST_EXEC_MODE_ADSP) {
1241 ALOGD("%s:[%d] LPI: pause SVA session",
1242 __func__, p_ses->sm_handle);
1243 st_session_pause(p_ses);
1244 }
1245 }
Quinn Malecc1affd2019-07-18 16:13:31 -07001246
Quinn Male2e883752019-03-22 11:28:54 -07001247 list_for_each(p_ses_node, &stdev->sound_model_list) {
1248 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
1249 if (p_ses && p_ses->exec_mode == ST_EXEC_MODE_ADSP) {
1250 ALOGD("%s:[%d] LPI: resume SVA session",
1251 __func__, p_ses->sm_handle);
1252 st_session_resume(p_ses);
1253 }
1254 }
1255 }
1256 pthread_mutex_unlock(&stdev->lock);
1257 ALOGV("%s: Exit", __func__);
1258}
1259
1260static void handle_echo_ref_switch(audio_event_type_t event_type,
1261 audio_event_info_t* config)
1262{
1263 struct listnode *node = NULL;
1264 st_session_t *p_ses = NULL;
Quinn Maled409e412019-12-09 14:50:48 -08001265
Quinn Male2e883752019-03-22 11:28:54 -07001266 if (config == NULL) {
1267 ALOGV("%s: null config event received!", __func__);
1268 return;
1269 }
1270
1271 pthread_mutex_lock(&stdev->lock);
1272 if (AUDIO_EVENT_PLAYBACK_STREAM_ACTIVE == event_type &&
Quinn Maled409e412019-12-09 14:50:48 -08001273 !platform_stdev_compare_devices(&config->device_info.devices,
1274 &stdev->active_rx_dev_list)) {
Quinn Male2e883752019-03-22 11:28:54 -07001275 /*
1276 * if currently no active ADSP session available, then echo
1277 * reference will be enabled during session transition
1278 */
Quinn Maled409e412019-12-09 14:50:48 -08001279 platform_stdev_assign_devices(&stdev->active_rx_dev_list,
1280 &config->device_info.devices);
Quinn Male2e883752019-03-22 11:28:54 -07001281 if (get_num_sessions_in_exec_mode(ST_EXEC_MODE_ADSP) > 0 &&
Quinn Maled409e412019-12-09 14:50:48 -08001282 (platform_stdev_is_a2dp_out_device_type(
1283 &stdev->active_rx_dev_list) ||
1284 platform_stdev_compare_device_type(&stdev->active_rx_dev_list,
1285 AUDIO_DEVICE_OUT_LINE) ||
1286 platform_stdev_compare_device_type(&stdev->active_rx_dev_list,
1287 AUDIO_DEVICE_OUT_SPEAKER) ||
1288 platform_stdev_compare_device_type(&stdev->active_rx_dev_list,
Zhou Song6ab4d642020-03-12 16:16:50 +08001289 AUDIO_DEVICE_IN_WIRED_HEADSET)) &&
1290 stdev->session_allowed) {
Quinn Male2e883752019-03-22 11:28:54 -07001291 /* pause and resume ADSP sessions to send new echo reference */
1292 list_for_each(node, &stdev->sound_model_list) {
Quinn Male2bfe13b2020-08-27 16:53:51 -07001293 ALOGD("%s: Pause and resume sessions", __func__);
Quinn Male2e883752019-03-22 11:28:54 -07001294 p_ses = node_to_item(node, st_session_t, list_node);
1295 if (p_ses->exec_mode == ST_EXEC_MODE_ADSP) {
1296 st_session_pause(p_ses);
1297 st_session_resume(p_ses);
1298 }
1299 }
1300 }
1301 }
1302 pthread_mutex_unlock(&stdev->lock);
1303}
1304
Quinn Malee51cc9c2020-09-10 13:59:29 -07001305static void get_base_properties(struct sound_trigger_device *stdev)
Quinn Male2e883752019-03-22 11:28:54 -07001306{
Quinn Malee51cc9c2020-09-10 13:59:29 -07001307 ALOGI("%s: enter", __func__);
Quinn Male2e883752019-03-22 11:28:54 -07001308
1309 stdev->hw_properties->concurrent_capture = stdev->conc_capture_supported;
1310
1311 /*
1312 * This hal interface API is not suitable to a granular level of reporting
1313 * individual max sound models based on different execution modes from
1314 * platform XML file. For ex: reporting lower no. of sound models meant for
1315 * WDSP mode results in framework not allowing more sound models which can
1316 * be supported for ADSP mode. Hence always report max sound models out of
1317 * all executions modes. At the max, the framework's error handling will be
1318 * delegated to sthal level, where sthal returns error if sound model
1319 * sessions exceed the platform supported for a given execution mode.
1320 */
Quinn Male9a345522020-03-12 17:49:25 -07001321 stdev->hw_properties->max_sound_models = MAX(stdev->max_wdsp_sessions,
1322 stdev->max_ape_sessions);
1323 stdev->hw_properties->max_key_phrases = MAX(stdev->avail_cpe_phrases,
1324 stdev->avail_ape_phrases);
1325 stdev->hw_properties->max_users = MAX(stdev->avail_cpe_users,
1326 stdev->avail_ape_users);
1327 stdev->hw_properties->max_buffer_ms = ST_GRAPHITE_LAB_BUF_DURATION_MS;
1328
Quinn Male2e883752019-03-22 11:28:54 -07001329 ALOGVV("%s version=0x%x recognition_modes=%d, capture_transition=%d, "
1330 "concurrent_capture=%d", __func__, stdev->hw_properties->version,
1331 stdev->hw_properties->recognition_modes,
1332 stdev->hw_properties->capture_transition,
1333 stdev->hw_properties->concurrent_capture);
1334
Quinn Malee51cc9c2020-09-10 13:59:29 -07001335 memset(&hw_properties_extended, 0, sizeof(hw_properties_extended));
1336 memcpy(&hw_properties_extended.base, stdev->hw_properties,
Quinn Male2e883752019-03-22 11:28:54 -07001337 sizeof(struct sound_trigger_properties));
Quinn Malee51cc9c2020-09-10 13:59:29 -07001338}
1339
1340static int stdev_get_properties(const struct sound_trigger_hw_device *dev,
1341 struct sound_trigger_properties *properties)
1342{
1343 struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
1344
1345 ALOGI("%s", __func__);
1346 if (properties == NULL) {
1347 ALOGE("%s: NULL properties", __func__);
1348 return -EINVAL;
1349 }
1350
1351 get_base_properties(stdev);
Quinn Male4bfd9b42020-09-30 17:01:45 -07001352 memcpy(properties, &hw_properties_extended.base, sizeof(struct sound_trigger_properties));
Harshal Ahire89337992020-07-13 02:38:14 +05301353 hw_properties_extended.header.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;
Quinn Male2e883752019-03-22 11:28:54 -07001354 return 0;
1355}
1356
1357static st_exec_mode_t get_session_exec_mode
1358(
1359 st_session_t *p_ses,
1360 struct sound_trigger_sound_model *common_sm
1361)
1362{
1363 unsigned int num_sessions = 0;
1364 unsigned int num_users = 0;
1365 unsigned int num_phrases = 0;
1366 unsigned int i, j;
1367 st_exec_mode_t exec_mode = ST_EXEC_MODE_NONE;
1368 struct st_vendor_info *v_info = p_ses->vendor_uuid_info;
1369 struct sound_trigger_phrase_sound_model *phrase_sm = NULL;
1370
1371 if (v_info == NULL)
1372 return ST_EXEC_MODE_NONE;
1373
1374 num_sessions = get_num_sessions();
1375
1376 if (common_sm->type == SOUND_MODEL_TYPE_KEYPHRASE) {
1377 phrase_sm = (struct sound_trigger_phrase_sound_model *)common_sm;
1378 num_phrases = phrase_sm->num_phrases;
1379
1380 for (i = 0; i < phrase_sm->num_phrases; i++) {
1381 for (j = 0; j < phrase_sm->phrases[i].num_users; j++) {
1382 num_users++;
1383 }
1384 }
1385 p_ses->num_phrases = num_phrases;
1386 p_ses->num_users = num_users;
1387
1388 ALOGD("%s: mode=%d NS=%d RKW=%u RU=%u VACKW=%u VACU=%u VADKW=%d, VADU=%d",
1389 __func__, v_info->exec_mode_cfg, num_sessions, num_phrases, num_users,
1390 v_info->avail_cpe_phrases, v_info->avail_cpe_users,
1391 v_info->avail_ape_phrases, v_info->avail_ape_users);
1392 }
1393
1394 /*
1395 * Each algorithm can be configured to either CPE, ADSP or DYNAMIC
1396 * in the vendor info, if vendor info is present use it to determine
1397 * exec_mode
1398 */
1399 if (v_info->exec_mode_cfg == EXEC_MODE_CFG_CPE) {
1400 /* Algorithm configured for CPE only */
Quinn Male9a345522020-03-12 17:49:25 -07001401 if (num_sessions < stdev->max_wdsp_sessions) {
Quinn Male2e883752019-03-22 11:28:54 -07001402 if (common_sm->type == SOUND_MODEL_TYPE_KEYPHRASE) {
1403 /* Keyphrase sound model */
1404 if (check_phrases_users_available(v_info, num_phrases,
1405 num_users, ST_EXEC_MODE_CPE, false))
1406 exec_mode = ST_EXEC_MODE_CPE;
1407 } else {
1408 /* Generic sound model without keyphrases */
1409 exec_mode = ST_EXEC_MODE_CPE;
1410 }
1411 }
1412 } else if (v_info->exec_mode_cfg == EXEC_MODE_CFG_APE) {
1413 if (num_sessions < stdev->max_ape_sessions) {
1414 if (common_sm->type == SOUND_MODEL_TYPE_KEYPHRASE) {
1415 if (check_phrases_users_available(v_info, num_phrases,
1416 num_users, ST_EXEC_MODE_ADSP, false))
1417 exec_mode = ST_EXEC_MODE_ADSP;
1418 } else {
1419 exec_mode = ST_EXEC_MODE_ADSP;
1420 }
1421 }
1422 } else if (v_info->exec_mode_cfg == EXEC_MODE_CFG_DYNAMIC) {
1423 /*
1424 * If execution type is DYNAMIC, there are two cases:
1425 * 1) Exec mode is dictated by explicit commands from the app.
1426 * This comes from stdev->client_req_exec_mode.
1427 * 2) If the app is not giving explicit exec mode commands, exec
1428 * mode is determined by the state of active audio playback in
1429 * accordance with the playback transitions functionality.
1430 */
1431 if (stdev->client_req_exec_mode == ST_EXEC_MODE_CPE) {
1432 /*
1433 * Check if the session can run on CPE, if client requested
1434 * CPE mode for all sessions.
1435 */
1436 ALOGV("%s: EXEC_MODE_CFG_DYNAMIC: req exec mode CPE", __func__);
Quinn Male9a345522020-03-12 17:49:25 -07001437 if (num_sessions < stdev->max_wdsp_sessions) {
Quinn Male2e883752019-03-22 11:28:54 -07001438 if (common_sm->type == SOUND_MODEL_TYPE_KEYPHRASE) {
1439 /* Keyphrase sound model */
1440 if (check_phrases_users_available(v_info, num_phrases,
1441 num_users, ST_EXEC_MODE_CPE, false))
1442 exec_mode = ST_EXEC_MODE_CPE;
1443 } else {
1444 /* Generic sound model without keyphrases */
1445 exec_mode = ST_EXEC_MODE_CPE;
1446 }
1447 }
1448 } else if (stdev->client_req_exec_mode == ST_EXEC_MODE_ADSP) {
1449 /*
1450 * Check if the session can run on ADSP, if client requested
1451 * ADSP mode for all sessions.
1452 */
1453 ALOGV("%s: EXEC_MODE_CFG_DYNAMIC: req exec mode ADSP", __func__);
1454 if (num_sessions < stdev->max_ape_sessions) {
1455 if (common_sm->type == SOUND_MODEL_TYPE_KEYPHRASE) {
1456 if (check_phrases_users_available(v_info, num_phrases,
1457 num_users, ST_EXEC_MODE_ADSP, false))
1458 exec_mode = ST_EXEC_MODE_ADSP;
1459 } else {
1460 exec_mode = ST_EXEC_MODE_ADSP;
1461 }
1462 }
1463 } else {
1464 /*
1465 * client_req_exec_mode is NONE.
1466 * In this case, check:
1467 * 1. If audio playback transitions are enabled
1468 * and if audio playback is currently active.
1469 * 2. If battery charging transitions are enabled
1470 * and if battery is in charging
1471 * If either of the criteria are satisfied, try on ADSP and error
1472 * out if the new session cannot be started on it. If they are not
1473 * satisfied, try on CPE and error out if the new session cannot be
1474 * started on it.
1475 *
1476 * TODO -
1477 * client requested exec mode can be NONE if transition was
1478 * requested for a particular session i.e. not a global transition.
1479 * In cases where transition was requested per session, two cases
1480 * arise for a newly started session:
1481 * 1. The new session’s backend does not match with the sessions
1482 * that have been switched and can run independent of them.
1483 * 2. The session’s backend matches with the sessions that have
1484 * been switched above.
1485 * Since st_device is not available at this point, backend_type
1486 * cannot be obtained to determine if it falls in any of the above
1487 * cases and exec mode cannot be determined.
1488 */
1489 ALOGV("%s: EXEC_MODE_CFG_DYNAMIC: req exec mode NONE", __func__);
1490 if ((stdev->transit_to_adsp_on_playback &&
1491 (stdev->rx_concurrency_active > 0)) ||
1492 (stdev->transit_to_adsp_on_battery_charging &&
1493 stdev->is_charging)) {
1494 /* Load on ADSP */
1495 if (num_sessions < stdev->max_ape_sessions) {
1496 if (common_sm->type == SOUND_MODEL_TYPE_KEYPHRASE) {
1497 /* Keyphrase sound model */
1498 if (check_phrases_users_available(v_info, num_phrases,
1499 num_users, ST_EXEC_MODE_ADSP, false))
1500 exec_mode = ST_EXEC_MODE_ADSP;
1501 } else {
1502 /* Generic sound model without keyphrases */
1503 exec_mode = ST_EXEC_MODE_ADSP;
1504 }
1505 }
1506 } else {
1507 /* Load on WDSP */
Quinn Male9a345522020-03-12 17:49:25 -07001508 if (num_sessions < stdev->max_wdsp_sessions) {
Quinn Male2e883752019-03-22 11:28:54 -07001509 if (common_sm->type == SOUND_MODEL_TYPE_KEYPHRASE) {
1510 /* Keyphrase sound model */
1511 if (check_phrases_users_available(v_info, num_phrases,
1512 num_users, ST_EXEC_MODE_CPE, false))
1513 exec_mode = ST_EXEC_MODE_CPE;
1514 } else {
1515 /* Generic sound model without keyphrases */
1516 exec_mode = ST_EXEC_MODE_CPE;
1517 }
1518 }
1519 }
1520 }
1521 } else if (v_info->exec_mode_cfg == EXEC_MODE_CFG_ARM) {
1522 if (num_sessions < stdev->max_arm_sessions)
1523 exec_mode = ST_EXEC_MODE_ARM;
1524 }
1525
1526 ALOGV("%s: Exit exec_mode=%d", __func__, exec_mode);
1527 return exec_mode;
1528}
1529
1530static void update_available_phrase_info
1531(
1532 st_session_t *p_ses,
1533 struct sound_trigger_phrase_sound_model *phrase_sm,
1534 bool add
1535)
1536{
1537 struct st_vendor_info *v_info = p_ses->vendor_uuid_info;
1538
1539 if (add) {
1540 if (p_ses->exec_mode == ST_EXEC_MODE_CPE) {
1541 v_info->avail_cpe_phrases += phrase_sm->num_phrases;
1542 v_info->avail_cpe_users += p_ses->num_users;
1543 } else {
1544 v_info->avail_ape_phrases += phrase_sm->num_phrases;
1545 v_info->avail_ape_users += p_ses->num_users;
1546 }
1547 } else {
1548 if (p_ses->exec_mode == ST_EXEC_MODE_CPE) {
1549 v_info->avail_cpe_phrases -= phrase_sm->num_phrases;
1550 v_info->avail_cpe_users -= p_ses->num_users;
1551 } else {
1552 v_info->avail_ape_phrases -= phrase_sm->num_phrases;
1553 v_info->avail_ape_users -= p_ses->num_users;
1554 }
1555 }
1556}
1557
1558static bool compare_recognition_config
1559(
1560 const struct sound_trigger_recognition_config *current_config,
1561 struct sound_trigger_recognition_config *new_config
1562)
1563{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001564 unsigned int i = 0, j = 0;
Quinn Male2e883752019-03-22 11:28:54 -07001565
1566 /*
1567 * Sometimes if the number of user confidence levels is 0, the
1568 * sound_trigger_confidence_level struct will be different between the two
1569 * configs. So all the values must be checked instead of a memcmp of the
1570 * whole configs.
1571 */
Harshal Ahire89337992020-07-13 02:38:14 +05301572
1573 /*
1574 * Extra uint32_t is added in memcmp as opaque data config starts after
1575 * audio_capabilities as per SOUND_TRIGGER_DEVICE_API_VERSION_1_3
1576 */
1577
Quinn Male2e883752019-03-22 11:28:54 -07001578 if ((current_config->capture_handle != new_config->capture_handle) ||
1579 (current_config->capture_device != new_config->capture_device) ||
1580 (current_config->capture_requested != new_config->capture_requested) ||
1581 (current_config->num_phrases != new_config->num_phrases) ||
1582 (current_config->data_size != new_config->data_size) ||
1583 (current_config->data_offset != new_config->data_offset) ||
Harshal Ahire89337992020-07-13 02:38:14 +05301584 (hw_properties_extended.header.version == SOUND_TRIGGER_DEVICE_API_VERSION_1_3 &&
1585 memcmp((char *) current_config + current_config->data_offset,
1586 (char *) new_config + sizeof(struct sound_trigger_recognition_config) +
1587 sizeof(uint32_t), current_config->data_size)) ||
1588 (hw_properties_extended.header.version == SOUND_TRIGGER_DEVICE_API_VERSION_1_0 &&
1589 memcmp((char *) current_config + current_config->data_offset,
Quinn Male2e883752019-03-22 11:28:54 -07001590 (char *) new_config + new_config->data_offset,
Harshal Ahire89337992020-07-13 02:38:14 +05301591 current_config->data_size))) {
Quinn Male2e883752019-03-22 11:28:54 -07001592 return false;
1593 } else {
1594 for (i = 0; i < current_config->num_phrases; i++) {
1595 if ((current_config->phrases[i].id !=
1596 new_config->phrases[i].id) ||
1597 (current_config->phrases[i].recognition_modes !=
1598 new_config->phrases[i].recognition_modes) ||
1599 (current_config->phrases[i].confidence_level !=
1600 new_config->phrases[i].confidence_level) ||
1601 (current_config->phrases[i].num_levels !=
1602 new_config->phrases[i].num_levels)) {
1603 return false;
1604 } else {
1605 for (j = 0; j < current_config->phrases[i].num_levels; j++) {
1606 if ((current_config->phrases[i].levels[j].user_id !=
1607 new_config->phrases[i].levels[j].user_id) ||
1608 (current_config->phrases[i].levels[j].level !=
1609 new_config->phrases[i].levels[j].level))
1610 return false;
1611 }
1612 }
1613 }
1614 return true;
1615 }
1616}
1617
1618static int load_audio_hal()
1619{
1620 int status = 0;
1621 char audio_hal_lib[100];
1622 void *sthal_prop_api_version;
1623
1624 snprintf(audio_hal_lib, sizeof(audio_hal_lib), "%s/%s.%s.so",
1625 AUDIO_HAL_LIBRARY_PATH1, AUDIO_HAL_NAME_PREFIX,
1626 XSTR(SOUND_TRIGGER_PLATFORM));
1627 if (access(audio_hal_lib, R_OK)) {
1628 snprintf(audio_hal_lib, sizeof(audio_hal_lib), "%s/%s.%s.so",
1629 AUDIO_HAL_LIBRARY_PATH2, AUDIO_HAL_NAME_PREFIX,
1630 XSTR(SOUND_TRIGGER_PLATFORM));
1631 if (access(audio_hal_lib, R_OK)) {
1632 ALOGE("%s: ERROR. %s not found", __func__, audio_hal_lib);
1633 return -ENOENT;
1634 }
1635 }
1636
1637 stdev->audio_hal_handle = dlopen(audio_hal_lib, RTLD_NOW);
1638 if (!stdev->audio_hal_handle) {
1639 ALOGE("%s: ERROR. %s", __func__, dlerror());
1640 return -ENODEV;
1641 }
1642
1643 DLSYM(stdev->audio_hal_handle, stdev->audio_hal_cb, audio_hw_call_back,
1644 status);
1645 if (status)
1646 goto error;
1647
1648 DLSYM(stdev->audio_hal_handle, sthal_prop_api_version,
1649 sthal_prop_api_version, status);
1650 if (status) {
1651 stdev->sthal_prop_api_version = 0;
1652 status = 0; /* passthru for backward compability */
1653 } else {
1654 stdev->sthal_prop_api_version = *(int*)sthal_prop_api_version;
1655 if (MAJOR_VERSION(stdev->sthal_prop_api_version) !=
1656 MAJOR_VERSION(STHAL_PROP_API_CURRENT_VERSION)) {
1657 ALOGE("%s: Incompatible API versions sthal:0x%x != ahal:0x%x",
1658 __func__, STHAL_PROP_API_CURRENT_VERSION,
1659 stdev->sthal_prop_api_version);
1660 goto error;
1661 }
1662 ALOGD("%s: ahal is using proprietary API version 0x%04x", __func__,
1663 stdev->sthal_prop_api_version);
1664 }
1665 return status;
1666
1667error:
1668 dlclose(stdev->audio_hal_handle);
1669 stdev->audio_hal_handle = NULL;
1670 return status;
1671}
1672
1673#ifndef USE_KEEP_ALIVE
1674#define run_keep_alive_session(stdev, st_ses, event) (0)
1675#else
1676static void run_keep_alive_session(struct sound_trigger_device *stdev,
1677 st_session_t *st_ses, int event)
1678{
1679 struct sound_trigger_event_info event_info;
1680
1681 ALOGV("%s: keep alive event %d", __func__, event);
1682 event_info.st_ses.p_ses = NULL;
1683 if ((ST_EXEC_MODE_ARM == st_ses->exec_mode) &&
1684 !st_ses->vendor_uuid_info->split_ec_ref_data)
1685 stdev->audio_hal_cb(event, &event_info);
1686
1687}
1688#endif /*USE_KEEP_ALIVE*/
1689
1690static int allocate_arm_second_stage_session(struct st_arm_second_stage **st_sec_stage,
1691 unsigned int sm_size)
1692{
1693 int status = 0;
1694
1695 *st_sec_stage = calloc(1, sizeof(struct st_arm_second_stage));
1696 if (!*st_sec_stage) {
1697 ALOGE("%s: failed to allocate struct st_arm_second_stage", __func__);
1698 status = -ENOMEM;
1699 goto exit;
1700 }
1701 (*st_sec_stage)->ss_info = calloc(1, sizeof(struct st_second_stage_info));
1702 if (!(*st_sec_stage)->ss_info) {
1703 ALOGE("%s: failed to allocate struct st_second_stage_info", __func__);
1704 status = -ENOMEM;
1705 goto exit;
1706 }
1707 (*st_sec_stage)->ss_session = calloc(1, sizeof(struct st_arm_ss_session));
1708 if (!(*st_sec_stage)->ss_session) {
1709 ALOGE("%s: failed to allocate struct st_arm_ss_session", __func__);
1710 status = -ENOMEM;
1711 goto exit;
1712 }
1713 (*st_sec_stage)->ss_session->sound_model = calloc(sm_size, sizeof(char));
1714 if (!(*st_sec_stage)->ss_session->sound_model) {
1715 ALOGE("%s: failed to allocate second stage sound model", __func__);
1716 status = -ENOMEM;
1717 goto exit;
1718 }
1719
1720exit:
1721 return status;
1722}
1723
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001724static void deallocate_arm_second_stage_session(
1725 struct st_arm_second_stage *st_sec_stage)
Quinn Male2e883752019-03-22 11:28:54 -07001726{
1727 if (st_sec_stage) {
1728 if (st_sec_stage->ss_info) {
1729 free(st_sec_stage->ss_info);
1730 st_sec_stage->ss_info = NULL;
1731 }
1732 if (st_sec_stage->ss_session) {
1733 st_sec_stage->ss_session->st_ses = NULL;
1734 if (st_sec_stage->ss_session->sound_model) {
1735 free(st_sec_stage->ss_session->sound_model);
1736 st_sec_stage->ss_session->sound_model = NULL;
1737 }
1738 free(st_sec_stage->ss_session);
1739 st_sec_stage->ss_session = NULL;
1740 }
1741 free(st_sec_stage);
1742 st_sec_stage = NULL;
1743 }
1744}
1745
1746static int allocate_lsm_ss_config(st_lsm_ss_config_t **ss_cfg, size_t sm_size)
1747{
1748 st_lsm_ss_config_t *cfg;
1749
1750 cfg = calloc(1, sizeof(st_lsm_ss_config_t));
1751 if (!cfg) {
1752 ALOGE("%s: failed to allocate lsm ss config", __func__);
1753 return -ENOMEM;
1754 }
1755 cfg->sm_data = calloc(sm_size, sizeof(char));
1756 if (!cfg->sm_data) {
1757 ALOGE("%s: failed to allocate sound model lsm ss config", __func__);
1758 free(cfg);
1759 return -ENOMEM;
1760 }
1761 *ss_cfg = cfg;
1762 return 0;
1763}
1764
1765static void deallocate_lsm_ss_config(st_lsm_ss_config_t *ss_cfg)
1766{
1767 if (ss_cfg) {
1768 free(ss_cfg->sm_data);
1769 free(ss_cfg);
1770 }
1771}
1772
1773/*
1774 * This function takes the sound model id from each SML_BigSoundModelTypeV3 in
1775 * the sound_trigger_sound_model payload, and looks for a match in the platform
1776 * list derived from the platform xml file. If there is a match, allocate the
1777 * structures needed to support a second stage session.
1778 */
1779static int check_and_configure_second_stage_models
1780(
1781 st_session_t *st_ses,
1782 uint8_t *sm_payload,
1783 uint32_t num_models,
1784 uint32_t recognition_mode
1785)
1786{
1787 int ret = 0;
1788 struct st_ss_usecase ss_usecase;
1789 struct st_arm_second_stage *st_sec_stage = NULL;
1790 SML_BigSoundModelTypeV3 *big_sm;
1791 uint32_t i;
1792 uint8_t *sound_model;
1793
Quinn Male2e883752019-03-22 11:28:54 -07001794 for (i = 0; i < num_models; i++) {
1795 big_sm = (SML_BigSoundModelTypeV3 *)(sm_payload + sizeof(SML_GlobalHeaderType) +
1796 sizeof(SML_HeaderTypeV3) + (i * sizeof(SML_BigSoundModelTypeV3)));
1797
1798 if (big_sm->type != ST_SM_ID_SVA_GMM) {
Quinn Maleff134d92020-07-02 15:54:32 -07001799 if (big_sm->type == SML_ID_SVA_S_STAGE_UBM || (big_sm->type == ST_SM_ID_SVA_VOP &&
1800 !(recognition_mode & RECOGNITION_MODE_USER_IDENTIFICATION)))
Quinn Male2e883752019-03-22 11:28:54 -07001801 continue;
1802
1803 ss_usecase = platform_get_ss_usecase(st_ses->vendor_uuid_info, big_sm->type);
1804 if (ss_usecase.type == ST_SS_USECASE_TYPE_ARM) {
1805 ret = allocate_arm_second_stage_session(&st_sec_stage, big_sm->size);
1806 if (ret || (st_sec_stage == NULL)) {
1807 ALOGE("%s: failed to allocate arm second stage session", __func__);
1808 goto exit;
1809 }
1810
1811 st_sec_stage->ss_session->sm_size = big_sm->size;
1812 sound_model = (uint8_t *)(sm_payload + sizeof(SML_GlobalHeaderType) +
1813 sizeof(SML_HeaderTypeV3) + (num_models * sizeof(SML_BigSoundModelTypeV3)) +
1814 big_sm->offset);
1815
1816 memcpy(st_sec_stage->ss_session->sound_model, sound_model, big_sm->size);
1817 memcpy((char *)st_sec_stage->ss_info, (char *)&ss_usecase.arm->common_params,
1818 sizeof(struct st_second_stage_info));
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001819 st_sec_stage->stdev = st_ses->stdev;
Quinn Male2e883752019-03-22 11:28:54 -07001820 list_add_tail(&st_ses->second_stage_list, &st_sec_stage->list_node);
1821 ALOGD("%s: Added second stage session of type %d", __func__,
1822 st_sec_stage->ss_info->sm_detection_type);
1823 } else if (ss_usecase.type == ST_SS_USECASE_TYPE_LSM) {
1824 st_lsm_ss_config_t *ss_cfg = NULL;
1825
1826 if (!st_hw_check_ses_ss_usecase_allowed(st_ses)) {
1827 ALOGE("%s: cannot add requested lsm ss usecase", __func__);
1828 ret = -EBUSY;
1829 goto exit;
1830 }
1831
1832 ret = allocate_lsm_ss_config(&ss_cfg, big_sm->size);
1833 if (ret) {
1834 ALOGE("%s: failed to allocate lsm ss config", __func__);
1835 goto exit;
1836 }
1837
1838 ss_cfg->sm_size = big_sm->size;
1839 sound_model = (uint8_t *)(sm_payload + sizeof(SML_GlobalHeaderType) +
1840 sizeof(SML_HeaderTypeV3) + (num_models * sizeof(SML_BigSoundModelTypeV3)) +
1841 big_sm->offset);
1842 memcpy(ss_cfg->sm_data, sound_model, big_sm->size);
1843
1844 ss_cfg->params = ss_usecase.lsm;
1845 ss_cfg->ss_info = &ss_usecase.lsm->common_params;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001846 list_add_tail(&st_ses->hw_proxy_ses->hw_ses_adsp->lsm_ss_cfg_list,
1847 &ss_cfg->list_node);
Quinn Male2e883752019-03-22 11:28:54 -07001848 ALOGD("%s: Added second stage lsm usecase with sm id %d", __func__, big_sm->type);
1849 } else if (ss_usecase.type == ST_SS_USECASE_TYPE_NONE) {
1850 ALOGE("%s: No matching usecase in sound trigger platform for sm_id %d",
1851 __func__, big_sm->type);
1852 ret = -EINVAL;
1853 goto exit;
1854 }
1855 }
1856 }
Quinn Male2e883752019-03-22 11:28:54 -07001857
1858 return 0;
1859
1860exit:
1861 deallocate_arm_second_stage_session(st_sec_stage);
1862 return ret;
1863}
1864
1865/*
1866 * This function finds the first stage sound model raw data size and offset, and sets
1867 * the sound_trigger_sound_model payload size and offset to these values.
1868 */
Quinn Male58749452020-03-26 17:14:56 -07001869static int get_first_stage_model(struct sound_trigger_sound_model **common_sm,
1870 uint8_t *sm_payload, uint32_t num_models,
1871 st_module_type_t *sm_version)
Quinn Male2e883752019-03-22 11:28:54 -07001872{
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07001873 SML_BigSoundModelTypeV3 *big_sm = NULL;
1874 uint32_t i = 0;
Quinn Male2e883752019-03-22 11:28:54 -07001875 int status = 0;
1876
1877 for (i = 0; i < num_models; i++) {
1878 big_sm = (SML_BigSoundModelTypeV3 *)(sm_payload + sizeof(SML_GlobalHeaderType) +
1879 sizeof(SML_HeaderTypeV3) + (i * sizeof(SML_BigSoundModelTypeV3)));
1880 if (big_sm->type == ST_SM_ID_SVA_GMM) {
Quinn Male58749452020-03-26 17:14:56 -07001881 if (big_sm->versionMajor == ST_MODULE_TYPE_PDK5)
1882 *sm_version = ST_MODULE_TYPE_PDK5;
1883 else
1884 *sm_version = ST_MODULE_TYPE_GMM;
Quinn Male2e883752019-03-22 11:28:54 -07001885 (*common_sm)->data_size = big_sm->size;
1886 (*common_sm)->data_offset += sizeof(SML_GlobalHeaderType) + sizeof(SML_HeaderTypeV3) +
1887 (num_models * sizeof(SML_BigSoundModelTypeV3)) + big_sm->offset;
1888 break;
1889 }
1890 }
1891 if (!(*common_sm)) {
1892 ALOGE("%s: common_sm was not initialized, exiting", __func__);
1893 status = -EINVAL;
1894 }
1895 return status;
1896}
1897
1898#ifdef ST_SUPPORT_GET_MODEL_STATE
1899static int stdev_get_model_state(const struct sound_trigger_hw_device *dev,
1900 sound_model_handle_t handle)
1901{
1902 int status = 0;
1903 st_session_t* st_ses = NULL;
1904 struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
1905
1906 ALOGD("%s:[%d] Enter", __func__, handle);
1907
1908 if (!stdev) {
1909 ALOGE("%s: sound_trigger_device is NULL, exiting", __func__);
1910 return -ENODEV;
1911 }
1912
1913 pthread_mutex_lock(&stdev->lock);
1914 st_ses = get_sound_trigger_session(stdev, handle);
1915 if (!st_ses) {
1916 ALOGE("%s: Error - no sound trigger session with handle %d",
1917 __func__, handle);
1918 status = -ENOSYS;
1919 goto err_exit;
1920 }
1921
1922 status = st_session_request_detection(st_ses);
1923
1924err_exit:
1925 pthread_mutex_unlock(&stdev->lock);
1926 ALOGD("%s: Exit, status %d", __func__, status);
1927 return status;
1928}
1929#endif
1930
1931static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
1932 struct sound_trigger_sound_model *sound_model,
1933 sound_model_callback_t callback __unused,
1934 void *cookie __unused,
1935 sound_model_handle_t *handle)
1936{
1937 int status = 0;
1938 st_exec_mode_t exec_mode;
1939 st_session_t *st_session = NULL;
1940 struct sound_trigger_phrase_sound_model *phrase_sm = NULL;
1941 struct sound_trigger_sound_model *common_sm = NULL;
1942 unsigned int sm_size = 0;
1943 struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
1944 uint8_t *sm_payload;
1945 SML_GlobalHeaderType *global_hdr;
1946 SML_HeaderTypeV3 *hdr_v3;
Quinn Male58749452020-03-26 17:14:56 -07001947 uint32_t num_models = 0, sml_version = SML_MODEL_V2;
1948 st_module_type_t sm_version = ST_MODULE_TYPE_GMM;
Quinn Male2e883752019-03-22 11:28:54 -07001949 struct listnode *node = NULL, *tmp_node = NULL;
1950 struct st_arm_second_stage *st_sec_stage = NULL;
1951
1952 ALOGD("%s", __func__);
1953 ATRACE_BEGIN("sthal: stdev_load_sound_model");
1954
1955 pthread_mutex_lock(&stdev->lock);
1956
1957 if (handle == NULL || sound_model == NULL) {
1958 status = -EINVAL;
1959 goto exit;
1960 }
1961
1962 /*
1963 * For LPMA feature, client just passes known vendor_uuid to start the
1964 * LPMA usecase. This is a hacky way of reusing existing HAL interface
1965 * to start/stop LPMA non-VA usecase from client.
1966 */
1967 if (!memcmp(&sound_model->vendor_uuid,
1968 &lpma_uuid, sizeof(sound_trigger_uuid_t))) {
1969 if (stdev->lpma_handle == -1) {
1970 status = sthw_extn_lpma_notify_event(LPMA_EVENT_START);
1971 *handle = (!status ? android_atomic_inc(&stdev->session_id): -1);
1972 stdev->lpma_handle = *handle;
1973 } else {
1974 ALOGD("%s: lpma is already started", __func__);
1975 *handle = stdev->lpma_handle;
1976 }
1977 pthread_mutex_unlock(&stdev->lock);
1978 ATRACE_END();
1979 ALOGD("%s: lpma exit status %d", __func__, status);
1980 return status;
1981 }
1982
1983 /*
1984 * for swmad case dont load sm and return failure to client
1985 */
1986 if (!stdev->session_allowed && stdev->sw_mad) {
1987 ALOGW("%s: session prevented by concurrency", __func__);
1988 status = -ENODEV;
1989 goto exit;
1990 }
1991
1992 if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
1993 phrase_sm = (struct sound_trigger_phrase_sound_model *)sound_model;
1994 if ((phrase_sm->common.data_size == 0) ||
1995 (phrase_sm->common.data_offset < sizeof(*phrase_sm)) ||
1996 (phrase_sm->common.type != SOUND_MODEL_TYPE_KEYPHRASE) ||
1997 (phrase_sm->num_phrases == 0)) {
1998 ALOGE("%s: Invalid phrase sound model params data size=%d, data offset=%d, "
1999 "type=%d phrases=%d", __func__, phrase_sm->common.data_size,
2000 phrase_sm->common.data_offset, phrase_sm->common.type,
2001 phrase_sm->num_phrases);
2002 status = -EINVAL;
2003 goto exit;
2004 }
2005 common_sm = &phrase_sm->common;
2006 sm_payload = (uint8_t *)common_sm + common_sm->data_offset;
2007 global_hdr = (SML_GlobalHeaderType *)sm_payload;
2008 if (global_hdr->magicNumber == SML_GLOBAL_HEADER_MAGIC_NUMBER) {
Quinn Male58749452020-03-26 17:14:56 -07002009 sml_version = SML_MODEL_V3;
Quinn Male2e883752019-03-22 11:28:54 -07002010 hdr_v3 = (SML_HeaderTypeV3 *)(sm_payload + sizeof(SML_GlobalHeaderType));
2011 num_models = hdr_v3->numModels;
Quinn Male58749452020-03-26 17:14:56 -07002012 status = get_first_stage_model(&common_sm, sm_payload, num_models, &sm_version);
Quinn Male2e883752019-03-22 11:28:54 -07002013 if (status) {
2014 ALOGE("%s: Failed to set the first stage sound modle offset and size",
2015 __func__);
2016 goto exit;
2017 }
2018 }
2019 sm_size = sizeof(*phrase_sm) + phrase_sm->common.data_size;
2020 } else if (sound_model->type == SOUND_MODEL_TYPE_GENERIC) {
2021 if (!sound_model->data_size ||
2022 (sound_model->data_offset < sizeof(*common_sm))) {
2023 ALOGE("%s: Invalid Generic sound model params data size=%d, data offset=%d",
2024 __func__, sound_model->data_size, sound_model->data_offset);
2025 status = -EINVAL;
2026 goto exit;
2027 }
2028 common_sm = sound_model;
2029 sm_size = sizeof(*common_sm) + common_sm->data_size;
2030 sm_payload = (uint8_t *)common_sm + common_sm->data_offset;
2031 } else {
2032 ALOGE("%s: Unknown sound model type %d", __func__, sound_model->type);
2033 status = -EINVAL;
2034 goto exit;
2035 }
2036
2037 ALOGV("%s: sm_size=%d data_size=%d", __func__, sm_size, common_sm->data_size);
2038 st_session = calloc(1, sizeof(st_session_t));
2039 if (!st_session) {
2040 status = -ENOMEM;
2041 goto exit;
2042 }
Venkatesh Mangalappali50367742019-08-07 17:19:59 -07002043 list_init(&st_session->second_stage_list);
Quinn Male2e883752019-03-22 11:28:54 -07002044
Quinn Male58749452020-03-26 17:14:56 -07002045 st_session->f_stage_version = sm_version;
2046
Quinn Male2e883752019-03-22 11:28:54 -07002047 /* CPE takes time to become online, so parse for the pcm devices
2048 here instead during boot time */
2049 if (!CHECK_BIT(stdev->hw_type,
2050 ST_DEVICE_HW_APE|ST_DEVICE_HW_CPE|ST_DEVICE_HW_ARM)) {
2051 status = platform_stdev_get_hw_type(stdev->platform);
2052 if (status)
2053 goto exit;
2054 }
2055
2056 st_session->vendor_uuid_info = platform_stdev_get_vendor_info(
2057 stdev->platform,
2058 &common_sm->vendor_uuid);
2059
2060 if (!st_session->vendor_uuid_info) {
2061 ALOGE("%s: no matching vendor uuid found", __func__);
2062 status = -EINVAL;
2063 goto exit;
2064 }
2065
2066 exec_mode = get_session_exec_mode(st_session, common_sm);
2067 if (exec_mode == ST_EXEC_MODE_NONE) {
2068 status = -EINVAL;
2069 goto exit;
2070 }
2071
2072 *handle = android_atomic_inc(&stdev->session_id);
2073
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002074 ALOGD("%s:[%d] calling st_session_init", __func__, *handle);
Quinn Male2e883752019-03-22 11:28:54 -07002075 status = st_session_init(st_session, stdev, exec_mode, *handle);
2076 if (status) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002077 ALOGE("%s: failed to initialize st_session with error %d", __func__,
2078 status);
Quinn Male2e883752019-03-22 11:28:54 -07002079 goto exit_1;
2080 }
2081
Shalini Manjunatha47c34c82021-05-10 16:46:43 +05302082 ALOGD("%s: second state detection %s",__func__,
2083 st_session->vendor_uuid_info->second_stage_supported ? "supported" : "not supported");
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002084 /*
2085 * Parse second stage sound models and populate the second stage list for
2086 * this session.
2087 */
Shalini Manjunatha47c34c82021-05-10 16:46:43 +05302088 if (sml_version == SML_MODEL_V3 && st_session->vendor_uuid_info->second_stage_supported) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002089 status = check_and_configure_second_stage_models(st_session, sm_payload,
2090 num_models, phrase_sm->phrases[0].recognition_mode);
Quinn Male2e883752019-03-22 11:28:54 -07002091 if (status) {
2092 ALOGE("%s: Failed to set the second stage list", __func__);
2093 goto exit_2;
2094 }
2095 }
2096
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002097 if (!list_empty(&st_session->second_stage_list)) {
2098 ALOGD("%s: calling st_session_ss_init ", __func__);
Quinn Male2e883752019-03-22 11:28:54 -07002099 status = st_session_ss_init(st_session);
2100 if (status) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002101 ALOGE("%s: failed to initialize st_session second stage,"
2102 "error %d", __func__, status);
Quinn Male2e883752019-03-22 11:28:54 -07002103 goto exit_2;
2104 }
2105 }
2106
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002107 /*
2108 * Store the sound model information for handling SSR
2109 * and interaction with smlib
2110 */
2111 st_session->phrase_sm = calloc(1, sm_size);
2112 if (!st_session->phrase_sm) {
Quinn Male2e883752019-03-22 11:28:54 -07002113 status = -ENOMEM;
2114 goto exit_3;
2115 }
2116
2117 if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002118 memcpy(st_session->phrase_sm, (char *)phrase_sm, sizeof(*phrase_sm));
2119 st_session->phrase_sm->common.data_offset = sizeof(*phrase_sm);
2120 memcpy((char *)st_session->phrase_sm + sizeof(*phrase_sm),
Quinn Male2e883752019-03-22 11:28:54 -07002121 (char *)phrase_sm + phrase_sm->common.data_offset,
2122 phrase_sm->common.data_size);
2123 /* TODO: SVA doesn't support per keyword recognition mode.
2124 * So use the first phrase recognition mode. App is supposed
2125 * to set the proper recognition mode in the first phrase
2126 */
2127 st_session->recognition_mode = phrase_sm->phrases[0].recognition_mode;
2128 ALOGD("%s: sm magic number 0x%x rm %d", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002129 ((int *)((char *)st_session->phrase_sm +
2130 phrase_sm->common.data_offset))[0],
Quinn Male2e883752019-03-22 11:28:54 -07002131 phrase_sm->phrases[0].recognition_mode);
2132 } else {
2133 st_session->recognition_mode = RECOGNITION_MODE_VOICE_TRIGGER;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002134 memcpy(st_session->phrase_sm, (char *)common_sm, sizeof(*common_sm));
2135 memcpy((char *)st_session->phrase_sm + common_sm->data_offset,
Quinn Male2e883752019-03-22 11:28:54 -07002136 (char *)common_sm + common_sm->data_offset,
2137 common_sm->data_size);
2138 ALOGD("%s: sm magic number 0x%x", __func__,
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002139 ((int *)((char *)st_session->phrase_sm +
2140 common_sm->data_offset))[0]);
Quinn Male2e883752019-03-22 11:28:54 -07002141 }
2142
2143 st_session->sm_type = sound_model->type;
Quinn Malecc1affd2019-07-18 16:13:31 -07002144 st_hw_check_and_update_lpi(stdev, NULL);
Quinn Male2e883752019-03-22 11:28:54 -07002145 st_hw_check_and_set_lpi_mode(st_session);
2146
Quinn Male2e883752019-03-22 11:28:54 -07002147 status = st_session_load_sm(st_session);
2148 if (status) {
2149 goto exit_3;
2150 }
2151
2152 if (!stdev->session_allowed) {
2153 status = st_session_pause(st_session);
2154 if (status) {
2155 st_session_unload_sm(st_session);
2156 goto exit_3;
2157 }
2158 }
2159
Quinn Male2e883752019-03-22 11:28:54 -07002160 /* Keyphrase, user information is valid only for keyphrase sound models */
2161 if ((common_sm->type == SOUND_MODEL_TYPE_KEYPHRASE) && (phrase_sm != NULL))
2162 update_available_phrase_info(st_session, phrase_sm, false);
2163
2164 /* Add the session to the list of registered sound models list */
2165 list_add_tail(&stdev->sound_model_list, &st_session->list_node);
2166
2167 pthread_mutex_unlock(&stdev->lock);
2168
2169 ATRACE_END();
2170
2171 run_keep_alive_session(stdev, st_session, ST_EVENT_START_KEEP_ALIVE);
2172 ALOGD("%s: success, sound_model_handle %d", __func__, st_session->sm_handle);
2173 return 0;
2174
2175exit_3:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002176 if (st_session->phrase_sm != NULL)
2177 free(st_session->phrase_sm);
2178 if (!list_empty(&st_session->second_stage_list))
Quinn Male2e883752019-03-22 11:28:54 -07002179 st_session_ss_deinit(st_session);
2180
2181exit_2:
2182 st_session_deinit(st_session);
2183
2184exit_1:
2185 android_atomic_dec(&stdev->session_id);
2186
2187exit:
2188 if (st_session != NULL) {
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002189 list_for_each_safe(node, tmp_node, &st_session->second_stage_list) {
2190 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
2191 list_remove(&st_sec_stage->list_node);
2192 deallocate_arm_second_stage_session(st_sec_stage);
Quinn Male2e883752019-03-22 11:28:54 -07002193 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002194 if (st_session->hw_proxy_ses &&
2195 st_session->hw_proxy_ses->hw_ses_adsp) {
2196 list_for_each_safe(node, tmp_node,
2197 &st_session->hw_proxy_ses->hw_ses_adsp->lsm_ss_cfg_list) {
2198 st_lsm_ss_config_t *cfg =
2199 node_to_item(node, st_lsm_ss_config_t, list_node);
Quinn Male2e883752019-03-22 11:28:54 -07002200 list_remove(&cfg->list_node);
2201 deallocate_lsm_ss_config(cfg);
2202 }
2203 }
2204 free(st_session);
2205 st_session = NULL;
2206 }
2207 if (handle != NULL)
2208 *handle = -1;
2209 pthread_mutex_unlock(&stdev->lock);
2210 ATRACE_END();
2211 return status;
2212}
2213
2214/* called with stdev lock held */
2215static int stdev_reconfig_backend_on_stop(st_session_t *stopped_ses)
2216{
2217 /*
2218 * Of the remaining sessions, pick the session with the
2219 * best ch_count, rate, format and reconfigure backend according to it.
2220 * Examples
2221 * 1) Assume two sessions are active. S1 is using mono and S2 is using stereo.
2222 * As S2 is using stereo, backend will be configured as stereo.
2223 * If S1 stops, maintain backend as stereo.
2224 * If S2 stops, change backend to mono
2225 * 2) Assume single session S2 (stereo)
2226 * If S2 stops, reset backend to allow a future session (S1) to
2227 * to optimally set the backend at mono.
2228 */
2229 st_session_t *best_ses = NULL;
2230 st_session_t *ses = NULL;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002231 struct listnode *ses_node = NULL;
Quinn Male2e883752019-03-22 11:28:54 -07002232 int ses_channel_count = 0;
2233 int stopped_ses_channel_count = 0;
2234 int best_channel_count = 0;
2235 unsigned int stopped_ses_vad_preroll = 0;
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002236 unsigned int best_vad_preroll = 0, preroll = 0;
Quinn Male2e883752019-03-22 11:28:54 -07002237 bool stopped_ses_lpi_mode = false, is_stopped = false;
2238
2239 if (stopped_ses->exec_mode != ST_EXEC_MODE_ADSP &&
2240 stopped_ses->exec_mode != ST_EXEC_MODE_ARM)
2241 return 0;
2242
2243 is_stopped = (st_session_is_detected(stopped_ses) == false) &&
2244 (st_session_is_active(stopped_ses) == false) &&
2245 (st_session_is_buffering(stopped_ses) == false);
2246
2247 if (!is_stopped || is_any_session_buffering()) {
2248 ALOGW("defer backend reconfig as session not stopped or buffering");
2249 return 0;
2250 }
2251
2252 struct st_vendor_info *stopped_v_info = stopped_ses->vendor_uuid_info;
Quinn Male23026702019-07-19 10:51:16 -07002253 ALOGV("%s:[%d] v_info %p", __func__, stopped_ses->sm_handle, stopped_v_info);
Quinn Male2e883752019-03-22 11:28:54 -07002254
2255 stopped_ses_channel_count =
2256 platform_stdev_get_backend_channel_count(stdev->platform,
2257 stopped_v_info);
2258
2259 if ((stopped_ses->exec_mode == ST_EXEC_MODE_ADSP) &&
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002260 stopped_ses->hw_proxy_ses->hw_ses_adsp) {
2261 stopped_ses_lpi_mode = stopped_ses->hw_proxy_ses->hw_ses_adsp->lpi_enable;
2262 stopped_ses_vad_preroll = st_session_get_preroll(stopped_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002263 }
2264
2265 list_for_each(ses_node, &stdev->sound_model_list) {
2266 ses = node_to_item(ses_node, st_session_t, list_node);
Quinn Male2e883752019-03-22 11:28:54 -07002267 if (ses->exec_mode != ST_EXEC_MODE_ADSP &&
2268 ses->exec_mode != ST_EXEC_MODE_ARM)
2269 continue;
2270 if (ses == stopped_ses) {
2271 ALOGV("ses == stopped_ses, ignore");
2272 continue;
2273 }
2274
2275 is_stopped = (st_session_is_detected(ses) == false) &&
2276 (st_session_is_active(ses) == false) &&
2277 (st_session_is_buffering(ses) == false);
2278 if (is_stopped) {
Quinn Male23026702019-07-19 10:51:16 -07002279 ALOGV("%s:[%d] is stopped, ignore", __func__, ses->sm_handle);
Quinn Male2e883752019-03-22 11:28:54 -07002280 continue;
2281 }
2282
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002283 ses_channel_count =
2284 platform_stdev_get_backend_channel_count(stdev->platform,
2285 ses->vendor_uuid_info);
2286 ALOGV("%s:[%d] check ses_v_info %p", __func__, ses->sm_handle,
2287 ses->vendor_uuid_info);
2288
2289 if (ses->exec_mode == ST_EXEC_MODE_ADSP) {
2290 preroll = st_session_get_preroll(ses);
2291 if (preroll > best_vad_preroll)
2292 best_vad_preroll = preroll;
2293 }
Quinn Male2e883752019-03-22 11:28:54 -07002294
2295 if ((best_ses == NULL) || (ses_channel_count > best_channel_count)) {
2296 best_ses = ses;
2297 best_channel_count = ses_channel_count;
2298 }
2299 }
2300
Quinn Malecc1affd2019-07-18 16:13:31 -07002301 st_hw_check_and_update_lpi(stdev, NULL);
Quinn Male2e883752019-03-22 11:28:54 -07002302 stdev->vad_enable = st_hw_check_vad_support(stdev, best_ses,
2303 stdev->lpi_enable);
2304
2305 /* skip reconfig/reset if any other session still active with best config */
2306 if ((best_ses != NULL) &&
2307 (stopped_ses_channel_count <= best_channel_count) &&
2308 (stopped_ses_lpi_mode == stdev->lpi_enable) &&
2309 (stopped_ses_vad_preroll <= best_vad_preroll)) {
2310 ALOGV("%s: stdev %p skipped reconfig", __func__, stdev);
2311 return 0;
2312 }
2313
2314 if (best_ses) {
2315 platform_stdev_set_codec_backend_cfg(stdev->platform,
2316 best_ses->vendor_uuid_info,
2317 stdev->lpi_enable,
2318 stdev->vad_enable,
2319 best_vad_preroll);
2320 ALOGI("%s:[%d] force changed backend to %d", __func__,
2321 best_ses->sm_handle, best_channel_count);
2322 stop_other_sessions(stdev, stopped_ses);
2323 start_other_sessions(stdev, stopped_ses);
2324 } else {
2325 ALOGI("%s: no session remains, reset to default", __func__);
2326 platform_stdev_reset_backend_cfg(stdev->platform);
2327 }
2328
2329 return 0;
2330}
2331
2332
2333/* to be called with no locks held */
2334static void stdev_session_event_cb(sound_model_handle_t handle,
2335 st_session_event_id_t event)
2336{
2337 pthread_mutex_lock(&stdev->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002338 st_session_t* st_ses = get_sound_trigger_session(stdev, handle);
Quinn Male2e883752019-03-22 11:28:54 -07002339
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002340 if (!st_ses)
Quinn Male2e883752019-03-22 11:28:54 -07002341 goto exit;
2342
2343 ALOGV("%s:[%d] event %d", __func__, handle, event);
2344 switch (event) {
2345 case ST_SES_EV_DEFERRED_STOP:
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002346 if (st_ses->pending_stop)
2347 stop_recognition_l(st_ses);
Quinn Male2e883752019-03-22 11:28:54 -07002348 break;
2349 default:
2350 break;
2351 }
2352exit:
2353 pthread_mutex_unlock(&stdev->lock);
2354}
2355
2356static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
2357 sound_model_handle_t handle)
2358{
2359 struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
2360 st_session_t *st_session = NULL;
2361 int status = 0, ret = 0;
2362 struct listnode *node = NULL, *tmp_node = NULL;
2363 struct st_arm_second_stage *st_sec_stage = NULL;
2364
2365 ALOGD("%s:[%d] Enter", __func__, handle);
2366 ATRACE_BEGIN("sthal: stdev_unload_sound_model");
2367
2368 pthread_mutex_lock(&stdev->lock);
2369 if (handle == stdev->lpma_handle) {
2370 status = sthw_extn_lpma_notify_event(LPMA_EVENT_STOP);
2371 stdev->lpma_handle = -1;
2372 pthread_mutex_unlock(&stdev->lock);
2373 ATRACE_END();
2374 ALOGD("%s: lpma exit status %d", __func__, status);
2375 return status;
2376 }
2377
2378 st_session = get_sound_trigger_session(stdev, handle);
2379 if (!st_session) {
2380 ALOGE("%s: Could not find sound model %d", __func__, handle);
2381 ret = -EINVAL;
2382 goto exit;
2383 }
2384
Quinn Male2bfe13b2020-08-27 16:53:51 -07002385 ALOGD("%s:[%d] fs detections: %d, ss detections: %d, ss rejections: %d",
2386 __func__, handle, st_session->fs_det_count, st_session->ss_det_count,
2387 st_session->ss_rej_count);
2388
Quinn Male2e883752019-03-22 11:28:54 -07002389 if (st_session->callback) {
2390 status = stop_recognition_l(st_session);
2391 if (status) {
2392 ALOGE("%s:[%d] Failed to stop recognition, status %d", __func__,
2393 handle, status);
2394 ret = status;
2395 }
2396 }
2397
2398 status = st_session_unload_sm(st_session);
2399 if (status) {
2400 ALOGE("%s:[%d] Failed to unload sound model, status %d", __func__,
2401 handle, status);
2402 ret = status;
2403 }
2404
2405 list_remove(&st_session->list_node);
2406
2407 if (st_session->sm_type == SOUND_MODEL_TYPE_KEYPHRASE)
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002408 update_available_phrase_info(st_session, st_session->phrase_sm, true);
Quinn Male2e883752019-03-22 11:28:54 -07002409
2410 if (!get_num_sessions())
2411 stdev->exec_mode = ST_EXEC_MODE_NONE;
2412
2413 pthread_mutex_lock(&st_session->lock);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002414 free(st_session->phrase_sm);
Quinn Male2e883752019-03-22 11:28:54 -07002415 pthread_mutex_unlock(&st_session->lock);
2416
2417 run_keep_alive_session(stdev, st_session, ST_EVENT_STOP_KEEP_ALIVE);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002418 if (!list_empty(&st_session->second_stage_list)) {
Quinn Male2e883752019-03-22 11:28:54 -07002419 st_session_ss_deinit(st_session);
2420 list_for_each_safe(node, tmp_node, &st_session->second_stage_list) {
2421 st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
2422 list_remove(&st_sec_stage->list_node);
2423 deallocate_arm_second_stage_session(st_sec_stage);
2424 }
2425 }
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002426 if (st_session && st_session->hw_proxy_ses->hw_ses_adsp) {
2427 list_for_each_safe(node, tmp_node,
2428 &st_session->hw_proxy_ses->hw_ses_adsp->lsm_ss_cfg_list) {
2429 st_lsm_ss_config_t *cfg =
2430 node_to_item(node, st_lsm_ss_config_t, list_node);
Quinn Male2e883752019-03-22 11:28:54 -07002431 list_remove(&cfg->list_node);
2432 deallocate_lsm_ss_config(cfg);
2433 }
2434 }
2435 st_session_deinit(st_session);
2436
2437 free(st_session);
2438
2439exit:
2440 pthread_mutex_unlock(&stdev->lock);
2441 ATRACE_END();
2442 ALOGD("%s: Exit status %d", __func__, ret);
2443 return ret;
2444}
2445
2446static int stdev_start_recognition
2447(
2448 const struct sound_trigger_hw_device *dev,
2449 sound_model_handle_t sound_model_handle,
2450 const struct sound_trigger_recognition_config *config,
2451 recognition_callback_t callback,
2452 void *cookie
2453)
2454{
2455 struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
2456 st_session_t *st_session = NULL;
2457 int status = 0;
2458 bool config_updated = false;
2459 bool backend_cfg_change = false;
2460
2461 ALOGD("%s:[%d] Enter", __func__, sound_model_handle);
2462 ATRACE_BEGIN("sthal: stdev_start_recognition");
2463
2464 pthread_mutex_lock(&stdev->lock);
2465
2466 if (!callback || !config) {
2467 ALOGE("%s: ERROR. NULL params", __func__);
2468 status = -EINVAL;
2469 goto exit;
2470 }
2471
2472 st_session = get_sound_trigger_session(stdev, sound_model_handle);
2473 if (!st_session) {
2474 ALOGE("%s: ERROR. Could not find session for sound model %d", __func__,
2475 sound_model_handle);
2476 status = -EINVAL;
2477 goto exit;
2478 }
2479
2480 ALOGV("%s:[%d] About to take session lock", __func__, sound_model_handle);
Quinn Male2e883752019-03-22 11:28:54 -07002481 pthread_mutex_lock(&st_session->lock);
Quinn Male2e883752019-03-22 11:28:54 -07002482 if (!st_session->rc_config ||
2483 !compare_recognition_config(config, st_session->rc_config)) {
2484 config_updated = true;
2485
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002486 ALOGV("%s:[%d] received new params ", __func__, st_session->sm_handle);
Quinn Male2e883752019-03-22 11:28:54 -07002487
2488 /*
2489 * Store the recogntion configuration for sending opaque data
2490 * and for SSR, passing to sounmodel wrapper library.
2491 */
2492 if (st_session->rc_config)
2493 free(st_session->rc_config);
2494
2495 /*
2496 * 2nd stage sessions require SVA 3.0 opaque data. This check prevents
2497 * the session from being active with the wrong settings.
2498 */
2499 if ((config->data_size <= CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
2500 st_session->vendor_uuid_info->is_qcva_uuid &&
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002501 !list_empty(&st_session->second_stage_list)) {
2502 ALOGE("%s: SVA 3.0 rc_config opaque data required, exiting",
2503 __func__);
Quinn Male2e883752019-03-22 11:28:54 -07002504 status = -EINVAL;
2505 goto cleanup;
2506 }
2507
2508 st_session->rc_config = calloc(1, sizeof(*config) + config->data_size);
2509 if (!st_session->rc_config) {
2510 ALOGE("%s: No memory for rc_config", __func__);
2511 status = -ENOMEM;
2512 goto cleanup;
2513 }
2514
2515 memcpy(st_session->rc_config, (char *)config, sizeof(*config));
Harshal Ahire89337992020-07-13 02:38:14 +05302516
2517 /*
2518 * SOUND_TRIGGER_DEVICE_API_VERSION_1_3 version introduced new strucutre
2519 * sound_trigger_recognition_config_extended_1_3 containing header and base,
2520 * so the data_offset for opaque data is relative to this new structure,
2521 * leading to extra 12 bytes (8 bytes for header and 4 bytes for audio_capabilities)
2522 * w.r.t recoginition config structure. So the extra bytes need to be subtracted
2523 * from the data_offset passed considering new strucutre. Opaque data starts after
2524 * audio_capabilities variable in sound_trigger_recognition_config_extended_1_3
2525 */
2526 if (hw_properties_extended.header.version == SOUND_TRIGGER_DEVICE_API_VERSION_1_3) {
2527 st_session->rc_config->data_offset -= (sizeof(struct sound_trigger_recognition_config_header) +
2528 sizeof(uint32_t));
2529
2530 memcpy((char *)st_session->rc_config + st_session->rc_config->data_offset,
2531 (char *)config + config->data_offset -
2532 sizeof(struct sound_trigger_recognition_config_header),
2533 config->data_size);
2534 } else {
2535 memcpy((char *)st_session->rc_config + st_session->rc_config->data_offset,
2536 (char *)config + config->data_offset, config->data_size);
2537 }
Quinn Male2e883752019-03-22 11:28:54 -07002538
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002539 ALOGVV("%s: num_phrases=%d, id=%d", __func__,
2540 st_session->rc_config->num_phrases,
Quinn Male2e883752019-03-22 11:28:54 -07002541 st_session->rc_config->phrases[0].id);
2542 st_session->callback = callback;
2543 st_session->cookie = cookie;
2544 /* capture_handle will be shared with AHAL for reading LAB data */
2545 st_session->capture_handle = config->capture_handle;
2546 st_session->capture_requested = config->capture_requested;
2547
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002548 /*
2549 * Must be called before lpi decision with updated config:
2550 * preroll, client requested mode etc..
2551 */
2552 status = st_session_update_recongition_config(st_session);
Quinn Male2e883752019-03-22 11:28:54 -07002553 if (status) {
2554 ALOGE("%s: ERROR. updating rc_config, returned status %d",
2555 __func__, status);
2556 goto cleanup;
2557 }
2558 }
2559
2560 if (ST_EXEC_MODE_ADSP == st_session->exec_mode ||
2561 ST_EXEC_MODE_ARM == st_session->exec_mode) {
Quinn Malecc1affd2019-07-18 16:13:31 -07002562 st_hw_check_and_update_lpi(stdev, st_session);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002563 stdev->vad_enable = st_hw_check_vad_support(stdev, st_session,
2564 stdev->lpi_enable);
2565 int vad_preroll = st_session_get_preroll(st_session);
Quinn Male2e883752019-03-22 11:28:54 -07002566
2567 status = platform_stdev_check_and_set_codec_backend_cfg(stdev->platform,
2568 st_session->vendor_uuid_info, &backend_cfg_change,
2569 stdev->lpi_enable, stdev->vad_enable, vad_preroll);
2570 if (status) {
2571 ALOGE("%s: ERROR. codec backend config update failed", __func__);
2572 goto cleanup;
2573 }
2574
2575 if (backend_cfg_change) {
2576 /*
2577 * If backend config change because of this session, stop and start
2578 * existing sessions.
2579 * This will ensure existing sessions are routed with same updated
2580 * codec backend configuration.
2581 * set config_updated to true so that current session is also stopped
2582 * and started to reflect configuration update.
2583 */
2584 ALOGV("%s: backend config change, stop existing sessions", __func__);
2585 stop_other_sessions(stdev, st_session);
2586 config_updated = true;
2587 }
2588 }
2589
2590 /*
2591 * Check if there is any change in config, if not issue restart event
2592 * to state machine
2593 */
2594 if (config_updated)
2595 status = st_session_start(st_session);
2596 else
2597 status = st_session_restart(st_session);
2598
Zhou Song900ffd92020-06-04 17:49:50 +08002599 if (status) {
2600 /*
2601 * still return success to sound trigger service, as session
2602 * can be resumed internally due to SSR or PDR
2603 */
2604 status = 0;
Quinn Male2e883752019-03-22 11:28:54 -07002605 ALOGE("%s: failed to (re)start session", __func__);
Zhou Song900ffd92020-06-04 17:49:50 +08002606 }
Quinn Male2e883752019-03-22 11:28:54 -07002607
2608 if (backend_cfg_change) {
2609 ALOGV("%s: backend config change, start existing sessions", __func__);
2610 start_other_sessions(stdev, st_session);
2611 }
2612
2613 /* Switch session to high performance/low power mode if requested by APP */
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002614 if ((ST_EXEC_MODE_CPE == st_session->exec_mode) &&
2615 (ST_DET_HIGH_PERF_MODE == st_session->client_req_det_mode))
Quinn Male2e883752019-03-22 11:28:54 -07002616 check_and_transit_cpe_ses_to_ape(st_session);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002617 else if ((ST_EXEC_MODE_ADSP == st_session->exec_mode) &&
2618 (ST_DET_LOW_POWER_MODE == st_session->client_req_det_mode))
Quinn Male2e883752019-03-22 11:28:54 -07002619 check_and_transit_ape_ses_to_cpe(st_session);
2620
2621cleanup:
2622 pthread_mutex_unlock(&st_session->lock);
2623
2624exit:
2625 pthread_mutex_unlock(&stdev->lock);
2626 ATRACE_END();
2627 ALOGD("%s:[%d] Exit", __func__, sound_model_handle);
2628 return status;
2629}
2630
Harshal Ahire89337992020-07-13 02:38:14 +05302631static int stdev_start_recognition_extended
2632(
2633 const struct sound_trigger_hw_device *dev,
2634 sound_model_handle_t sound_model_handle,
2635 const struct sound_trigger_recognition_config_header *config,
2636 recognition_callback_t callback,
2637 void *cookie
2638)
2639{
2640 return stdev_start_recognition(dev, sound_model_handle,
2641 &((struct sound_trigger_recognition_config_extended_1_3 *)config)->base,
2642 callback, cookie);
2643
2644}
2645
Quinn Male2e883752019-03-22 11:28:54 -07002646static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev,
2647 sound_model_handle_t sound_model_handle)
2648{
2649 struct sound_trigger_device *stdev = (struct sound_trigger_device *)dev;
2650 struct st_session *st_session = NULL;
2651 int status = 0;
2652
2653 ALOGD("%s:[%d] Enter", __func__, sound_model_handle);
2654 ATRACE_BEGIN("sthal: stdev_stop_recognition");
2655
2656 pthread_mutex_lock(&stdev->lock);
2657
2658 st_session = get_sound_trigger_session(stdev, sound_model_handle);
2659 if (st_session == NULL) {
2660 ATRACE_END();
2661 ALOGE("%s: Could not find sound model %d", __func__, sound_model_handle);
2662 status = -EINVAL;
2663 pthread_mutex_unlock(&stdev->lock);
2664 return status;
2665 }
2666
2667 /* If ftrt processing loop in progress, indicate to exit
2668 before acquiring the lock here */
2669 status = stop_recognition_l(st_session);
2670
2671 pthread_mutex_unlock(&stdev->lock);
2672 ATRACE_END();
2673 ALOGD("%s:[%d] Exit status %d", __func__, sound_model_handle, status);
2674 return status;
2675}
2676
2677static int stdev_close(hw_device_t *device)
2678{
Quinn Male9c4f7932020-04-21 16:15:03 -07002679 struct sound_trigger_device *st_device =
2680 (struct sound_trigger_device *)device;
Quinn Male2e883752019-03-22 11:28:54 -07002681 st_session_t *st_session = NULL;
2682 struct listnode *node = NULL, *tmp_node = NULL;
2683 int status = 0;
2684
2685 ALOGD("%s: count=%d", __func__, stdev_ref_cnt);
2686 ATRACE_BEGIN("sthal: stdev_close");
2687
2688 pthread_mutex_lock(&stdev_init_lock);
Quinn Male9c4f7932020-04-21 16:15:03 -07002689 if (!st_device || (--stdev_ref_cnt != 0)) {
Quinn Male2e883752019-03-22 11:28:54 -07002690 goto exit;
2691 }
2692
Quinn Male9c4f7932020-04-21 16:15:03 -07002693 pthread_mutex_lock(&st_device->lock);
Quinn Male2e883752019-03-22 11:28:54 -07002694 sthw_extn_lpma_deinit();
Quinn Male9c4f7932020-04-21 16:15:03 -07002695 platform_stdev_deinit(st_device->platform);
2696 free(st_device->arm_pcm_use_cases);
2697 free(st_device->ape_pcm_use_cases);
2698 free(st_device->dev_ref_cnt);
2699 free(st_device->dev_enable_cnt);
2700 list_for_each_safe(node, tmp_node, &st_device->sound_model_list) {
Quinn Male2e883752019-03-22 11:28:54 -07002701 st_session = node_to_item(node, st_session_t, list_node);
2702 list_remove(node);
2703 st_session_stop_lab(st_session);
2704 st_session_stop(st_session);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002705 if (!list_empty(&st_session->second_stage_list))
Quinn Male2e883752019-03-22 11:28:54 -07002706 st_session_ss_deinit(st_session);
2707 st_session_deinit(st_session);
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07002708 free(st_session->phrase_sm);
Quinn Male2e883752019-03-22 11:28:54 -07002709 free(st_session->rc_config);
2710 free(st_session);
2711 }
2712
Quinn Male9c4f7932020-04-21 16:15:03 -07002713 pthread_mutex_unlock(&st_device->lock);
Quinn Male2e883752019-03-22 11:28:54 -07002714 hw_session_notifier_deinit();
2715
Quinn Male9c4f7932020-04-21 16:15:03 -07002716 if (st_device->transit_to_adsp_on_playback ||
2717 st_device->transit_to_adsp_on_battery_charging) {
2718 st_device->stop_transitions_thread_loop = true;
2719 pthread_cond_signal(&st_device->transitions_cond);
2720 status = pthread_join(st_device->transitions_thread, NULL);
Quinn Male2e883752019-03-22 11:28:54 -07002721 if (status)
2722 ALOGE("%s: Error joining transitions thread. status = %d",
2723 __func__, status);
2724 }
2725
Quinn Male9c4f7932020-04-21 16:15:03 -07002726 pthread_mutex_destroy(&st_device->lock);
2727 pthread_mutex_destroy(&st_device->ref_cnt_lock);
Quinn Male2e883752019-03-22 11:28:54 -07002728 free(device);
2729 stdev = NULL;
2730
2731exit:
2732 pthread_mutex_unlock(&stdev_init_lock);
2733 ATRACE_END();
Quinn Male9c4f7932020-04-21 16:15:03 -07002734 ALOGD("%s: Exit device=%p cnt=%d ", __func__, st_device,
2735 stdev_ref_cnt);
Quinn Male2e883752019-03-22 11:28:54 -07002736 return 0;
2737}
2738
Harshal Ahire89337992020-07-13 02:38:14 +05302739static int stdev_stop_all_recognitions(const struct sound_trigger_hw_device* dev __unused)
2740{
2741 ALOGV("%s: unsupported API", __func__);
2742 return -ENOSYS;
2743}
2744
2745static int stdev_get_parameter(const struct sound_trigger_hw_device *dev __unused,
2746 sound_model_handle_t sound_model_handle __unused,
2747 sound_trigger_model_parameter_t model_param __unused, int32_t* value __unused)
2748{
2749 ALOGV("%s: unsupported API", __func__);
2750 return -EINVAL;
2751}
2752
2753static int stdev_set_parameter(const struct sound_trigger_hw_device *dev __unused,
2754 sound_model_handle_t sound_model_handle __unused,
2755 sound_trigger_model_parameter_t model_param __unused, int32_t value __unused)
2756{
2757 ALOGV("%s: unsupported API", __func__);
2758 return -EINVAL;
2759}
2760
2761static int stdev_query_parameter(const struct sound_trigger_hw_device *dev __unused,
2762 sound_model_handle_t sound_model_handle __unused,
2763 sound_trigger_model_parameter_t model_param __unused,
2764 sound_trigger_model_parameter_range_t* param_range)
2765{
2766 if (param_range)
2767 param_range->is_supported = false;
2768 return 0;
2769}
2770
2771static const struct sound_trigger_properties_header*
2772stdev_get_properties_extended(const struct sound_trigger_hw_device *dev)
2773{
2774 struct st_vendor_info *v_info = NULL;
2775 struct listnode *v_node = NULL;
2776 struct sound_trigger_device *stdev = NULL;
2777 sound_model_handle_t handle = 0;
2778 st_session_t *st_session = NULL;
2779 struct sound_trigger_properties_header *prop_hdr = NULL;
2780 int status = 0;
2781
2782 ALOGI("%s: enter", __func__);
2783
2784 if (!dev) {
2785 ALOGW("%s: invalid sound_trigger_hw_device received", __func__);
2786 return NULL;
2787 }
2788
2789 stdev = (struct sound_trigger_device *)dev;
2790 prop_hdr = (struct sound_trigger_properties_header *)&hw_properties_extended;
Quinn Malee51cc9c2020-09-10 13:59:29 -07002791 get_base_properties(stdev);
2792
Harshal Ahire89337992020-07-13 02:38:14 +05302793 hw_properties_extended.header.size = sizeof(struct sound_trigger_properties_extended_1_3);
2794 hw_properties_extended.audio_capabilities = 0;
2795 hw_properties_extended.header.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_3;
2796
2797 /*
2798 * The below code is to get hotword algo version from ADSP. In case of any
2799 * errors in getting the version, return base properties as its not harmful
2800 * to bail out STHAL feature with version failure.
2801 */
2802
2803 pthread_mutex_lock(&stdev->lock);
2804 if (!CHECK_BIT(stdev->hw_type,
2805 ST_DEVICE_HW_APE|ST_DEVICE_HW_CPE|ST_DEVICE_HW_ARM)) {
2806 status = platform_stdev_get_hw_type(stdev->platform);
2807 if (status) {
2808 ALOGW("%s: get hw type failed, %d", __func__, status);
2809 goto exit_2;
2810 }
2811 }
2812 list_for_each(v_node, &stdev->vendor_uuid_list) {
2813 v_info = node_to_item(v_node, struct st_vendor_info, list_node);
2814 if (v_info->get_module_version) {
2815 st_session = calloc(1, sizeof(st_session_t));
2816 if (!st_session) {
2817 ALOGW("%s: st_session allocation failed", __func__);
2818 goto exit_2;
2819 }
2820
Harshal Ahiref4495352020-09-26 04:09:53 +05302821 st_session->f_stage_version = ST_MODULE_TYPE_GMM;
Harshal Ahire89337992020-07-13 02:38:14 +05302822 st_session->vendor_uuid_info = v_info;
2823 handle = android_atomic_inc(&stdev->session_id);
2824
2825 status = st_session_init(st_session, stdev, ST_EXEC_MODE_ADSP, handle);
2826 if (status) {
2827 ALOGW("%s: failed to initialize st_session with error %d", __func__,
2828 status);
2829 goto exit_1;
2830 }
2831
2832 status = st_session_get_module_version(st_session, hw_properties_extended.supported_model_arch);
2833 if (status) {
2834 ALOGW("%s: failed to get module version with error %d", __func__,
2835 status);
2836 goto exit;
2837 }
2838 ALOGV("%s: version is %s", __func__, hw_properties_extended.supported_model_arch);
2839 break;
2840 }
2841 }
2842
2843 pthread_mutex_unlock(&stdev->lock);
2844 return prop_hdr;
2845
2846exit:
2847 st_session_deinit(st_session);
2848
2849exit_1:
2850 android_atomic_dec(&stdev->session_id);
2851 free(st_session);
2852 st_session = NULL;
2853
2854exit_2:
2855 pthread_mutex_unlock(&stdev->lock);
2856 return prop_hdr;
2857}
2858
Quinn Male2e883752019-03-22 11:28:54 -07002859static int stdev_open(const hw_module_t* module, const char* name,
2860 hw_device_t** device)
2861{
2862 int status = 0;
2863
2864 ALOGD("%s: Enter", __func__);
2865 ATRACE_BEGIN("sthal: stdev_open");
2866
2867 if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0) {
2868 ALOGE("%s: ERROR. wrong interface", __func__);
2869 status = -EINVAL;
2870 goto exit;
2871 }
2872
2873 pthread_mutex_lock(&stdev_init_lock);
2874 if (stdev_ref_cnt != 0) {
2875 *device = &stdev->device.common;
2876 stdev_ref_cnt++;
2877 ATRACE_END();
2878 ALOGD("%s: returning existing stdev instance, exit", __func__);
2879 pthread_mutex_unlock(&stdev_init_lock);
2880 return status;
2881 }
2882
2883 stdev = calloc(1, sizeof(struct sound_trigger_device));
2884 if (!stdev) {
2885 ALOGE("%s: ERROR. stdev alloc failed", __func__);
2886 status = -ENOMEM;
2887 goto exit;
2888 }
2889
2890 stdev->hw_properties = &hw_properties;
2891
2892 status = load_audio_hal();
2893 if (status)
2894 goto exit;
2895
2896 stdev->platform = platform_stdev_init(stdev);
2897 if (!stdev->platform) {
2898 ALOGE("%s: ERROR. platform init failed", __func__);
2899 status = -ENODEV;
2900 goto exit_1;
2901 }
2902
2903 stdev->ape_pcm_use_cases =
2904 calloc(stdev->max_ape_sessions, sizeof(struct use_case_info));
2905
2906 if (!stdev->ape_pcm_use_cases) {
2907 ALOGE("%s: ERROR. Mem alloc failed for ape use cases", __func__);
2908 status = -ENODEV;
2909 goto exit_1;
2910 }
2911
Quinn Male2e883752019-03-22 11:28:54 -07002912 /* Each arm session is associated with corresponding ec ref session */
2913 stdev->arm_pcm_use_cases =
2914 calloc(stdev->max_arm_sessions * 2, sizeof(struct use_case_info));
2915
2916 if (!stdev->arm_pcm_use_cases) {
2917 ALOGE("%s: ERROR. Mem alloc failed for capture use cases", __func__);
2918 status = -ENODEV;
2919 goto exit_1;
2920 }
2921
2922 stdev->dev_ref_cnt =
2923 calloc(ST_EXEC_MODE_MAX * ST_DEVICE_MAX, sizeof(int));
2924
2925 if (!stdev->dev_ref_cnt) {
2926 ALOGE("%s: ERROR. Mem alloc failed dev ref cnt", __func__);
2927 status = -ENOMEM;
2928 goto exit_1;
2929 }
2930
Quinn Maledd105082019-11-07 18:36:02 -08002931 stdev->dev_enable_cnt =
2932 calloc(ST_EXEC_MODE_MAX * ST_DEVICE_MAX, sizeof(int));
2933
2934 if (!stdev->dev_enable_cnt) {
2935 ALOGE("%s: ERROR. Mem alloc failed dev enable cnt", __func__);
2936 status = -ENOMEM;
2937 goto exit_1;
2938 }
2939
Quinn Male2e883752019-03-22 11:28:54 -07002940 if (hw_session_notifier_init(stdev_session_event_cb) < 0) {
2941 ALOGE("%s: Failed to initialize notifier", __func__);
2942 status = -ENOMEM;
2943 goto exit_1;
2944 }
2945
2946 stdev->device.common.tag = HARDWARE_DEVICE_TAG;
Harshal Ahire89337992020-07-13 02:38:14 +05302947 stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_3;
Quinn Male2e883752019-03-22 11:28:54 -07002948 stdev->device.common.module = (struct hw_module_t *) module;
2949 stdev->device.common.close = stdev_close;
2950 stdev->device.get_properties = stdev_get_properties;
2951 stdev->device.load_sound_model = stdev_load_sound_model;
2952 stdev->device.unload_sound_model = stdev_unload_sound_model;
2953 stdev->device.start_recognition = stdev_start_recognition;
2954 stdev->device.stop_recognition = stdev_stop_recognition;
Harshal Ahire89337992020-07-13 02:38:14 +05302955 stdev->device.get_properties_extended = stdev_get_properties_extended;
2956 stdev->device.start_recognition_extended = stdev_start_recognition_extended;
2957 stdev->device.stop_all_recognitions = stdev_stop_all_recognitions;
2958 stdev->device.get_parameter = stdev_get_parameter;
2959 stdev->device.set_parameter = stdev_set_parameter;
2960 stdev->device.query_parameter = stdev_query_parameter;
2961
Quinn Male2e883752019-03-22 11:28:54 -07002962#ifdef ST_SUPPORT_GET_MODEL_STATE
2963 stdev->device.get_model_state = stdev_get_model_state;
2964#endif
2965 stdev->session_id = 1;
2966 stdev->gcs_token = 1;
2967 stdev->exec_mode = ST_EXEC_MODE_MAX;
Quinn Male2e883752019-03-22 11:28:54 -07002968 stdev->client_req_exec_mode = ST_EXEC_MODE_NONE;
Quinn Maled409e412019-12-09 14:50:48 -08002969 list_init(&stdev->available_devices);
2970 platform_stdev_update_device_list(AUDIO_DEVICE_IN_BUILTIN_MIC, "",
2971 &stdev->available_devices, true);
2972 list_init(&stdev->ec_ref_dev_list);
2973 platform_stdev_update_device_list(AUDIO_DEVICE_OUT_SPEAKER, "",
2974 &stdev->ec_ref_dev_list, true);
2975 list_init(&stdev->active_rx_dev_list);
2976 platform_stdev_update_device_list(AUDIO_DEVICE_OUT_SPEAKER, "",
2977 &stdev->active_rx_dev_list, true);
Quinn Male2e883752019-03-22 11:28:54 -07002978 stdev->session_allowed = true;
2979 stdev->reset_backend = true;
2980 stdev->conc_voice_active = false;
2981 stdev->conc_voip_active = false;
2982 stdev->lpma_handle = -1;
2983 stdev->is_charging = false;
2984 stdev->lpi_enable = false;
2985 stdev->vad_enable = false;
2986 stdev->audio_ec_enabled = false;
2987
2988 pthread_mutex_init(&stdev->lock, (const pthread_mutexattr_t *) NULL);
2989 pthread_mutex_init(&stdev->ref_cnt_lock, (const pthread_mutexattr_t*)NULL);
2990 list_init(&stdev->sound_model_list);
2991
2992 if (stdev->transit_to_adsp_on_playback ||
2993 stdev->transit_to_adsp_on_battery_charging)
2994 init_transitions_thread();
2995
2996 sthw_extn_lpma_init(stdev);
2997 dbg_trace_parse_max_lab_reads(); /*For trace log control*/
2998 *device = &stdev->device.common;
2999 stdev_ref_cnt++;
3000 pthread_mutex_unlock(&stdev_init_lock);
3001
Quinn Malee51cc9c2020-09-10 13:59:29 -07003002 get_base_properties(stdev);
3003 hw_properties_extended.header.size = sizeof(struct sound_trigger_properties_extended_1_3);
3004 hw_properties_extended.audio_capabilities = 0;
3005 hw_properties_extended.header.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_3;
3006
Quinn Male2e883752019-03-22 11:28:54 -07003007 ATRACE_END();
3008 return 0;
3009
3010exit_1:
3011 if (stdev->dev_ref_cnt)
3012 free(stdev->dev_ref_cnt);
3013
Quinn Maledd105082019-11-07 18:36:02 -08003014 if (stdev->dev_enable_cnt)
3015 free(stdev->dev_enable_cnt);
3016
Quinn Male2e883752019-03-22 11:28:54 -07003017 if (stdev->arm_pcm_use_cases)
3018 free(stdev->arm_pcm_use_cases);
3019
Quinn Male2e883752019-03-22 11:28:54 -07003020 if (stdev->ape_pcm_use_cases)
3021 free(stdev->ape_pcm_use_cases);
3022
3023 if (stdev->audio_hal_handle)
3024 dlclose(stdev->audio_hal_handle);
3025
3026 if (stdev->platform)
3027 platform_stdev_deinit(stdev->platform);
3028
3029exit:
3030
3031 if (stdev)
3032 free(stdev);
3033 stdev = NULL;
3034 *device = NULL;
3035
3036 pthread_mutex_unlock(&stdev_init_lock);
3037 ATRACE_END();
3038 ALOGD("%s: Exit status %d", __func__, status);
3039 return status;
3040}
3041
3042static int stdev_get_param_data(st_session_t *p_ses, audio_event_info_t* config)
3043{
3044 qsthw_get_param_payload_t payload;
3045 size_t payload_size = sizeof(qsthw_get_param_payload_t);
3046 size_t param_data_size;
3047 int ret = 0;
3048 char value[128] = "";
3049
3050 ret = st_session_get_param_data(p_ses, config->u.st_get_param_data.param,
3051 (void *)&payload, payload_size, &param_data_size);
3052 if (ret) {
3053 ALOGE("%s: ERROR. fetching get param data %d", __func__, ret);
3054 return ret;
3055 }
3056 if (!strncmp(config->u.st_get_param_data.param, QSTHW_PARAMETER_CHANNEL_INDEX,
3057 sizeof(QSTHW_PARAMETER_CHANNEL_INDEX))) {
3058 struct qsthw_target_channel_index_param ch_index_params =
3059 payload.ch_index_params;
3060 if (param_data_size != sizeof(struct qsthw_target_channel_index_param)) {
3061 ALOGE("%s: ERROR. Invalid param data size returned %zd",
3062 __func__, param_data_size);
3063 return -EINVAL;
3064 }
3065 ALOGD("%s: target channel index - [%d]", __func__,
3066 ch_index_params.target_chan_idx);
3067 str_parms_add_int(config->u.st_get_param_data.reply,
3068 QSTHW_PARAMETER_CHANNEL_INDEX, ch_index_params.target_chan_idx);
3069 } else if (!strncmp(config->u.st_get_param_data.param, QSTHW_PARAMETER_DIRECTION_OF_ARRIVAL,
3070 sizeof(QSTHW_PARAMETER_DIRECTION_OF_ARRIVAL))) {
3071 struct qsthw_source_tracking_param st_params = payload.st_params;
3072 if (param_data_size != sizeof(struct qsthw_source_tracking_param)) {
3073 ALOGE("%s: ERROR. Invalid param data size returned %zd",
3074 __func__, param_data_size);
3075 return -EINVAL;
3076 }
3077 ALOGD("%s: target angle boundaries [%d, %d]\n", __func__,
3078 st_params.target_angle_L16[0], st_params.target_angle_L16[1]);
3079 ALOGD("%s: interference angle boundaries [%d, %d]\n", __func__,
3080 st_params.interf_angle_L16[0], st_params.interf_angle_L16[1]);
3081 /*
3082 * To Do: Send polarActivityGUI data also to client
3083 */
3084 snprintf(value, sizeof(value), "target_angle: [%d, %d], interf_angle :[%d, %d]",
3085 st_params.target_angle_L16[0], st_params.target_angle_L16[0],
3086 st_params.interf_angle_L16[0], st_params.interf_angle_L16[0]);
3087 str_parms_add_str(config->u.st_get_param_data.reply,
3088 QSTHW_PARAMETER_DIRECTION_OF_ARRIVAL, value);
3089 } else {
3090 ALOGE("%s: Invalid get param", __func__);
3091 }
3092 return ret;
3093}
3094
Venkatesh Mangalappalie4f17532019-06-04 16:30:28 -07003095/*
3096 * Audio hal calls this callback for notifying Subsystem restart,
3097 * lab stop and concurrency events
3098 */
Quinn Male2e883752019-03-22 11:28:54 -07003099int sound_trigger_hw_call_back(audio_event_type_t event,
3100 audio_event_info_t* config)
3101{
3102 struct listnode *p_ses_node = NULL;
3103 st_session_t *p_ses = NULL;
3104 int ret = 0;
3105 size_t bytes_read = 0;
3106 st_exec_mode_t exec_mode = 0;
3107 sound_model_handle_t sm_handle = 0;
3108
Quinn Male9c4f7932020-04-21 16:15:03 -07003109 pthread_mutex_lock(&stdev_init_lock);
3110 if (!stdev) {
3111 pthread_mutex_unlock(&stdev_init_lock);
Quinn Male2e883752019-03-22 11:28:54 -07003112 return -ENODEV;
Quinn Male9c4f7932020-04-21 16:15:03 -07003113 }
Quinn Male2e883752019-03-22 11:28:54 -07003114
3115 switch (event) {
3116 case AUDIO_EVENT_PLAYBACK_STREAM_INACTIVE:
3117 case AUDIO_EVENT_PLAYBACK_STREAM_ACTIVE:
3118 ATRACE_BEGIN("sthal: handle_echo_ref_switch");
3119 handle_echo_ref_switch(event, config);
3120 ATRACE_END();
3121 /* fall through */
3122 case AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE:
3123 case AUDIO_EVENT_CAPTURE_DEVICE_ACTIVE:
3124 ATRACE_BEGIN("sthal: handle_audio_concurrency");
3125 handle_audio_concurrency(event, config);
3126 ATRACE_END();
3127 break;
3128
3129 case AUDIO_EVENT_CAPTURE_STREAM_INACTIVE:
3130 case AUDIO_EVENT_CAPTURE_STREAM_ACTIVE:
3131 if (!config) {
3132 ALOGE("%s: NULL capture stream event config", __func__);
3133 ret = -EINVAL;
3134 } else {
3135 handle_audio_concurrency(event, config);
3136 }
3137 break;
3138
3139 case AUDIO_EVENT_UPDATE_ECHO_REF:
3140 handle_audio_ec_ref_enabled(config);
3141 break;
3142
3143 case AUDIO_EVENT_STOP_LAB:
3144 if (!config || !config->u.ses_info.p_ses) {
3145 ALOGE("%s: NULL params for stop lab", __func__);
3146 ret = -EINVAL;
3147 break;
3148 }
3149 ATRACE_BEGIN("sthal: event_stop_lab");
3150 p_ses = config->u.ses_info.p_ses;
3151 pthread_mutex_lock(&stdev->lock);
3152
3153 /* check capture_handle to ensure pointer sanity */
3154 list_for_each(p_ses_node, &stdev->sound_model_list) {
3155 p_ses = node_to_item(p_ses_node, st_session_t, list_node);
3156 if (p_ses->capture_handle == config->u.ses_info.capture_handle) {
3157 st_session_stop_lab(p_ses);
3158 break;
3159 }
3160 }
3161 pthread_mutex_unlock(&stdev->lock);
3162 ATRACE_END();
3163 break;
3164
3165 case AUDIO_EVENT_SSR:
3166 if (!config) {
3167 ALOGE("%s: NULL config for SSR", __func__);
3168 ret = -EINVAL;
3169 break;
3170 }
3171
3172 if ((config->u.status == SND_CARD_STATUS_OFFLINE) ||
3173 (config->u.status == CPE_STATUS_OFFLINE) ||
3174 (config->u.status == SLPI_STATUS_OFFLINE))
3175 handle_ssr_offline(config->u.status);
3176
3177 if ((config->u.status == SND_CARD_STATUS_ONLINE) ||
3178 (config->u.status == CPE_STATUS_ONLINE) ||
3179 (config->u.status == SLPI_STATUS_ONLINE))
3180 handle_ssr_online(config->u.status);
3181 break;
3182
3183 case AUDIO_EVENT_NUM_ST_SESSIONS:
3184 if (!config) {
3185 ALOGE("%s: NULL config for AUDIO_EVENT_NUM_ST_SESSIONS", __func__);
3186 ret = -EINVAL;
3187 break;
3188 }
3189 pthread_mutex_lock(&stdev->lock);
3190 ALOGV("%s: num sessions configured %d", __func__, config->u.value);
3191 stdev->num_sessions_configured = config->u.value;
3192 pthread_mutex_unlock(&stdev->lock);
3193 break;
3194
3195 case AUDIO_EVENT_READ_SAMPLES:
3196 if (!config) {
3197 ALOGE("%s: Invalid config", __func__);
3198 ret = -EINVAL;
3199 break;
3200 }
3201 p_ses = (st_session_t*)config->u.aud_info.ses_info->p_ses;
3202 ret = st_session_read_pcm(p_ses, config->u.aud_info.buf,
3203 config->u.aud_info.num_bytes,
3204 &bytes_read);
3205 break;
3206
3207 case AUDIO_EVENT_DEVICE_CONNECT:
3208 if (!config) {
3209 ALOGE("%s: NULL config for DEVICE_CONNECT", __func__);
3210 ret = -EINVAL;
3211 break;
3212 }
3213 if (config->u.value == AUDIO_DEVICE_OUT_LINE ||
Quinn Maled409e412019-12-09 14:50:48 -08003214 config->u.value == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP ||
3215 config->u.value == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES ||
3216 config->u.value == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) {
Quinn Male2e883752019-03-22 11:28:54 -07003217 pthread_mutex_lock(&stdev->lock);
Quinn Maled409e412019-12-09 14:50:48 -08003218 platform_stdev_update_device_list(config->u.value, "",
3219 &stdev->ec_ref_dev_list, true);
Quinn Male2e883752019-03-22 11:28:54 -07003220 pthread_mutex_unlock(&stdev->lock);
Quinn Maled409e412019-12-09 14:50:48 -08003221 ALOGD("%s: Device connected. Updated ec ref devices with %d",
3222 __func__, config->u.value);
Quinn Male2e883752019-03-22 11:28:54 -07003223 } else {
3224 handle_device_switch(true, config);
3225 }
3226 break;
3227
3228 case AUDIO_EVENT_DEVICE_DISCONNECT:
3229 if (!config) {
3230 ALOGE("%s: NULL config for DEVICE_DISCONNECT", __func__);
3231 ret = -EINVAL;
3232 break;
3233 }
3234 if (config->u.value == AUDIO_DEVICE_OUT_LINE ||
Quinn Maled409e412019-12-09 14:50:48 -08003235 config->u.value == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP ||
3236 config->u.value == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES ||
3237 config->u.value == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) {
Quinn Male2e883752019-03-22 11:28:54 -07003238 pthread_mutex_lock(&stdev->lock);
3239 /*
3240 * Currently spkr/lineout/a2dp are the supported ec ref devices
3241 * Set default EC ref device (spkr) if lineout/a2dp is disconnected
3242 */
Quinn Maled409e412019-12-09 14:50:48 -08003243 platform_stdev_update_device_list(config->u.value, "",
3244 &stdev->ec_ref_dev_list, false);
Quinn Male2e883752019-03-22 11:28:54 -07003245 pthread_mutex_unlock(&stdev->lock);
Quinn Maled409e412019-12-09 14:50:48 -08003246 ALOGD("%s: Device disconnected. Updated ec ref devices by removing %d",
3247 __func__, config->u.value);
Quinn Male2e883752019-03-22 11:28:54 -07003248 } else {
3249 handle_device_switch(false, config);
3250 }
3251 break;
3252
3253 case AUDIO_EVENT_SVA_EXEC_MODE:
3254 pthread_mutex_lock(&stdev->lock);
3255 if (!config) {
3256 ALOGE("%s: NULL config for AUDIO_EVENT_SVA_EXEC_MODE", __func__);
3257 ret = -EINVAL;
3258 goto error;
3259 }
3260 ret = parse_exec_mode_config(config->u.str_value, &exec_mode, &sm_handle);
3261 if (ret) {
3262 ALOGE("%s: Failed to parse exec mode config", __func__);
3263 goto error;
3264 }
3265
3266 if (sm_handle) {
3267 p_ses = get_sound_trigger_session(stdev, sm_handle);
3268 if (p_ses == NULL) {
3269 ALOGE("%s: Could not find sound model %d", __func__, sm_handle);
3270 ret = -EINVAL;
3271 goto error;
3272 }
3273 }
3274 ALOGV("%s:[%d] set exec mode %d", __func__, sm_handle, exec_mode);
3275 if (exec_mode == ST_EXEC_MODE_ADSP) {
3276 ret = check_and_transit_cpe_ses_to_ape(p_ses);
3277 if (!sm_handle)
3278 stdev->client_req_exec_mode = exec_mode;
3279 } else if (exec_mode == ST_EXEC_MODE_CPE) {
3280 ret = check_and_transit_ape_ses_to_cpe(p_ses);
3281 if (!sm_handle)
3282 stdev->client_req_exec_mode = exec_mode;
3283 } else {
3284 ALOGE("%s: Invalid exec mode %d", __func__, exec_mode);
3285 ret = -EINVAL;
3286 }
3287
3288 error:
3289 /* store exec mode callback status to return when queried */
3290 stdev->client_req_exec_mode_status = ret;
3291 pthread_mutex_unlock(&stdev->lock);
3292 break;
3293
3294 case AUDIO_EVENT_SVA_EXEC_MODE_STATUS:
3295 if (!config) {
3296 ALOGE("%s: NULL config for AUDIO_EVENT_SVA_EXEC_MODE", __func__);
3297 ret = -EINVAL;
3298 break;
3299 }
3300 config->u.value = stdev->client_req_exec_mode_status;
3301 ALOGV("%s: exec mode status %d", __func__, config->u.value);
3302 break;
3303
3304 case AUDIO_EVENT_GET_PARAM:
3305 if (!config || !(config->u.st_get_param_data.reply)) {
3306 ALOGE("%s: NULL config for AUDIO_EVENT_GET_PARAM", __func__);
3307 ret = -EINVAL;
3308 break;
3309 }
3310 ALOGD("%s: get param data for %s with sm_handle %d", __func__,
3311 config->u.st_get_param_data.param, config->u.st_get_param_data.sm_handle);
3312 pthread_mutex_lock(&stdev->lock);
3313 p_ses = get_sound_trigger_session(stdev, config->u.st_get_param_data.sm_handle);
3314 if (!p_ses) {
3315 ALOGE("%s: ERROR. Could not find session for sm_handle %d",
3316 __func__, config->u.st_get_param_data.sm_handle);
3317 ret = -EINVAL;
3318 goto exit;
3319 }
3320 ret = stdev_get_param_data(p_ses, config);
3321 exit:
3322 pthread_mutex_unlock(&stdev->lock);
3323 ALOGV("%s: exit: return - %d", __func__, ret);
3324 break;
3325
3326 case AUDIO_EVENT_BATTERY_STATUS_CHANGED:
3327 if (!config) {
3328 ALOGE("%s: NULL config for AUDIO_EVENT_BATTERY_STATUS_CHANGED", __func__);
3329 ret = -EINVAL;
3330 break;
3331 }
3332 handle_battery_status_change(config);
3333 break;
3334
Quinn Malecc1affd2019-07-18 16:13:31 -07003335 case AUDIO_EVENT_SCREEN_STATUS_CHANGED:
3336 if (!config) {
3337 ALOGE("%s: NULL config for AUDIO_EVENT_SCREEN_STATUS_CHANGED", __func__);
3338 ret = -EINVAL;
3339 break;
3340 }
3341 handle_screen_status_change(config);
3342 break;
3343
Quinn Male2e883752019-03-22 11:28:54 -07003344 default:
3345 ALOGW("%s: Unknown event %d", __func__, event);
3346 break;
3347 }
3348
Quinn Male9c4f7932020-04-21 16:15:03 -07003349 pthread_mutex_unlock(&stdev_init_lock);
Quinn Male2e883752019-03-22 11:28:54 -07003350 return ret;
3351}
3352
3353/*
3354 * Current proprietary API version used by STHAL. Queried by AHAL
3355 * for compatibility check with STHAL
3356 */
3357const unsigned int sthal_prop_api_version = STHAL_PROP_API_CURRENT_VERSION;
3358
3359static struct hw_module_methods_t hal_module_methods = {
3360 .open = stdev_open,
3361};
3362
3363struct sound_trigger_module HAL_MODULE_INFO_SYM = {
3364 .common = {
3365 .tag = HARDWARE_MODULE_TAG,
3366 .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0,
3367 .hal_api_version = HARDWARE_HAL_API_VERSION,
3368 .id = SOUND_TRIGGER_HARDWARE_MODULE_ID,
3369 .name = "Sound trigger HAL",
3370 .author = "QUALCOMM Technologies, Inc",
3371 .methods = &hal_module_methods,
3372 },
3373};