blob: 7ad8e9f8292a2d48c48625b6b49d25a18b7590ab [file] [log] [blame]
Surendar Karka59c51072017-12-13 11:25:57 +05301/* Copyright (c) 2013-2014, 2016-2018 The Linux Foundation. All rights reserved.
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07002 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29#define LOG_TAG "soundtrigger"
30/* #define LOG_NDEBUG 0 */
31#define LOG_NDDEBUG 0
32
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -070033#include <errno.h>
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070034#include <stdbool.h>
35#include <stdlib.h>
36#include <dlfcn.h>
37#include <cutils/log.h>
38#include "audio_hw.h"
39#include "audio_extn.h"
40#include "platform.h"
41#include "platform_api.h"
42#include "sound_trigger_prop_intf.h"
43
Revathi Uddaraju1eac8b02017-05-18 17:13:33 +053044#ifdef DYNAMIC_LOG_ENABLED
45#include <log_xml_parser.h>
46#define LOG_MASK HAL_MOD_FILE_SND_TRIGGER
47#include <log_utils.h>
48#endif
49
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070050#define XSTR(x) STR(x)
51#define STR(x) #x
Yamit Mehtaa0d653a2016-11-25 20:33:25 +053052#define MAX_LIBRARY_PATH 100
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070053
54struct sound_trigger_info {
55 struct sound_trigger_session_info st_ses;
56 bool lab_stopped;
57 struct listnode list;
58};
59
60struct sound_trigger_audio_device {
61 void *lib_handle;
62 struct audio_device *adev;
63 sound_trigger_hw_call_back_t st_callback;
64 struct listnode st_ses_list;
65 pthread_mutex_t lock;
66};
67
68static struct sound_trigger_audio_device *st_dev;
69
Yamit Mehtaa0d653a2016-11-25 20:33:25 +053070#if LINUX_ENABLED
71static void get_library_path(char *lib_path)
72{
73 snprintf(lib_path, MAX_LIBRARY_PATH,
Manish Dewangan6a36d002017-10-09 14:11:00 +053074 "sound_trigger.primary.default.so");
Yamit Mehtaa0d653a2016-11-25 20:33:25 +053075}
76#else
77static void get_library_path(char *lib_path)
78{
79 snprintf(lib_path, MAX_LIBRARY_PATH,
David Ng06ccd872017-03-15 11:39:33 -070080 "/vendor/lib/hw/sound_trigger.primary.%s.so",
Yamit Mehtaa0d653a2016-11-25 20:33:25 +053081 XSTR(SOUND_TRIGGER_PLATFORM_NAME));
82}
83#endif
84
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070085static struct sound_trigger_info *
86get_sound_trigger_info(int capture_handle)
87{
88 struct sound_trigger_info *st_ses_info = NULL;
89 struct listnode *node;
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -070090 ALOGV("%s: list empty %d capture_handle %d", __func__,
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070091 list_empty(&st_dev->st_ses_list), capture_handle);
92 list_for_each(node, &st_dev->st_ses_list) {
93 st_ses_info = node_to_item(node, struct sound_trigger_info , list);
94 if (st_ses_info->st_ses.capture_handle == capture_handle)
95 return st_ses_info;
96 }
97 return NULL;
98}
99
Dhananjay Kumare6293dd2017-05-25 17:25:30 +0530100static void stdev_snd_mon_cb(void * stream __unused, struct str_parms * parms)
101{
102 if (!parms)
103 return;
104
105 audio_extn_sound_trigger_set_parameters(NULL, parms);
106 return;
107}
108
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700109int audio_hw_call_back(sound_trigger_event_type_t event,
110 sound_trigger_event_info_t* config)
111{
112 int status = 0;
113 struct sound_trigger_info *st_ses_info;
114
115 if (!st_dev)
116 return -EINVAL;
117
118 pthread_mutex_lock(&st_dev->lock);
119 switch (event) {
120 case ST_EVENT_SESSION_REGISTER:
121 if (!config) {
122 ALOGE("%s: NULL config", __func__);
123 status = -EINVAL;
124 break;
125 }
126 st_ses_info= calloc(1, sizeof(struct sound_trigger_info ));
127 if (!st_ses_info) {
128 ALOGE("%s: st_ses_info alloc failed", __func__);
129 status = -ENOMEM;
130 break;
131 }
Shiv Maliyappanahalli0e283d32016-07-14 23:20:03 -0700132 memcpy(&st_ses_info->st_ses, &config->st_ses, sizeof (struct sound_trigger_session_info));
133 ALOGV("%s: add capture_handle %d st session opaque ptr %p", __func__,
134 st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.p_ses);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700135 list_add_tail(&st_dev->st_ses_list, &st_ses_info->list);
136 break;
137
Surendar Karka59c51072017-12-13 11:25:57 +0530138 case ST_EVENT_START_KEEP_ALIVE:
139 pthread_mutex_unlock(&st_dev->lock);
140 pthread_mutex_lock(&st_dev->adev->lock);
141 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_PRIMARY);
142 pthread_mutex_unlock(&st_dev->adev->lock);
143 goto done;
144
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700145 case ST_EVENT_SESSION_DEREGISTER:
146 if (!config) {
147 ALOGE("%s: NULL config", __func__);
148 status = -EINVAL;
149 break;
150 }
151 st_ses_info = get_sound_trigger_info(config->st_ses.capture_handle);
152 if (!st_ses_info) {
Shiv Maliyappanahalli0e283d32016-07-14 23:20:03 -0700153 ALOGE("%s: st session opaque ptr %p not in the list!", __func__, config->st_ses.p_ses);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700154 status = -EINVAL;
155 break;
156 }
Shiv Maliyappanahalli0e283d32016-07-14 23:20:03 -0700157 ALOGV("%s: remove capture_handle %d st session opaque ptr %p", __func__,
158 st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.p_ses);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700159 list_remove(&st_ses_info->list);
160 free(st_ses_info);
161 break;
Surendar Karka59c51072017-12-13 11:25:57 +0530162
163 case ST_EVENT_STOP_KEEP_ALIVE:
164 pthread_mutex_unlock(&st_dev->lock);
165 pthread_mutex_lock(&st_dev->adev->lock);
166 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_PRIMARY);
167 pthread_mutex_unlock(&st_dev->adev->lock);
168 goto done;
169
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700170 default:
171 ALOGW("%s: Unknown event %d", __func__, event);
172 break;
173 }
174 pthread_mutex_unlock(&st_dev->lock);
Surendar Karka59c51072017-12-13 11:25:57 +0530175done:
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700176 return status;
177}
178
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -0700179int audio_extn_sound_trigger_read(struct stream_in *in, void *buffer,
180 size_t bytes)
181{
182 int ret = -1;
183 struct sound_trigger_info *st_info = NULL;
184 audio_event_info_t event;
185
186 if (!st_dev)
187 return ret;
188
189 if (!in->is_st_session_active) {
190 ALOGE(" %s: Sound trigger is not active", __func__);
191 goto exit;
192 }
193 if(in->standby)
194 in->standby = false;
195
196 pthread_mutex_lock(&st_dev->lock);
197 st_info = get_sound_trigger_info(in->capture_handle);
198 pthread_mutex_unlock(&st_dev->lock);
199 if (st_info) {
200 event.u.aud_info.ses_info = &st_info->st_ses;
201 event.u.aud_info.buf = buffer;
202 event.u.aud_info.num_bytes = bytes;
203 ret = st_dev->st_callback(AUDIO_EVENT_READ_SAMPLES, &event);
204 }
205
206exit:
207 if (ret) {
208 if (-ENETRESET == ret)
209 in->is_st_session_active = false;
210 memset(buffer, 0, bytes);
211 ALOGV("%s: read failed status %d - sleep", __func__, ret);
212 usleep((bytes * 1000000) / (audio_stream_in_frame_size((struct audio_stream_in *)in) *
213 in->config.rate));
214 }
215 return ret;
216}
217
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700218void audio_extn_sound_trigger_stop_lab(struct stream_in *in)
219{
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700220 struct sound_trigger_info *st_ses_info = NULL;
221 audio_event_info_t event;
222
Mingming Yinfd7607b2016-01-22 12:48:44 -0800223 if (!st_dev || !in || !in->is_st_session_active)
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700224 return;
225
226 pthread_mutex_lock(&st_dev->lock);
227 st_ses_info = get_sound_trigger_info(in->capture_handle);
Bharath Ramachandramurthy5baa6a52014-10-21 11:18:49 -0700228 pthread_mutex_unlock(&st_dev->lock);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700229 if (st_ses_info) {
230 event.u.ses_info = st_ses_info->st_ses;
Shiv Maliyappanahalli0e283d32016-07-14 23:20:03 -0700231 ALOGV("%s: AUDIO_EVENT_STOP_LAB st sess %p", __func__, st_ses_info->st_ses.p_ses);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700232 st_dev->st_callback(AUDIO_EVENT_STOP_LAB, &event);
Mingming Yinfd7607b2016-01-22 12:48:44 -0800233 in->is_st_session_active = false;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700234 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700235}
236void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in)
237{
238 struct sound_trigger_info *st_ses_info = NULL;
239 struct listnode *node;
240
241 if (!st_dev || !in)
242 return;
243
244 pthread_mutex_lock(&st_dev->lock);
245 in->is_st_session = false;
246 ALOGV("%s: list %d capture_handle %d", __func__,
247 list_empty(&st_dev->st_ses_list), in->capture_handle);
248 list_for_each(node, &st_dev->st_ses_list) {
249 st_ses_info = node_to_item(node, struct sound_trigger_info , list);
250 if (st_ses_info->st_ses.capture_handle == in->capture_handle) {
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700251 in->config = st_ses_info->st_ses.config;
252 in->channel_mask = audio_channel_in_mask_from_count(in->config.channels);
253 in->is_st_session = true;
Bharath Ramachandramurthy837535b2015-02-05 14:27:59 -0800254 in->is_st_session_active = true;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700255 ALOGD("%s: capture_handle %d is sound trigger", __func__, in->capture_handle);
256 break;
257 }
258 }
259 pthread_mutex_unlock(&st_dev->lock);
260}
261
262void audio_extn_sound_trigger_update_device_status(snd_device_t snd_device,
263 st_event_type_t event)
264{
265 bool raise_event = false;
266 int device_type = -1;
267
268 if (!st_dev)
269 return;
270
271 if (snd_device >= SND_DEVICE_OUT_BEGIN &&
272 snd_device < SND_DEVICE_OUT_END)
273 device_type = PCM_PLAYBACK;
274 else if (snd_device >= SND_DEVICE_IN_BEGIN &&
275 snd_device < SND_DEVICE_IN_END)
276 device_type = PCM_CAPTURE;
277 else {
278 ALOGE("%s: invalid device 0x%x, for event %d",
279 __func__, snd_device, event);
280 return;
281 }
282
283 raise_event = platform_sound_trigger_device_needs_event(snd_device);
284 ALOGI("%s: device 0x%x of type %d for Event %d, with Raise=%d",
285 __func__, snd_device, device_type, event, raise_event);
286 if (raise_event && (device_type == PCM_CAPTURE)) {
287 switch(event) {
288 case ST_EVENT_SND_DEVICE_FREE:
289 st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE, NULL);
290 break;
291 case ST_EVENT_SND_DEVICE_BUSY:
292 st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_ACTIVE, NULL);
293 break;
294 default:
295 ALOGW("%s:invalid event %d for device 0x%x",
296 __func__, event, snd_device);
297 }
298 }/*Events for output device, if required can be placed here in else*/
299}
300
301void audio_extn_sound_trigger_update_stream_status(struct audio_usecase *uc_info,
302 st_event_type_t event)
303{
304 bool raise_event = false;
305 audio_usecase_t uc_id;
306 int usecase_type = -1;
307
308 if (!st_dev) {
309 return;
310 }
311
312 if (uc_info == NULL) {
313 ALOGE("%s: usecase is NULL!!!", __func__);
314 return;
315 }
316 uc_id = uc_info->id;
317 usecase_type = uc_info->type;
318
319 raise_event = platform_sound_trigger_usecase_needs_event(uc_id);
320 ALOGD("%s: uc_id %d of type %d for Event %d, with Raise=%d",
321 __func__, uc_id, usecase_type, event, raise_event);
322 if (raise_event && (usecase_type == PCM_PLAYBACK)) {
323 switch(event) {
324 case ST_EVENT_STREAM_FREE:
325 st_dev->st_callback(AUDIO_EVENT_PLAYBACK_STREAM_INACTIVE, NULL);
326 break;
327 case ST_EVENT_STREAM_BUSY:
328 st_dev->st_callback(AUDIO_EVENT_PLAYBACK_STREAM_ACTIVE, NULL);
329 break;
330 default:
331 ALOGW("%s:invalid event %d, for usecase %d",
332 __func__, event, uc_id);
333 }
334 }/*Events for capture usecase, if required can be placed here in else*/
335}
336
337void audio_extn_sound_trigger_set_parameters(struct audio_device *adev __unused,
338 struct str_parms *params)
339{
340 audio_event_info_t event;
341 char value[32];
Bharath Ramachandramurthyc694f8a2014-09-25 16:15:12 -0700342 int ret, val;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700343
344 if(!st_dev || !params) {
345 ALOGE("%s: str_params NULL", __func__);
346 return;
347 }
348
349 ret = str_parms_get_str(params, "SND_CARD_STATUS", value,
350 sizeof(value));
351 if (ret > 0) {
352 if (strstr(value, "OFFLINE")) {
353 event.u.status = SND_CARD_STATUS_OFFLINE;
354 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
355 }
356 else if (strstr(value, "ONLINE")) {
357 event.u.status = SND_CARD_STATUS_ONLINE;
358 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
359 }
360 else
361 ALOGE("%s: unknown snd_card_status", __func__);
362 }
363
364 ret = str_parms_get_str(params, "CPE_STATUS", value, sizeof(value));
365 if (ret > 0) {
366 if (strstr(value, "OFFLINE")) {
367 event.u.status = CPE_STATUS_OFFLINE;
368 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
369 }
370 else if (strstr(value, "ONLINE")) {
371 event.u.status = CPE_STATUS_ONLINE;
372 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
373 }
374 else
375 ALOGE("%s: unknown CPE status", __func__);
376 }
Bharath Ramachandramurthyc694f8a2014-09-25 16:15:12 -0700377
378 ret = str_parms_get_int(params, "SVA_NUM_SESSIONS", &val);
379 if (ret >= 0) {
380 event.u.value = val;
381 st_dev->st_callback(AUDIO_EVENT_NUM_ST_SESSIONS, &event);
382 }
Quinn male73dd1fd2016-12-02 10:47:11 -0800383
384 ret = str_parms_get_int(params, AUDIO_PARAMETER_DEVICE_CONNECT, &val);
385 if ((ret >= 0) && audio_is_input_device(val)) {
386 event.u.value = val;
387 st_dev->st_callback(AUDIO_EVENT_DEVICE_CONNECT, &event);
388 }
389
390 ret = str_parms_get_int(params, AUDIO_PARAMETER_DEVICE_DISCONNECT, &val);
391 if ((ret >= 0) && audio_is_input_device(val)) {
392 event.u.value = val;
393 st_dev->st_callback(AUDIO_EVENT_DEVICE_DISCONNECT, &event);
394 }
Chaithanya Krishna Bacharajue3d711e2016-12-08 16:17:32 +0530395
396 ret = str_parms_get_str(params, "SVA_EXEC_MODE", value, sizeof(value));
397 if (ret >= 0) {
398 strlcpy(event.u.str_value, value, sizeof(event.u.str_value));
399 st_dev->st_callback(AUDIO_EVENT_SVA_EXEC_MODE, &event);
400 }
401}
402
403void audio_extn_sound_trigger_get_parameters(const struct audio_device *adev __unused,
404 struct str_parms *query, struct str_parms *reply)
405{
406 audio_event_info_t event;
407 int ret;
408 char value[32];
409
410 ret = str_parms_get_str(query, "SVA_EXEC_MODE_STATUS", value,
411 sizeof(value));
412 if (ret >= 0) {
413 st_dev->st_callback(AUDIO_EVENT_SVA_EXEC_MODE_STATUS, &event);
414 str_parms_add_int(reply, "SVA_EXEC_MODE_STATUS", event.u.value);
415 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700416}
417
418int audio_extn_sound_trigger_init(struct audio_device *adev)
419{
420 int status = 0;
421 char sound_trigger_lib[100];
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700422
423 ALOGI("%s: Enter", __func__);
424
425 st_dev = (struct sound_trigger_audio_device*)
426 calloc(1, sizeof(struct sound_trigger_audio_device));
427 if (!st_dev) {
428 ALOGE("%s: ERROR. sound trigger alloc failed", __func__);
429 return -ENOMEM;
430 }
431
Yamit Mehtaa0d653a2016-11-25 20:33:25 +0530432 get_library_path(sound_trigger_lib);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700433 st_dev->lib_handle = dlopen(sound_trigger_lib, RTLD_NOW);
434
435 if (st_dev->lib_handle == NULL) {
436 ALOGE("%s: DLOPEN failed for %s. error = %s", __func__, sound_trigger_lib,
437 dlerror());
438 status = -EINVAL;
439 goto cleanup;
440 }
441 ALOGI("%s: DLOPEN successful for %s", __func__, sound_trigger_lib);
442
443 st_dev->st_callback = (sound_trigger_hw_call_back_t)
444 dlsym(st_dev->lib_handle, "sound_trigger_hw_call_back");
445
446 if (st_dev->st_callback == NULL) {
447 ALOGE("%s: ERROR. dlsym Error:%s sound_trigger_hw_call_back", __func__,
448 dlerror());
449 goto cleanup;
450 }
451
452 st_dev->adev = adev;
453 list_init(&st_dev->st_ses_list);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +0530454 audio_extn_snd_mon_register_listener(st_dev, stdev_snd_mon_cb);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700455
456 return 0;
457
458cleanup:
459 if (st_dev->lib_handle)
460 dlclose(st_dev->lib_handle);
461 free(st_dev);
462 st_dev = NULL;
463 return status;
464
465}
466
467void audio_extn_sound_trigger_deinit(struct audio_device *adev)
468{
469 ALOGI("%s: Enter", __func__);
470 if (st_dev && (st_dev->adev == adev) && st_dev->lib_handle) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +0530471 audio_extn_snd_mon_unregister_listener(st_dev);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700472 dlclose(st_dev->lib_handle);
473 free(st_dev);
474 st_dev = NULL;
475 }
476}