blob: 112bd1e02f28a5c08a577b696b324c57226d8e73 [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>
24#include <cutils/log.h>
25#include "audio_hw.h"
26#include "audio_extn.h"
27#include "platform.h"
28#include "platform_api.h"
29#include "sound_trigger_prop_intf.h"
30
31#define XSTR(x) STR(x)
32#define STR(x) #x
33
Andy Hung7ddf8672016-03-31 10:30:42 -070034#ifdef __LP64__
35#define SOUND_TRIGGER_LIBRARY_PATH "/system/vendor/lib64/hw/sound_trigger.primary.%s.so"
36#else
37#define SOUND_TRIGGER_LIBRARY_PATH "/system/vendor/lib/hw/sound_trigger.primary.%s.so"
38#endif
Andy Hung4bd229e2016-03-07 18:29:16 -080039
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -070040struct sound_trigger_info {
41 struct sound_trigger_session_info st_ses;
42 bool lab_stopped;
43 struct listnode list;
44};
45
46struct sound_trigger_audio_device {
47 void *lib_handle;
48 struct audio_device *adev;
49 sound_trigger_hw_call_back_t st_callback;
50 struct listnode st_ses_list;
51 pthread_mutex_t lock;
52};
53
54static struct sound_trigger_audio_device *st_dev;
55
56static struct sound_trigger_info *
57get_sound_trigger_info(int capture_handle)
58{
59 struct sound_trigger_info *st_ses_info = NULL;
60 struct listnode *node;
61 ALOGV("%s: list %d capture_handle %d", __func__,
62 list_empty(&st_dev->st_ses_list), capture_handle);
63 list_for_each(node, &st_dev->st_ses_list) {
64 st_ses_info = node_to_item(node, struct sound_trigger_info , list);
65 if (st_ses_info->st_ses.capture_handle == capture_handle)
66 return st_ses_info;
67 }
68 return NULL;
69}
70
Haynes Mathew Georgeceafc552017-05-24 15:44:23 -070071static void stdev_snd_mon_cb(void * stream __unused, struct str_parms * parms)
72{
73 if (!parms)
74 return;
75
76 audio_extn_sound_trigger_set_parameters(NULL, parms);
77 return;
78}
79
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -070080int audio_hw_call_back(sound_trigger_event_type_t event,
81 sound_trigger_event_info_t* config)
82{
83 int status = 0;
84 struct sound_trigger_info *st_ses_info;
85
86 if (!st_dev)
87 return -EINVAL;
88
89 pthread_mutex_lock(&st_dev->lock);
90 switch (event) {
91 case ST_EVENT_SESSION_REGISTER:
92 if (!config) {
93 ALOGE("%s: NULL config", __func__);
94 status = -EINVAL;
95 break;
96 }
97 st_ses_info= calloc(1, sizeof(struct sound_trigger_info ));
98 if (!st_ses_info) {
99 ALOGE("%s: st_ses_info alloc failed", __func__);
100 status = -ENOMEM;
101 break;
102 }
103 memcpy(&st_ses_info->st_ses, &config->st_ses, sizeof (config->st_ses));
104 ALOGV("%s: add capture_handle %d pcm %p", __func__,
105 st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.pcm);
106 list_add_tail(&st_dev->st_ses_list, &st_ses_info->list);
107 break;
108
109 case ST_EVENT_SESSION_DEREGISTER:
110 if (!config) {
111 ALOGE("%s: NULL config", __func__);
112 status = -EINVAL;
113 break;
114 }
115 st_ses_info = get_sound_trigger_info(config->st_ses.capture_handle);
116 if (!st_ses_info) {
117 ALOGE("%s: pcm %p not in the list!", __func__, config->st_ses.pcm);
118 status = -EINVAL;
119 break;
120 }
121 ALOGV("%s: remove capture_handle %d pcm %p", __func__,
122 st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.pcm);
123 list_remove(&st_ses_info->list);
124 free(st_ses_info);
125 break;
126 default:
127 ALOGW("%s: Unknown event %d", __func__, event);
128 break;
129 }
130 pthread_mutex_unlock(&st_dev->lock);
131 return status;
132}
133
134int audio_extn_sound_trigger_read(struct stream_in *in, void *buffer,
135 size_t bytes)
136{
137 int ret = -1;
138 struct sound_trigger_info *st_info = NULL;
139 audio_event_info_t event;
140
141 if (!st_dev)
142 return ret;
143
144 if (!in->is_st_session_active) {
145 ALOGE(" %s: Sound trigger is not active", __func__);
146 goto exit;
147 }
148 if (in->standby)
149 in->standby = false;
150
151 pthread_mutex_lock(&st_dev->lock);
152 st_info = get_sound_trigger_info(in->capture_handle);
153 pthread_mutex_unlock(&st_dev->lock);
154 if (st_info) {
155 event.u.aud_info.ses_info = &st_info->st_ses;
156 event.u.aud_info.buf = buffer;
157 event.u.aud_info.num_bytes = bytes;
158 ret = st_dev->st_callback(AUDIO_EVENT_READ_SAMPLES, &event);
159 }
160
161exit:
162 if (ret) {
163 if (-ENETRESET == ret)
164 in->is_st_session_active = false;
165 memset(buffer, 0, bytes);
166 ALOGV("%s: read failed status %d - sleep", __func__, ret);
167 usleep((bytes * 1000000) / (audio_stream_in_frame_size((struct audio_stream_in *)in) *
168 in->config.rate));
169 }
170 return ret;
171}
172
173void audio_extn_sound_trigger_stop_lab(struct stream_in *in)
174{
175 int status = 0;
176 struct sound_trigger_info *st_ses_info = NULL;
177 audio_event_info_t event;
178
179 if (!st_dev || !in)
180 return;
181
182 pthread_mutex_lock(&st_dev->lock);
183 st_ses_info = get_sound_trigger_info(in->capture_handle);
184 pthread_mutex_unlock(&st_dev->lock);
185 if (st_ses_info) {
186 event.u.ses_info = st_ses_info->st_ses;
187 ALOGV("%s: AUDIO_EVENT_STOP_LAB pcm %p", __func__, st_ses_info->st_ses.pcm);
188 st_dev->st_callback(AUDIO_EVENT_STOP_LAB, &event);
189 }
190}
191void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in)
192{
193 struct sound_trigger_info *st_ses_info = NULL;
194 struct listnode *node;
195
196 if (!st_dev || !in)
197 return;
198
199 pthread_mutex_lock(&st_dev->lock);
200 in->is_st_session = false;
201 ALOGV("%s: list %d capture_handle %d", __func__,
202 list_empty(&st_dev->st_ses_list), in->capture_handle);
203 list_for_each(node, &st_dev->st_ses_list) {
204 st_ses_info = node_to_item(node, struct sound_trigger_info , list);
205 if (st_ses_info->st_ses.capture_handle == in->capture_handle) {
206 in->pcm = st_ses_info->st_ses.pcm;
207 in->config = st_ses_info->st_ses.config;
208 in->channel_mask = audio_channel_in_mask_from_count(in->config.channels);
209 in->is_st_session = true;
210 in->is_st_session_active = true;
Joe Onorato188b6222016-03-01 11:02:27 -0800211 ALOGV("%s: capture_handle %d is sound trigger", __func__, in->capture_handle);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700212 break;
213 }
214 }
215 pthread_mutex_unlock(&st_dev->lock);
216}
217
218void audio_extn_sound_trigger_update_device_status(snd_device_t snd_device,
219 st_event_type_t event)
220{
221 int device_type = -1;
222
223 if (!st_dev)
224 return;
225
226 if (snd_device >= SND_DEVICE_OUT_BEGIN &&
Ravi Kumar Alamanda888dc3d2015-10-01 15:53:33 -0700227 snd_device < SND_DEVICE_OUT_END) {
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700228 device_type = PCM_PLAYBACK;
Ravi Kumar Alamanda888dc3d2015-10-01 15:53:33 -0700229 } else if (snd_device >= SND_DEVICE_IN_BEGIN &&
230 snd_device < SND_DEVICE_IN_END) {
231 if (snd_device == SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)
232 return;
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700233 device_type = PCM_CAPTURE;
Ravi Kumar Alamanda888dc3d2015-10-01 15:53:33 -0700234 } else {
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700235 ALOGE("%s: invalid device 0x%x, for event %d",
236 __func__, snd_device, event);
237 return;
238 }
239
Joe Onorato188b6222016-03-01 11:02:27 -0800240 ALOGV("%s: device 0x%x of type %d for Event %d",
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700241 __func__, snd_device, device_type, event);
242 if (device_type == PCM_CAPTURE) {
243 switch(event) {
244 case ST_EVENT_SND_DEVICE_FREE:
245 st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE, NULL);
246 break;
247 case ST_EVENT_SND_DEVICE_BUSY:
248 st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_ACTIVE, NULL);
249 break;
250 default:
251 ALOGW("%s:invalid event %d for device 0x%x",
252 __func__, event, snd_device);
253 }
254 }/*Events for output device, if required can be placed here in else*/
255}
256
257void audio_extn_sound_trigger_set_parameters(struct audio_device *adev __unused,
258 struct str_parms *params)
259{
260 audio_event_info_t event;
261 char value[32];
262 int ret, val;
263
264 if(!st_dev || !params) {
265 ALOGE("%s: str_params NULL", __func__);
266 return;
267 }
268
269 ret = str_parms_get_str(params, "SND_CARD_STATUS", value,
270 sizeof(value));
271 if (ret > 0) {
272 if (strstr(value, "OFFLINE")) {
273 event.u.status = SND_CARD_STATUS_OFFLINE;
274 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
275 }
276 else if (strstr(value, "ONLINE")) {
277 event.u.status = SND_CARD_STATUS_ONLINE;
278 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
279 }
280 else
281 ALOGE("%s: unknown snd_card_status", __func__);
282 }
283
284 ret = str_parms_get_str(params, "CPE_STATUS", value, sizeof(value));
285 if (ret > 0) {
286 if (strstr(value, "OFFLINE")) {
287 event.u.status = CPE_STATUS_OFFLINE;
288 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
289 }
290 else if (strstr(value, "ONLINE")) {
291 event.u.status = CPE_STATUS_ONLINE;
292 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
293 }
294 else
295 ALOGE("%s: unknown CPE status", __func__);
296 }
297
298 ret = str_parms_get_int(params, "SVA_NUM_SESSIONS", &val);
299 if (ret >= 0) {
300 event.u.value = val;
301 st_dev->st_callback(AUDIO_EVENT_NUM_ST_SESSIONS, &event);
302 }
303}
304
305int audio_extn_sound_trigger_init(struct audio_device *adev)
306{
307 int status = 0;
308 char sound_trigger_lib[100];
309 void *lib_handle;
310
Joe Onorato188b6222016-03-01 11:02:27 -0800311 ALOGV("%s: Enter", __func__);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700312
313 st_dev = (struct sound_trigger_audio_device*)
314 calloc(1, sizeof(struct sound_trigger_audio_device));
315 if (!st_dev) {
316 ALOGE("%s: ERROR. sound trigger alloc failed", __func__);
317 return -ENOMEM;
318 }
319
320 snprintf(sound_trigger_lib, sizeof(sound_trigger_lib),
Andy Hung4bd229e2016-03-07 18:29:16 -0800321 SOUND_TRIGGER_LIBRARY_PATH,
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700322 XSTR(SOUND_TRIGGER_PLATFORM_NAME));
323
324 st_dev->lib_handle = dlopen(sound_trigger_lib, RTLD_NOW);
325
326 if (st_dev->lib_handle == NULL) {
327 ALOGE("%s: DLOPEN failed for %s. error = %s", __func__, sound_trigger_lib,
328 dlerror());
329 status = -EINVAL;
330 goto cleanup;
331 }
Joe Onorato188b6222016-03-01 11:02:27 -0800332 ALOGV("%s: DLOPEN successful for %s", __func__, sound_trigger_lib);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700333
334 st_dev->st_callback = (sound_trigger_hw_call_back_t)
335 dlsym(st_dev->lib_handle, "sound_trigger_hw_call_back");
336
337 if (st_dev->st_callback == NULL) {
338 ALOGE("%s: ERROR. dlsym Error:%s sound_trigger_hw_call_back", __func__,
339 dlerror());
340 goto cleanup;
341 }
342
343 st_dev->adev = adev;
344 list_init(&st_dev->st_ses_list);
Haynes Mathew Georgeceafc552017-05-24 15:44:23 -0700345 audio_extn_snd_mon_register_listener(st_dev, stdev_snd_mon_cb);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700346
347 return 0;
348
349cleanup:
350 if (st_dev->lib_handle)
351 dlclose(st_dev->lib_handle);
352 free(st_dev);
353 st_dev = NULL;
354 return status;
355
356}
357
358void audio_extn_sound_trigger_deinit(struct audio_device *adev)
359{
Joe Onorato188b6222016-03-01 11:02:27 -0800360 ALOGV("%s: Enter", __func__);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700361 if (st_dev && (st_dev->adev == adev) && st_dev->lib_handle) {
Haynes Mathew Georgeceafc552017-05-24 15:44:23 -0700362 audio_extn_snd_mon_unregister_listener(st_dev);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700363 dlclose(st_dev->lib_handle);
364 free(st_dev);
365 st_dev = NULL;
366 }
367}