blob: 3417c72b8b31b38dd36bd723398b8c9ccef9e171 [file] [log] [blame]
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#define LOG_TAG "soundtrigger"
17/* #define LOG_NDEBUG 0 */
18#define LOG_NDDEBUG 0
19
20#include <errno.h>
21#include <stdbool.h>
22#include <stdlib.h>
23#include <dlfcn.h>
Jiyong Park6431fe62017-06-29 15:15:58 +090024#include <pthread.h>
25#include <unistd.h>
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -070026#include <cutils/log.h>
27#include "audio_hw.h"
28#include "audio_extn.h"
29#include "platform.h"
30#include "platform_api.h"
31#include "sound_trigger_prop_intf.h"
32
33#define XSTR(x) STR(x)
34#define STR(x) #x
35
Andy Hung7ddf8672016-03-31 10:30:42 -070036#ifdef __LP64__
37#define SOUND_TRIGGER_LIBRARY_PATH "/system/vendor/lib64/hw/sound_trigger.primary.%s.so"
38#else
39#define SOUND_TRIGGER_LIBRARY_PATH "/system/vendor/lib/hw/sound_trigger.primary.%s.so"
40#endif
Andy Hung4bd229e2016-03-07 18:29:16 -080041
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -070042struct sound_trigger_info {
43 struct sound_trigger_session_info st_ses;
44 bool lab_stopped;
45 struct listnode list;
46};
47
48struct sound_trigger_audio_device {
49 void *lib_handle;
50 struct audio_device *adev;
51 sound_trigger_hw_call_back_t st_callback;
52 struct listnode st_ses_list;
53 pthread_mutex_t lock;
54};
55
56static struct sound_trigger_audio_device *st_dev;
57
58static struct sound_trigger_info *
59get_sound_trigger_info(int capture_handle)
60{
61 struct sound_trigger_info *st_ses_info = NULL;
62 struct listnode *node;
63 ALOGV("%s: list %d capture_handle %d", __func__,
64 list_empty(&st_dev->st_ses_list), capture_handle);
65 list_for_each(node, &st_dev->st_ses_list) {
66 st_ses_info = node_to_item(node, struct sound_trigger_info , list);
67 if (st_ses_info->st_ses.capture_handle == capture_handle)
68 return st_ses_info;
69 }
70 return NULL;
71}
72
Haynes Mathew Georgeceafc552017-05-24 15:44:23 -070073static void stdev_snd_mon_cb(void * stream __unused, struct str_parms * parms)
74{
75 if (!parms)
76 return;
77
78 audio_extn_sound_trigger_set_parameters(NULL, parms);
79 return;
80}
81
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -070082int audio_hw_call_back(sound_trigger_event_type_t event,
83 sound_trigger_event_info_t* config)
84{
85 int status = 0;
86 struct sound_trigger_info *st_ses_info;
87
88 if (!st_dev)
89 return -EINVAL;
90
91 pthread_mutex_lock(&st_dev->lock);
92 switch (event) {
93 case ST_EVENT_SESSION_REGISTER:
94 if (!config) {
95 ALOGE("%s: NULL config", __func__);
96 status = -EINVAL;
97 break;
98 }
99 st_ses_info= calloc(1, sizeof(struct sound_trigger_info ));
100 if (!st_ses_info) {
101 ALOGE("%s: st_ses_info alloc failed", __func__);
102 status = -ENOMEM;
103 break;
104 }
105 memcpy(&st_ses_info->st_ses, &config->st_ses, sizeof (config->st_ses));
106 ALOGV("%s: add capture_handle %d pcm %p", __func__,
107 st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.pcm);
108 list_add_tail(&st_dev->st_ses_list, &st_ses_info->list);
109 break;
110
111 case ST_EVENT_SESSION_DEREGISTER:
112 if (!config) {
113 ALOGE("%s: NULL config", __func__);
114 status = -EINVAL;
115 break;
116 }
117 st_ses_info = get_sound_trigger_info(config->st_ses.capture_handle);
118 if (!st_ses_info) {
119 ALOGE("%s: pcm %p not in the list!", __func__, config->st_ses.pcm);
120 status = -EINVAL;
121 break;
122 }
123 ALOGV("%s: remove capture_handle %d pcm %p", __func__,
124 st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.pcm);
125 list_remove(&st_ses_info->list);
126 free(st_ses_info);
127 break;
128 default:
129 ALOGW("%s: Unknown event %d", __func__, event);
130 break;
131 }
132 pthread_mutex_unlock(&st_dev->lock);
133 return status;
134}
135
136int audio_extn_sound_trigger_read(struct stream_in *in, void *buffer,
137 size_t bytes)
138{
139 int ret = -1;
140 struct sound_trigger_info *st_info = NULL;
141 audio_event_info_t event;
142
143 if (!st_dev)
144 return ret;
145
146 if (!in->is_st_session_active) {
147 ALOGE(" %s: Sound trigger is not active", __func__);
148 goto exit;
149 }
150 if (in->standby)
151 in->standby = false;
152
153 pthread_mutex_lock(&st_dev->lock);
154 st_info = get_sound_trigger_info(in->capture_handle);
155 pthread_mutex_unlock(&st_dev->lock);
156 if (st_info) {
157 event.u.aud_info.ses_info = &st_info->st_ses;
158 event.u.aud_info.buf = buffer;
159 event.u.aud_info.num_bytes = bytes;
160 ret = st_dev->st_callback(AUDIO_EVENT_READ_SAMPLES, &event);
161 }
162
163exit:
164 if (ret) {
165 if (-ENETRESET == ret)
166 in->is_st_session_active = false;
167 memset(buffer, 0, bytes);
168 ALOGV("%s: read failed status %d - sleep", __func__, ret);
169 usleep((bytes * 1000000) / (audio_stream_in_frame_size((struct audio_stream_in *)in) *
170 in->config.rate));
171 }
172 return ret;
173}
174
175void audio_extn_sound_trigger_stop_lab(struct stream_in *in)
176{
177 int status = 0;
178 struct sound_trigger_info *st_ses_info = NULL;
179 audio_event_info_t event;
180
181 if (!st_dev || !in)
182 return;
183
184 pthread_mutex_lock(&st_dev->lock);
185 st_ses_info = get_sound_trigger_info(in->capture_handle);
186 pthread_mutex_unlock(&st_dev->lock);
187 if (st_ses_info) {
188 event.u.ses_info = st_ses_info->st_ses;
189 ALOGV("%s: AUDIO_EVENT_STOP_LAB pcm %p", __func__, st_ses_info->st_ses.pcm);
190 st_dev->st_callback(AUDIO_EVENT_STOP_LAB, &event);
191 }
192}
193void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in)
194{
195 struct sound_trigger_info *st_ses_info = NULL;
196 struct listnode *node;
197
198 if (!st_dev || !in)
199 return;
200
201 pthread_mutex_lock(&st_dev->lock);
202 in->is_st_session = false;
203 ALOGV("%s: list %d capture_handle %d", __func__,
204 list_empty(&st_dev->st_ses_list), in->capture_handle);
205 list_for_each(node, &st_dev->st_ses_list) {
206 st_ses_info = node_to_item(node, struct sound_trigger_info , list);
207 if (st_ses_info->st_ses.capture_handle == in->capture_handle) {
208 in->pcm = st_ses_info->st_ses.pcm;
209 in->config = st_ses_info->st_ses.config;
210 in->channel_mask = audio_channel_in_mask_from_count(in->config.channels);
211 in->is_st_session = true;
212 in->is_st_session_active = true;
Joe Onorato188b6222016-03-01 11:02:27 -0800213 ALOGV("%s: capture_handle %d is sound trigger", __func__, in->capture_handle);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700214 break;
215 }
216 }
217 pthread_mutex_unlock(&st_dev->lock);
218}
219
220void audio_extn_sound_trigger_update_device_status(snd_device_t snd_device,
221 st_event_type_t event)
222{
223 int device_type = -1;
224
225 if (!st_dev)
226 return;
227
228 if (snd_device >= SND_DEVICE_OUT_BEGIN &&
Ravi Kumar Alamanda888dc3d2015-10-01 15:53:33 -0700229 snd_device < SND_DEVICE_OUT_END) {
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700230 device_type = PCM_PLAYBACK;
Ravi Kumar Alamanda888dc3d2015-10-01 15:53:33 -0700231 } else if (snd_device >= SND_DEVICE_IN_BEGIN &&
232 snd_device < SND_DEVICE_IN_END) {
233 if (snd_device == SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)
234 return;
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700235 device_type = PCM_CAPTURE;
Ravi Kumar Alamanda888dc3d2015-10-01 15:53:33 -0700236 } else {
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700237 ALOGE("%s: invalid device 0x%x, for event %d",
238 __func__, snd_device, event);
239 return;
240 }
241
Joe Onorato188b6222016-03-01 11:02:27 -0800242 ALOGV("%s: device 0x%x of type %d for Event %d",
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700243 __func__, snd_device, device_type, event);
244 if (device_type == PCM_CAPTURE) {
245 switch(event) {
246 case ST_EVENT_SND_DEVICE_FREE:
247 st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE, NULL);
248 break;
249 case ST_EVENT_SND_DEVICE_BUSY:
250 st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_ACTIVE, NULL);
251 break;
252 default:
253 ALOGW("%s:invalid event %d for device 0x%x",
254 __func__, event, snd_device);
255 }
256 }/*Events for output device, if required can be placed here in else*/
257}
258
259void audio_extn_sound_trigger_set_parameters(struct audio_device *adev __unused,
260 struct str_parms *params)
261{
262 audio_event_info_t event;
263 char value[32];
264 int ret, val;
265
266 if(!st_dev || !params) {
267 ALOGE("%s: str_params NULL", __func__);
268 return;
269 }
270
271 ret = str_parms_get_str(params, "SND_CARD_STATUS", value,
272 sizeof(value));
273 if (ret > 0) {
274 if (strstr(value, "OFFLINE")) {
275 event.u.status = SND_CARD_STATUS_OFFLINE;
276 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
277 }
278 else if (strstr(value, "ONLINE")) {
279 event.u.status = SND_CARD_STATUS_ONLINE;
280 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
281 }
282 else
283 ALOGE("%s: unknown snd_card_status", __func__);
284 }
285
286 ret = str_parms_get_str(params, "CPE_STATUS", value, sizeof(value));
287 if (ret > 0) {
288 if (strstr(value, "OFFLINE")) {
289 event.u.status = CPE_STATUS_OFFLINE;
290 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
291 }
292 else if (strstr(value, "ONLINE")) {
293 event.u.status = CPE_STATUS_ONLINE;
294 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
295 }
296 else
297 ALOGE("%s: unknown CPE status", __func__);
298 }
299
300 ret = str_parms_get_int(params, "SVA_NUM_SESSIONS", &val);
301 if (ret >= 0) {
302 event.u.value = val;
303 st_dev->st_callback(AUDIO_EVENT_NUM_ST_SESSIONS, &event);
304 }
305}
306
307int audio_extn_sound_trigger_init(struct audio_device *adev)
308{
309 int status = 0;
310 char sound_trigger_lib[100];
311 void *lib_handle;
312
Joe Onorato188b6222016-03-01 11:02:27 -0800313 ALOGV("%s: Enter", __func__);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700314
315 st_dev = (struct sound_trigger_audio_device*)
316 calloc(1, sizeof(struct sound_trigger_audio_device));
317 if (!st_dev) {
318 ALOGE("%s: ERROR. sound trigger alloc failed", __func__);
319 return -ENOMEM;
320 }
321
322 snprintf(sound_trigger_lib, sizeof(sound_trigger_lib),
Andy Hung4bd229e2016-03-07 18:29:16 -0800323 SOUND_TRIGGER_LIBRARY_PATH,
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700324 XSTR(SOUND_TRIGGER_PLATFORM_NAME));
325
326 st_dev->lib_handle = dlopen(sound_trigger_lib, RTLD_NOW);
327
328 if (st_dev->lib_handle == NULL) {
329 ALOGE("%s: DLOPEN failed for %s. error = %s", __func__, sound_trigger_lib,
330 dlerror());
331 status = -EINVAL;
332 goto cleanup;
333 }
Joe Onorato188b6222016-03-01 11:02:27 -0800334 ALOGV("%s: DLOPEN successful for %s", __func__, sound_trigger_lib);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700335
336 st_dev->st_callback = (sound_trigger_hw_call_back_t)
337 dlsym(st_dev->lib_handle, "sound_trigger_hw_call_back");
338
339 if (st_dev->st_callback == NULL) {
340 ALOGE("%s: ERROR. dlsym Error:%s sound_trigger_hw_call_back", __func__,
341 dlerror());
342 goto cleanup;
343 }
344
345 st_dev->adev = adev;
346 list_init(&st_dev->st_ses_list);
Haynes Mathew Georgeceafc552017-05-24 15:44:23 -0700347 audio_extn_snd_mon_register_listener(st_dev, stdev_snd_mon_cb);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700348
349 return 0;
350
351cleanup:
352 if (st_dev->lib_handle)
353 dlclose(st_dev->lib_handle);
354 free(st_dev);
355 st_dev = NULL;
356 return status;
357
358}
359
360void audio_extn_sound_trigger_deinit(struct audio_device *adev)
361{
Joe Onorato188b6222016-03-01 11:02:27 -0800362 ALOGV("%s: Enter", __func__);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700363 if (st_dev && (st_dev->adev == adev) && st_dev->lib_handle) {
Haynes Mathew Georgeceafc552017-05-24 15:44:23 -0700364 audio_extn_snd_mon_unregister_listener(st_dev);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700365 dlclose(st_dev->lib_handle);
366 free(st_dev);
367 st_dev = NULL;
368 }
369}