blob: 6142e86127e94fb7cf4491cdf42df19801da3554 [file] [log] [blame]
Mingming Yinfd7607b2016-01-22 12:48:44 -08001/* Copyright (c) 2013-2014, 2016 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
46
47struct sound_trigger_info {
48 struct sound_trigger_session_info st_ses;
49 bool lab_stopped;
50 struct listnode list;
51};
52
53struct sound_trigger_audio_device {
54 void *lib_handle;
55 struct audio_device *adev;
56 sound_trigger_hw_call_back_t st_callback;
57 struct listnode st_ses_list;
58 pthread_mutex_t lock;
59};
60
61static struct sound_trigger_audio_device *st_dev;
62
63static struct sound_trigger_info *
64get_sound_trigger_info(int capture_handle)
65{
66 struct sound_trigger_info *st_ses_info = NULL;
67 struct listnode *node;
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -070068 ALOGV("%s: list empty %d capture_handle %d", __func__,
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070069 list_empty(&st_dev->st_ses_list), capture_handle);
70 list_for_each(node, &st_dev->st_ses_list) {
71 st_ses_info = node_to_item(node, struct sound_trigger_info , list);
72 if (st_ses_info->st_ses.capture_handle == capture_handle)
73 return st_ses_info;
74 }
75 return NULL;
76}
77
78int audio_hw_call_back(sound_trigger_event_type_t event,
79 sound_trigger_event_info_t* config)
80{
81 int status = 0;
82 struct sound_trigger_info *st_ses_info;
83
84 if (!st_dev)
85 return -EINVAL;
86
87 pthread_mutex_lock(&st_dev->lock);
88 switch (event) {
89 case ST_EVENT_SESSION_REGISTER:
90 if (!config) {
91 ALOGE("%s: NULL config", __func__);
92 status = -EINVAL;
93 break;
94 }
95 st_ses_info= calloc(1, sizeof(struct sound_trigger_info ));
96 if (!st_ses_info) {
97 ALOGE("%s: st_ses_info alloc failed", __func__);
98 status = -ENOMEM;
99 break;
100 }
Shiv Maliyappanahalli0e283d32016-07-14 23:20:03 -0700101 memcpy(&st_ses_info->st_ses, &config->st_ses, sizeof (struct sound_trigger_session_info));
102 ALOGV("%s: add capture_handle %d st session opaque ptr %p", __func__,
103 st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.p_ses);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700104 list_add_tail(&st_dev->st_ses_list, &st_ses_info->list);
105 break;
106
107 case ST_EVENT_SESSION_DEREGISTER:
108 if (!config) {
109 ALOGE("%s: NULL config", __func__);
110 status = -EINVAL;
111 break;
112 }
113 st_ses_info = get_sound_trigger_info(config->st_ses.capture_handle);
114 if (!st_ses_info) {
Shiv Maliyappanahalli0e283d32016-07-14 23:20:03 -0700115 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 -0700116 status = -EINVAL;
117 break;
118 }
Shiv Maliyappanahalli0e283d32016-07-14 23:20:03 -0700119 ALOGV("%s: remove capture_handle %d st session opaque ptr %p", __func__,
120 st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.p_ses);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700121 list_remove(&st_ses_info->list);
122 free(st_ses_info);
123 break;
124 default:
125 ALOGW("%s: Unknown event %d", __func__, event);
126 break;
127 }
128 pthread_mutex_unlock(&st_dev->lock);
129 return status;
130}
131
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -0700132int audio_extn_sound_trigger_read(struct stream_in *in, void *buffer,
133 size_t bytes)
134{
135 int ret = -1;
136 struct sound_trigger_info *st_info = NULL;
137 audio_event_info_t event;
138
139 if (!st_dev)
140 return ret;
141
142 if (!in->is_st_session_active) {
143 ALOGE(" %s: Sound trigger is not active", __func__);
144 goto exit;
145 }
146 if(in->standby)
147 in->standby = false;
148
149 pthread_mutex_lock(&st_dev->lock);
150 st_info = get_sound_trigger_info(in->capture_handle);
151 pthread_mutex_unlock(&st_dev->lock);
152 if (st_info) {
153 event.u.aud_info.ses_info = &st_info->st_ses;
154 event.u.aud_info.buf = buffer;
155 event.u.aud_info.num_bytes = bytes;
156 ret = st_dev->st_callback(AUDIO_EVENT_READ_SAMPLES, &event);
157 }
158
159exit:
160 if (ret) {
161 if (-ENETRESET == ret)
162 in->is_st_session_active = false;
163 memset(buffer, 0, bytes);
164 ALOGV("%s: read failed status %d - sleep", __func__, ret);
165 usleep((bytes * 1000000) / (audio_stream_in_frame_size((struct audio_stream_in *)in) *
166 in->config.rate));
167 }
168 return ret;
169}
170
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700171void audio_extn_sound_trigger_stop_lab(struct stream_in *in)
172{
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700173 struct sound_trigger_info *st_ses_info = NULL;
174 audio_event_info_t event;
175
Mingming Yinfd7607b2016-01-22 12:48:44 -0800176 if (!st_dev || !in || !in->is_st_session_active)
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700177 return;
178
179 pthread_mutex_lock(&st_dev->lock);
180 st_ses_info = get_sound_trigger_info(in->capture_handle);
Bharath Ramachandramurthy5baa6a52014-10-21 11:18:49 -0700181 pthread_mutex_unlock(&st_dev->lock);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700182 if (st_ses_info) {
183 event.u.ses_info = st_ses_info->st_ses;
Shiv Maliyappanahalli0e283d32016-07-14 23:20:03 -0700184 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 -0700185 st_dev->st_callback(AUDIO_EVENT_STOP_LAB, &event);
Mingming Yinfd7607b2016-01-22 12:48:44 -0800186 in->is_st_session_active = false;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700187 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700188}
189void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in)
190{
191 struct sound_trigger_info *st_ses_info = NULL;
192 struct listnode *node;
193
194 if (!st_dev || !in)
195 return;
196
197 pthread_mutex_lock(&st_dev->lock);
198 in->is_st_session = false;
199 ALOGV("%s: list %d capture_handle %d", __func__,
200 list_empty(&st_dev->st_ses_list), in->capture_handle);
201 list_for_each(node, &st_dev->st_ses_list) {
202 st_ses_info = node_to_item(node, struct sound_trigger_info , list);
203 if (st_ses_info->st_ses.capture_handle == in->capture_handle) {
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700204 in->config = st_ses_info->st_ses.config;
205 in->channel_mask = audio_channel_in_mask_from_count(in->config.channels);
206 in->is_st_session = true;
Bharath Ramachandramurthy837535b2015-02-05 14:27:59 -0800207 in->is_st_session_active = true;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700208 ALOGD("%s: capture_handle %d is sound trigger", __func__, in->capture_handle);
209 break;
210 }
211 }
212 pthread_mutex_unlock(&st_dev->lock);
213}
214
215void audio_extn_sound_trigger_update_device_status(snd_device_t snd_device,
216 st_event_type_t event)
217{
218 bool raise_event = false;
219 int device_type = -1;
220
221 if (!st_dev)
222 return;
223
224 if (snd_device >= SND_DEVICE_OUT_BEGIN &&
225 snd_device < SND_DEVICE_OUT_END)
226 device_type = PCM_PLAYBACK;
227 else if (snd_device >= SND_DEVICE_IN_BEGIN &&
228 snd_device < SND_DEVICE_IN_END)
229 device_type = PCM_CAPTURE;
230 else {
231 ALOGE("%s: invalid device 0x%x, for event %d",
232 __func__, snd_device, event);
233 return;
234 }
235
236 raise_event = platform_sound_trigger_device_needs_event(snd_device);
237 ALOGI("%s: device 0x%x of type %d for Event %d, with Raise=%d",
238 __func__, snd_device, device_type, event, raise_event);
239 if (raise_event && (device_type == PCM_CAPTURE)) {
240 switch(event) {
241 case ST_EVENT_SND_DEVICE_FREE:
242 st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE, NULL);
243 break;
244 case ST_EVENT_SND_DEVICE_BUSY:
245 st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_ACTIVE, NULL);
246 break;
247 default:
248 ALOGW("%s:invalid event %d for device 0x%x",
249 __func__, event, snd_device);
250 }
251 }/*Events for output device, if required can be placed here in else*/
252}
253
254void audio_extn_sound_trigger_update_stream_status(struct audio_usecase *uc_info,
255 st_event_type_t event)
256{
257 bool raise_event = false;
258 audio_usecase_t uc_id;
259 int usecase_type = -1;
260
261 if (!st_dev) {
262 return;
263 }
264
265 if (uc_info == NULL) {
266 ALOGE("%s: usecase is NULL!!!", __func__);
267 return;
268 }
269 uc_id = uc_info->id;
270 usecase_type = uc_info->type;
271
272 raise_event = platform_sound_trigger_usecase_needs_event(uc_id);
273 ALOGD("%s: uc_id %d of type %d for Event %d, with Raise=%d",
274 __func__, uc_id, usecase_type, event, raise_event);
275 if (raise_event && (usecase_type == PCM_PLAYBACK)) {
276 switch(event) {
277 case ST_EVENT_STREAM_FREE:
278 st_dev->st_callback(AUDIO_EVENT_PLAYBACK_STREAM_INACTIVE, NULL);
279 break;
280 case ST_EVENT_STREAM_BUSY:
281 st_dev->st_callback(AUDIO_EVENT_PLAYBACK_STREAM_ACTIVE, NULL);
282 break;
283 default:
284 ALOGW("%s:invalid event %d, for usecase %d",
285 __func__, event, uc_id);
286 }
287 }/*Events for capture usecase, if required can be placed here in else*/
288}
289
290void audio_extn_sound_trigger_set_parameters(struct audio_device *adev __unused,
291 struct str_parms *params)
292{
293 audio_event_info_t event;
294 char value[32];
Bharath Ramachandramurthyc694f8a2014-09-25 16:15:12 -0700295 int ret, val;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700296
297 if(!st_dev || !params) {
298 ALOGE("%s: str_params NULL", __func__);
299 return;
300 }
301
302 ret = str_parms_get_str(params, "SND_CARD_STATUS", value,
303 sizeof(value));
304 if (ret > 0) {
305 if (strstr(value, "OFFLINE")) {
306 event.u.status = SND_CARD_STATUS_OFFLINE;
307 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
308 }
309 else if (strstr(value, "ONLINE")) {
310 event.u.status = SND_CARD_STATUS_ONLINE;
311 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
312 }
313 else
314 ALOGE("%s: unknown snd_card_status", __func__);
315 }
316
317 ret = str_parms_get_str(params, "CPE_STATUS", value, sizeof(value));
318 if (ret > 0) {
319 if (strstr(value, "OFFLINE")) {
320 event.u.status = CPE_STATUS_OFFLINE;
321 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
322 }
323 else if (strstr(value, "ONLINE")) {
324 event.u.status = CPE_STATUS_ONLINE;
325 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
326 }
327 else
328 ALOGE("%s: unknown CPE status", __func__);
329 }
Bharath Ramachandramurthyc694f8a2014-09-25 16:15:12 -0700330
331 ret = str_parms_get_int(params, "SVA_NUM_SESSIONS", &val);
332 if (ret >= 0) {
333 event.u.value = val;
334 st_dev->st_callback(AUDIO_EVENT_NUM_ST_SESSIONS, &event);
335 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700336}
337
338int audio_extn_sound_trigger_init(struct audio_device *adev)
339{
340 int status = 0;
341 char sound_trigger_lib[100];
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700342
343 ALOGI("%s: Enter", __func__);
344
345 st_dev = (struct sound_trigger_audio_device*)
346 calloc(1, sizeof(struct sound_trigger_audio_device));
347 if (!st_dev) {
348 ALOGE("%s: ERROR. sound trigger alloc failed", __func__);
349 return -ENOMEM;
350 }
351
352 snprintf(sound_trigger_lib, sizeof(sound_trigger_lib),
353 "/system/vendor/lib/hw/sound_trigger.primary.%s.so",
354 XSTR(SOUND_TRIGGER_PLATFORM_NAME));
355
356 st_dev->lib_handle = dlopen(sound_trigger_lib, RTLD_NOW);
357
358 if (st_dev->lib_handle == NULL) {
359 ALOGE("%s: DLOPEN failed for %s. error = %s", __func__, sound_trigger_lib,
360 dlerror());
361 status = -EINVAL;
362 goto cleanup;
363 }
364 ALOGI("%s: DLOPEN successful for %s", __func__, sound_trigger_lib);
365
366 st_dev->st_callback = (sound_trigger_hw_call_back_t)
367 dlsym(st_dev->lib_handle, "sound_trigger_hw_call_back");
368
369 if (st_dev->st_callback == NULL) {
370 ALOGE("%s: ERROR. dlsym Error:%s sound_trigger_hw_call_back", __func__,
371 dlerror());
372 goto cleanup;
373 }
374
375 st_dev->adev = adev;
376 list_init(&st_dev->st_ses_list);
377
378 return 0;
379
380cleanup:
381 if (st_dev->lib_handle)
382 dlclose(st_dev->lib_handle);
383 free(st_dev);
384 st_dev = NULL;
385 return status;
386
387}
388
389void audio_extn_sound_trigger_deinit(struct audio_device *adev)
390{
391 ALOGI("%s: Enter", __func__);
392 if (st_dev && (st_dev->adev == adev) && st_dev->lib_handle) {
393 dlclose(st_dev->lib_handle);
394 free(st_dev);
395 st_dev = NULL;
396 }
397}