blob: 9051334a2ad1597904da9fb2caffbb65f88d689c [file] [log] [blame]
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
2 *
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
33#include <stdbool.h>
34#include <stdlib.h>
35#include <dlfcn.h>
36#include <cutils/log.h>
37#include "audio_hw.h"
38#include "audio_extn.h"
39#include "platform.h"
40#include "platform_api.h"
41#include "sound_trigger_prop_intf.h"
42
43#define XSTR(x) STR(x)
44#define STR(x) #x
45
46struct sound_trigger_info {
47 struct sound_trigger_session_info st_ses;
48 bool lab_stopped;
49 struct listnode list;
50};
51
52struct sound_trigger_audio_device {
53 void *lib_handle;
54 struct audio_device *adev;
55 sound_trigger_hw_call_back_t st_callback;
56 struct listnode st_ses_list;
57 pthread_mutex_t lock;
58};
59
60static struct sound_trigger_audio_device *st_dev;
61
62static struct sound_trigger_info *
63get_sound_trigger_info(int capture_handle)
64{
65 struct sound_trigger_info *st_ses_info = NULL;
66 struct listnode *node;
67 ALOGD("%s: list %d capture_handle %d", __func__,
68 list_empty(&st_dev->st_ses_list), capture_handle);
69 list_for_each(node, &st_dev->st_ses_list) {
70 st_ses_info = node_to_item(node, struct sound_trigger_info , list);
71 if (st_ses_info->st_ses.capture_handle == capture_handle)
72 return st_ses_info;
73 }
74 return NULL;
75}
76
77int audio_hw_call_back(sound_trigger_event_type_t event,
78 sound_trigger_event_info_t* config)
79{
80 int status = 0;
81 struct sound_trigger_info *st_ses_info;
82
83 if (!st_dev)
84 return -EINVAL;
85
86 pthread_mutex_lock(&st_dev->lock);
87 switch (event) {
88 case ST_EVENT_SESSION_REGISTER:
89 if (!config) {
90 ALOGE("%s: NULL config", __func__);
91 status = -EINVAL;
92 break;
93 }
94 st_ses_info= calloc(1, sizeof(struct sound_trigger_info ));
95 if (!st_ses_info) {
96 ALOGE("%s: st_ses_info alloc failed", __func__);
97 status = -ENOMEM;
98 break;
99 }
100 memcpy(&st_ses_info->st_ses, &config->st_ses, sizeof (config->st_ses));
101 ALOGV("%s: add capture_handle %d pcm %p", __func__,
102 st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.pcm);
103 list_add_tail(&st_dev->st_ses_list, &st_ses_info->list);
104 break;
105
106 case ST_EVENT_SESSION_DEREGISTER:
107 if (!config) {
108 ALOGE("%s: NULL config", __func__);
109 status = -EINVAL;
110 break;
111 }
112 st_ses_info = get_sound_trigger_info(config->st_ses.capture_handle);
113 if (!st_ses_info) {
114 ALOGE("%s: pcm %p not in the list!", __func__, config->st_ses.pcm);
115 status = -EINVAL;
116 break;
117 }
118 ALOGV("%s: remove capture_handle %d pcm %p", __func__,
119 st_ses_info->st_ses.capture_handle, st_ses_info->st_ses.pcm);
120 list_remove(&st_ses_info->list);
121 free(st_ses_info);
122 break;
123 default:
124 ALOGW("%s: Unknown event %d", __func__, event);
125 break;
126 }
127 pthread_mutex_unlock(&st_dev->lock);
128 return status;
129}
130
131void audio_extn_sound_trigger_stop_lab(struct stream_in *in)
132{
133 int status = 0;
134 struct sound_trigger_info *st_ses_info = NULL;
135 audio_event_info_t event;
136
137 if (!st_dev || !in)
138 return;
139
140 pthread_mutex_lock(&st_dev->lock);
141 st_ses_info = get_sound_trigger_info(in->capture_handle);
Bharath Ramachandramurthy5baa6a52014-10-21 11:18:49 -0700142 pthread_mutex_unlock(&st_dev->lock);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700143 if (st_ses_info) {
144 event.u.ses_info = st_ses_info->st_ses;
145 ALOGV("%s: AUDIO_EVENT_STOP_LAB pcm %p", __func__, st_ses_info->st_ses.pcm);
146 st_dev->st_callback(AUDIO_EVENT_STOP_LAB, &event);
147 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700148}
149void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in)
150{
151 struct sound_trigger_info *st_ses_info = NULL;
152 struct listnode *node;
153
154 if (!st_dev || !in)
155 return;
156
157 pthread_mutex_lock(&st_dev->lock);
158 in->is_st_session = false;
159 ALOGV("%s: list %d capture_handle %d", __func__,
160 list_empty(&st_dev->st_ses_list), in->capture_handle);
161 list_for_each(node, &st_dev->st_ses_list) {
162 st_ses_info = node_to_item(node, struct sound_trigger_info , list);
163 if (st_ses_info->st_ses.capture_handle == in->capture_handle) {
164 in->pcm = st_ses_info->st_ses.pcm;
165 in->config = st_ses_info->st_ses.config;
166 in->channel_mask = audio_channel_in_mask_from_count(in->config.channels);
167 in->is_st_session = true;
Bharath Ramachandramurthy837535b2015-02-05 14:27:59 -0800168 in->is_st_session_active = true;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700169 ALOGD("%s: capture_handle %d is sound trigger", __func__, in->capture_handle);
170 break;
171 }
172 }
173 pthread_mutex_unlock(&st_dev->lock);
174}
175
176void audio_extn_sound_trigger_update_device_status(snd_device_t snd_device,
177 st_event_type_t event)
178{
179 bool raise_event = false;
180 int device_type = -1;
181
182 if (!st_dev)
183 return;
184
185 if (snd_device >= SND_DEVICE_OUT_BEGIN &&
186 snd_device < SND_DEVICE_OUT_END)
187 device_type = PCM_PLAYBACK;
188 else if (snd_device >= SND_DEVICE_IN_BEGIN &&
189 snd_device < SND_DEVICE_IN_END)
190 device_type = PCM_CAPTURE;
191 else {
192 ALOGE("%s: invalid device 0x%x, for event %d",
193 __func__, snd_device, event);
194 return;
195 }
196
197 raise_event = platform_sound_trigger_device_needs_event(snd_device);
198 ALOGI("%s: device 0x%x of type %d for Event %d, with Raise=%d",
199 __func__, snd_device, device_type, event, raise_event);
200 if (raise_event && (device_type == PCM_CAPTURE)) {
201 switch(event) {
202 case ST_EVENT_SND_DEVICE_FREE:
203 st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_INACTIVE, NULL);
204 break;
205 case ST_EVENT_SND_DEVICE_BUSY:
206 st_dev->st_callback(AUDIO_EVENT_CAPTURE_DEVICE_ACTIVE, NULL);
207 break;
208 default:
209 ALOGW("%s:invalid event %d for device 0x%x",
210 __func__, event, snd_device);
211 }
212 }/*Events for output device, if required can be placed here in else*/
213}
214
215void audio_extn_sound_trigger_update_stream_status(struct audio_usecase *uc_info,
216 st_event_type_t event)
217{
218 bool raise_event = false;
219 audio_usecase_t uc_id;
220 int usecase_type = -1;
221
222 if (!st_dev) {
223 return;
224 }
225
226 if (uc_info == NULL) {
227 ALOGE("%s: usecase is NULL!!!", __func__);
228 return;
229 }
230 uc_id = uc_info->id;
231 usecase_type = uc_info->type;
232
233 raise_event = platform_sound_trigger_usecase_needs_event(uc_id);
234 ALOGD("%s: uc_id %d of type %d for Event %d, with Raise=%d",
235 __func__, uc_id, usecase_type, event, raise_event);
236 if (raise_event && (usecase_type == PCM_PLAYBACK)) {
237 switch(event) {
238 case ST_EVENT_STREAM_FREE:
239 st_dev->st_callback(AUDIO_EVENT_PLAYBACK_STREAM_INACTIVE, NULL);
240 break;
241 case ST_EVENT_STREAM_BUSY:
242 st_dev->st_callback(AUDIO_EVENT_PLAYBACK_STREAM_ACTIVE, NULL);
243 break;
244 default:
245 ALOGW("%s:invalid event %d, for usecase %d",
246 __func__, event, uc_id);
247 }
248 }/*Events for capture usecase, if required can be placed here in else*/
249}
250
251void audio_extn_sound_trigger_set_parameters(struct audio_device *adev __unused,
252 struct str_parms *params)
253{
254 audio_event_info_t event;
255 char value[32];
Bharath Ramachandramurthyc694f8a2014-09-25 16:15:12 -0700256 int ret, val;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700257
258 if(!st_dev || !params) {
259 ALOGE("%s: str_params NULL", __func__);
260 return;
261 }
262
263 ret = str_parms_get_str(params, "SND_CARD_STATUS", value,
264 sizeof(value));
265 if (ret > 0) {
266 if (strstr(value, "OFFLINE")) {
267 event.u.status = SND_CARD_STATUS_OFFLINE;
268 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
269 }
270 else if (strstr(value, "ONLINE")) {
271 event.u.status = SND_CARD_STATUS_ONLINE;
272 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
273 }
274 else
275 ALOGE("%s: unknown snd_card_status", __func__);
276 }
277
278 ret = str_parms_get_str(params, "CPE_STATUS", value, sizeof(value));
279 if (ret > 0) {
280 if (strstr(value, "OFFLINE")) {
281 event.u.status = CPE_STATUS_OFFLINE;
282 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
283 }
284 else if (strstr(value, "ONLINE")) {
285 event.u.status = CPE_STATUS_ONLINE;
286 st_dev->st_callback(AUDIO_EVENT_SSR, &event);
287 }
288 else
289 ALOGE("%s: unknown CPE status", __func__);
290 }
Bharath Ramachandramurthyc694f8a2014-09-25 16:15:12 -0700291
292 ret = str_parms_get_int(params, "SVA_NUM_SESSIONS", &val);
293 if (ret >= 0) {
294 event.u.value = val;
295 st_dev->st_callback(AUDIO_EVENT_NUM_ST_SESSIONS, &event);
296 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -0700297}
298
299int audio_extn_sound_trigger_init(struct audio_device *adev)
300{
301 int status = 0;
302 char sound_trigger_lib[100];
303 void *lib_handle;
304
305 ALOGI("%s: Enter", __func__);
306
307 st_dev = (struct sound_trigger_audio_device*)
308 calloc(1, sizeof(struct sound_trigger_audio_device));
309 if (!st_dev) {
310 ALOGE("%s: ERROR. sound trigger alloc failed", __func__);
311 return -ENOMEM;
312 }
313
314 snprintf(sound_trigger_lib, sizeof(sound_trigger_lib),
315 "/system/vendor/lib/hw/sound_trigger.primary.%s.so",
316 XSTR(SOUND_TRIGGER_PLATFORM_NAME));
317
318 st_dev->lib_handle = dlopen(sound_trigger_lib, RTLD_NOW);
319
320 if (st_dev->lib_handle == NULL) {
321 ALOGE("%s: DLOPEN failed for %s. error = %s", __func__, sound_trigger_lib,
322 dlerror());
323 status = -EINVAL;
324 goto cleanup;
325 }
326 ALOGI("%s: DLOPEN successful for %s", __func__, sound_trigger_lib);
327
328 st_dev->st_callback = (sound_trigger_hw_call_back_t)
329 dlsym(st_dev->lib_handle, "sound_trigger_hw_call_back");
330
331 if (st_dev->st_callback == NULL) {
332 ALOGE("%s: ERROR. dlsym Error:%s sound_trigger_hw_call_back", __func__,
333 dlerror());
334 goto cleanup;
335 }
336
337 st_dev->adev = adev;
338 list_init(&st_dev->st_ses_list);
339
340 return 0;
341
342cleanup:
343 if (st_dev->lib_handle)
344 dlclose(st_dev->lib_handle);
345 free(st_dev);
346 st_dev = NULL;
347 return status;
348
349}
350
351void audio_extn_sound_trigger_deinit(struct audio_device *adev)
352{
353 ALOGI("%s: Enter", __func__);
354 if (st_dev && (st_dev->adev == adev) && st_dev->lib_handle) {
355 dlclose(st_dev->lib_handle);
356 free(st_dev);
357 st_dev = NULL;
358 }
359}