blob: cecc8433b22296c917774149a04934e6390e72c3 [file] [log] [blame]
Chaithanya Krishna Bacharajue3d711e2016-12-08 16:17:32 +05301/* Copyright (c) 2013-2014, 2016-2017 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
44#define XSTR(x) STR(x)
45#define STR(x) #x
Yamit Mehtaa0d653a2016-11-25 20:33:25 +053046#define MAX_LIBRARY_PATH 100
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070047
48struct sound_trigger_info {
49 struct sound_trigger_session_info st_ses;
50 bool lab_stopped;
51 struct listnode list;
52};
53
54struct sound_trigger_audio_device {
55 void *lib_handle;
56 struct audio_device *adev;
57 sound_trigger_hw_call_back_t st_callback;
58 struct listnode st_ses_list;
59 pthread_mutex_t lock;
60};
61
62static struct sound_trigger_audio_device *st_dev;
63
Yamit Mehtaa0d653a2016-11-25 20:33:25 +053064#if LINUX_ENABLED
65static void get_library_path(char *lib_path)
66{
67 snprintf(lib_path, MAX_LIBRARY_PATH,
68 "/usr/lib/sound_trigger.primary.default.so");
69}
70#else
71static void get_library_path(char *lib_path)
72{
73 snprintf(lib_path, MAX_LIBRARY_PATH,
David Ng06ccd872017-03-15 11:39:33 -070074 "/vendor/lib/hw/sound_trigger.primary.%s.so",
Yamit Mehtaa0d653a2016-11-25 20:33:25 +053075 XSTR(SOUND_TRIGGER_PLATFORM_NAME));
76}
77#endif
78
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070079static struct sound_trigger_info *
80get_sound_trigger_info(int capture_handle)
81{
82 struct sound_trigger_info *st_ses_info = NULL;
83 struct listnode *node;
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -070084 ALOGV("%s: list empty %d capture_handle %d", __func__,
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070085 list_empty(&st_dev->st_ses_list), capture_handle);
86 list_for_each(node, &st_dev->st_ses_list) {
87 st_ses_info = node_to_item(node, struct sound_trigger_info , list);
88 if (st_ses_info->st_ses.capture_handle == capture_handle)
89 return st_ses_info;
90 }
91 return NULL;
92}
93
94int audio_hw_call_back(sound_trigger_event_type_t event,
95 sound_trigger_event_info_t* config)
96{
97 int status = 0;
98 struct sound_trigger_info *st_ses_info;
99
100 if (!st_dev)
101 return -EINVAL;
102
103 pthread_mutex_lock(&st_dev->lock);
104 switch (event) {
105 case ST_EVENT_SESSION_REGISTER:
106 if (!config) {
107 ALOGE("%s: NULL config", __func__);
108 status = -EINVAL;
109 break;
110 }
111 st_ses_info= calloc(1, sizeof(struct sound_trigger_info ));
112 if (!st_ses_info) {
113 ALOGE("%s: st_ses_info alloc failed", __func__);
114 status = -ENOMEM;
115 break;
116 }
Shiv Maliyappanahalli0e283d32016-07-14 23:20:03 -0700117 memcpy(&st_ses_info->st_ses, &config->st_ses, sizeof (struct sound_trigger_session_info));
118 ALOGV("%s: add capture_handle %d st session opaque ptr %p", __func__,
119 st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.p_ses);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700120 list_add_tail(&st_dev->st_ses_list, &st_ses_info->list);
121 break;
122
123 case ST_EVENT_SESSION_DEREGISTER:
124 if (!config) {
125 ALOGE("%s: NULL config", __func__);
126 status = -EINVAL;
127 break;
128 }
129 st_ses_info = get_sound_trigger_info(config->st_ses.capture_handle);
130 if (!st_ses_info) {
Shiv Maliyappanahalli0e283d32016-07-14 23:20:03 -0700131 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 -0700132 status = -EINVAL;
133 break;
134 }
Shiv Maliyappanahalli0e283d32016-07-14 23:20:03 -0700135 ALOGV("%s: remove capture_handle %d st session opaque ptr %p", __func__,
136 st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.p_ses);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700137 list_remove(&st_ses_info->list);
138 free(st_ses_info);
139 break;
140 default:
141 ALOGW("%s: Unknown event %d", __func__, event);
142 break;
143 }
144 pthread_mutex_unlock(&st_dev->lock);
145 return status;
146}
147
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -0700148int audio_extn_sound_trigger_read(struct stream_in *in, void *buffer,
149 size_t bytes)
150{
151 int ret = -1;
152 struct sound_trigger_info *st_info = NULL;
153 audio_event_info_t event;
154
155 if (!st_dev)
156 return ret;
157
158 if (!in->is_st_session_active) {
159 ALOGE(" %s: Sound trigger is not active", __func__);
160 goto exit;
161 }
162 if(in->standby)
163 in->standby = false;
164
165 pthread_mutex_lock(&st_dev->lock);
166 st_info = get_sound_trigger_info(in->capture_handle);
167 pthread_mutex_unlock(&st_dev->lock);
168 if (st_info) {
169 event.u.aud_info.ses_info = &st_info->st_ses;
170 event.u.aud_info.buf = buffer;
171 event.u.aud_info.num_bytes = bytes;
172 ret = st_dev->st_callback(AUDIO_EVENT_READ_SAMPLES, &event);
173 }
174
175exit:
176 if (ret) {
177 if (-ENETRESET == ret)
178 in->is_st_session_active = false;
179 memset(buffer, 0, bytes);
180 ALOGV("%s: read failed status %d - sleep", __func__, ret);
181 usleep((bytes * 1000000) / (audio_stream_in_frame_size((struct audio_stream_in *)in) *
182 in->config.rate));
183 }
184 return ret;
185}
186
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700187void audio_extn_sound_trigger_stop_lab(struct stream_in *in)
188{
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700189 struct sound_trigger_info *st_ses_info = NULL;
190 audio_event_info_t event;
191
Mingming Yinfd7607b2016-01-22 12:48:44 -0800192 if (!st_dev || !in || !in->is_st_session_active)
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700193 return;
194
195 pthread_mutex_lock(&st_dev->lock);
196 st_ses_info = get_sound_trigger_info(in->capture_handle);
Bharath Ramachandramurthy5baa6a52014-10-21 11:18:49 -0700197 pthread_mutex_unlock(&st_dev->lock);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700198 if (st_ses_info) {
199 event.u.ses_info = st_ses_info->st_ses;
Shiv Maliyappanahalli0e283d32016-07-14 23:20:03 -0700200 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 -0700201 st_dev->st_callback(AUDIO_EVENT_STOP_LAB, &event);
Mingming Yinfd7607b2016-01-22 12:48:44 -0800202 in->is_st_session_active = false;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700203 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700204}
205void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in)
206{
207 struct sound_trigger_info *st_ses_info = NULL;
208 struct listnode *node;
209
210 if (!st_dev || !in)
211 return;
212
213 pthread_mutex_lock(&st_dev->lock);
214 in->is_st_session = false;
215 ALOGV("%s: list %d capture_handle %d", __func__,
216 list_empty(&st_dev->st_ses_list), in->capture_handle);
217 list_for_each(node, &st_dev->st_ses_list) {
218 st_ses_info = node_to_item(node, struct sound_trigger_info , list);
219 if (st_ses_info->st_ses.capture_handle == in->capture_handle) {
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700220 in->config = st_ses_info->st_ses.config;
221 in->channel_mask = audio_channel_in_mask_from_count(in->config.channels);
222 in->is_st_session = true;
Bharath Ramachandramurthy837535b2015-02-05 14:27:59 -0800223 in->is_st_session_active = true;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700224 ALOGD("%s: capture_handle %d is sound trigger", __func__, in->capture_handle);
225 break;
226 }
227 }
228 pthread_mutex_unlock(&st_dev->lock);
229}
230
231void audio_extn_sound_trigger_update_device_status(snd_device_t snd_device,
232 st_event_type_t event)
233{
234 bool raise_event = false;
235 int device_type = -1;
236
237 if (!st_dev)
238 return;
239
240 if (snd_device >= SND_DEVICE_OUT_BEGIN &&
241 snd_device < SND_DEVICE_OUT_END)
242 device_type = PCM_PLAYBACK;
243 else if (snd_device >= SND_DEVICE_IN_BEGIN &&
244 snd_device < SND_DEVICE_IN_END)
245 device_type = PCM_CAPTURE;
246 else {
247 ALOGE("%s: invalid device 0x%x, for event %d",
248 __func__, snd_device, event);
249 return;
250 }
251
252 raise_event = platform_sound_trigger_device_needs_event(snd_device);
253 ALOGI("%s: device 0x%x of type %d for Event %d, with Raise=%d",
254 __func__, snd_device, device_type, event, raise_event);
255 if (raise_event && (device_type == PCM_CAPTURE)) {
256 switch(event) {
257 case ST_EVENT_SND_DEVICE_FREE:
258 st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE, NULL);
259 break;
260 case ST_EVENT_SND_DEVICE_BUSY:
261 st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_ACTIVE, NULL);
262 break;
263 default:
264 ALOGW("%s:invalid event %d for device 0x%x",
265 __func__, event, snd_device);
266 }
267 }/*Events for output device, if required can be placed here in else*/
268}
269
270void audio_extn_sound_trigger_update_stream_status(struct audio_usecase *uc_info,
271 st_event_type_t event)
272{
273 bool raise_event = false;
274 audio_usecase_t uc_id;
275 int usecase_type = -1;
276
277 if (!st_dev) {
278 return;
279 }
280
281 if (uc_info == NULL) {
282 ALOGE("%s: usecase is NULL!!!", __func__);
283 return;
284 }
285 uc_id = uc_info->id;
286 usecase_type = uc_info->type;
287
288 raise_event = platform_sound_trigger_usecase_needs_event(uc_id);
289 ALOGD("%s: uc_id %d of type %d for Event %d, with Raise=%d",
290 __func__, uc_id, usecase_type, event, raise_event);
291 if (raise_event && (usecase_type == PCM_PLAYBACK)) {
292 switch(event) {
293 case ST_EVENT_STREAM_FREE:
294 st_dev->st_callback(AUDIO_EVENT_PLAYBACK_STREAM_INACTIVE, NULL);
295 break;
296 case ST_EVENT_STREAM_BUSY:
297 st_dev->st_callback(AUDIO_EVENT_PLAYBACK_STREAM_ACTIVE, NULL);
298 break;
299 default:
300 ALOGW("%s:invalid event %d, for usecase %d",
301 __func__, event, uc_id);
302 }
303 }/*Events for capture usecase, if required can be placed here in else*/
304}
305
306void audio_extn_sound_trigger_set_parameters(struct audio_device *adev __unused,
307 struct str_parms *params)
308{
309 audio_event_info_t event;
310 char value[32];
Bharath Ramachandramurthyc694f8a2014-09-25 16:15:12 -0700311 int ret, val;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700312
313 if(!st_dev || !params) {
314 ALOGE("%s: str_params NULL", __func__);
315 return;
316 }
317
318 ret = str_parms_get_str(params, "SND_CARD_STATUS", value,
319 sizeof(value));
320 if (ret > 0) {
321 if (strstr(value, "OFFLINE")) {
322 event.u.status = SND_CARD_STATUS_OFFLINE;
323 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
324 }
325 else if (strstr(value, "ONLINE")) {
326 event.u.status = SND_CARD_STATUS_ONLINE;
327 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
328 }
329 else
330 ALOGE("%s: unknown snd_card_status", __func__);
331 }
332
333 ret = str_parms_get_str(params, "CPE_STATUS", value, sizeof(value));
334 if (ret > 0) {
335 if (strstr(value, "OFFLINE")) {
336 event.u.status = CPE_STATUS_OFFLINE;
337 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
338 }
339 else if (strstr(value, "ONLINE")) {
340 event.u.status = CPE_STATUS_ONLINE;
341 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
342 }
343 else
344 ALOGE("%s: unknown CPE status", __func__);
345 }
Bharath Ramachandramurthyc694f8a2014-09-25 16:15:12 -0700346
347 ret = str_parms_get_int(params, "SVA_NUM_SESSIONS", &val);
348 if (ret >= 0) {
349 event.u.value = val;
350 st_dev->st_callback(AUDIO_EVENT_NUM_ST_SESSIONS, &event);
351 }
Quinn male73dd1fd2016-12-02 10:47:11 -0800352
353 ret = str_parms_get_int(params, AUDIO_PARAMETER_DEVICE_CONNECT, &val);
354 if ((ret >= 0) && audio_is_input_device(val)) {
355 event.u.value = val;
356 st_dev->st_callback(AUDIO_EVENT_DEVICE_CONNECT, &event);
357 }
358
359 ret = str_parms_get_int(params, AUDIO_PARAMETER_DEVICE_DISCONNECT, &val);
360 if ((ret >= 0) && audio_is_input_device(val)) {
361 event.u.value = val;
362 st_dev->st_callback(AUDIO_EVENT_DEVICE_DISCONNECT, &event);
363 }
Chaithanya Krishna Bacharajue3d711e2016-12-08 16:17:32 +0530364
365 ret = str_parms_get_str(params, "SVA_EXEC_MODE", value, sizeof(value));
366 if (ret >= 0) {
367 strlcpy(event.u.str_value, value, sizeof(event.u.str_value));
368 st_dev->st_callback(AUDIO_EVENT_SVA_EXEC_MODE, &event);
369 }
370}
371
372void audio_extn_sound_trigger_get_parameters(const struct audio_device *adev __unused,
373 struct str_parms *query, struct str_parms *reply)
374{
375 audio_event_info_t event;
376 int ret;
377 char value[32];
378
379 ret = str_parms_get_str(query, "SVA_EXEC_MODE_STATUS", value,
380 sizeof(value));
381 if (ret >= 0) {
382 st_dev->st_callback(AUDIO_EVENT_SVA_EXEC_MODE_STATUS, &event);
383 str_parms_add_int(reply, "SVA_EXEC_MODE_STATUS", event.u.value);
384 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700385}
386
387int audio_extn_sound_trigger_init(struct audio_device *adev)
388{
389 int status = 0;
390 char sound_trigger_lib[100];
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700391
392 ALOGI("%s: Enter", __func__);
393
394 st_dev = (struct sound_trigger_audio_device*)
395 calloc(1, sizeof(struct sound_trigger_audio_device));
396 if (!st_dev) {
397 ALOGE("%s: ERROR. sound trigger alloc failed", __func__);
398 return -ENOMEM;
399 }
400
Yamit Mehtaa0d653a2016-11-25 20:33:25 +0530401 get_library_path(sound_trigger_lib);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700402 st_dev->lib_handle = dlopen(sound_trigger_lib, RTLD_NOW);
403
404 if (st_dev->lib_handle == NULL) {
405 ALOGE("%s: DLOPEN failed for %s. error = %s", __func__, sound_trigger_lib,
406 dlerror());
407 status = -EINVAL;
408 goto cleanup;
409 }
410 ALOGI("%s: DLOPEN successful for %s", __func__, sound_trigger_lib);
411
412 st_dev->st_callback = (sound_trigger_hw_call_back_t)
413 dlsym(st_dev->lib_handle, "sound_trigger_hw_call_back");
414
415 if (st_dev->st_callback == NULL) {
416 ALOGE("%s: ERROR. dlsym Error:%s sound_trigger_hw_call_back", __func__,
417 dlerror());
418 goto cleanup;
419 }
420
421 st_dev->adev = adev;
422 list_init(&st_dev->st_ses_list);
423
424 return 0;
425
426cleanup:
427 if (st_dev->lib_handle)
428 dlclose(st_dev->lib_handle);
429 free(st_dev);
430 st_dev = NULL;
431 return status;
432
433}
434
435void audio_extn_sound_trigger_deinit(struct audio_device *adev)
436{
437 ALOGI("%s: Enter", __func__);
438 if (st_dev && (st_dev->adev == adev) && st_dev->lib_handle) {
439 dlclose(st_dev->lib_handle);
440 free(st_dev);
441 st_dev = NULL;
442 }
443}