blob: 9bee2a1b0bb4e784c3e9dcb754895d6f0628d1e7 [file] [log] [blame]
Weiyin Jianga3719ac2016-11-23 19:29:35 +08001/*
2* Copyright (c) 2017, The Linux Foundation. All rights reserved.
3*
4* Redistribution and use in source and binary forms, with or without
5* modification, are permitted provided that the following conditions are
6* met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above
10* copyright notice, this list of conditions and the following
11* disclaimer in the documentation and/or other materials provided
12* with the distribution.
13* * Neither the name of The Linux Foundation nor the names of its
14* contributors may be used to endorse or promote products derived
15* from this software without specific prior written permission.
16*
17* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*/
29
30#define LOG_TAG "qahw_effect"
31//#define LOG_NDEBUG 0
32#define LOG_NDDEBUG 0
33
34#include <cutils/list.h>
35#include <dlfcn.h>
36#include <utils/Log.h>
37#include <hardware/audio.h>
38#include <hardware/audio_effect.h>
39#include <stdlib.h>
40
Sachin Mohan Gadag25328bd2017-12-06 16:04:16 +053041#include "qahw.h"
Weiyin Jianga3719ac2016-11-23 19:29:35 +080042
43// The current effect API version.
44#define QAHW_EFFECT_API_VERSION_CURRENT QAHW_EFFECT_API_VERSION_0_0
45#define PATH_MAX 4096
46
47typedef struct {
48 char lib_path[PATH_MAX];
49 pthread_mutex_t lock;
50 uint32_t ref_count;
51 audio_effect_library_t *desc;
52 void *handle;
53 struct listnode lib_list;
54} qahw_effect_lib_t;
55
56// list of loaded effect libraries
57static struct listnode effect_libraries_list;
58static int effect_libraries_count = 0;
59static pthread_mutex_t effect_libraries_lock = PTHREAD_MUTEX_INITIALIZER;
60
61qahw_effect_lib_t *get_qahw_effect_lib_by_name(const char *lib_path) {
62 struct listnode *node = NULL;
63 qahw_effect_lib_t *effect_lib = NULL, *effect_lib_temp = NULL;
64
65 if (lib_path == NULL)
66 goto exit;
67
68 list_for_each(node, &effect_libraries_list) {
69 effect_lib_temp = node_to_item(node, qahw_effect_lib_t, lib_list);
70 if(!strncmp(lib_path, effect_lib_temp->lib_path, PATH_MAX)) {
71 effect_lib = effect_lib_temp;
72 break;
73 }
74 }
75exit:
76 return effect_lib;
77}
78
79
80qahw_effect_lib_t *get_qahw_effect_lib_by_desc(qahw_effect_lib_handle_t handle) {
81 struct listnode *node = NULL;
82 qahw_effect_lib_t *effect_lib = NULL, *effect_lib_temp = NULL;
83
84 if (handle == NULL)
85 goto exit;
86
87 list_for_each(node, &effect_libraries_list) {
88 effect_lib_temp = node_to_item(node, qahw_effect_lib_t, lib_list);
89 if (effect_lib_temp->desc == (audio_effect_library_t *)handle) {
90 effect_lib = effect_lib_temp;
91 break;
92 }
93 }
94exit:
95 return effect_lib;
96}
97
98
Trinath Thammishetty85b19292017-12-18 14:56:50 +053099qahw_effect_lib_handle_t qahw_effect_load_library_l(const char *lib_path) {
Weiyin Jianga3719ac2016-11-23 19:29:35 +0800100 audio_effect_library_t *desc;
101 qahw_effect_lib_t *qahw_effect_lib;
102 void *handle;
103
104 if (strlen(lib_path) >= PATH_MAX -1) {
105 ALOGE("%s: effect libraries path too long", __func__);
106 return NULL;
107 }
108
109 /* return existing lib handler if already loaded */
110 pthread_mutex_lock(&effect_libraries_lock);
111 if (effect_libraries_count > 0) {
112 qahw_effect_lib = get_qahw_effect_lib_by_name(lib_path);
113 if (qahw_effect_lib != NULL) {
114 desc = qahw_effect_lib->desc;
115 pthread_mutex_lock(&qahw_effect_lib->lock);
116 qahw_effect_lib->ref_count++;
117 pthread_mutex_unlock(&qahw_effect_lib->lock);
118 goto done;
119 }
120 }
121
122 handle = dlopen(lib_path, RTLD_NOW);
123 if (handle == NULL) {
124 ALOGE("%s: failed to dlopen lib %s", __func__, lib_path);
125 goto error;
126 }
127
128 desc = (audio_effect_library_t *)dlsym(handle, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
129 if (desc == NULL) {
130 ALOGE("%s: could not find symbol %s", __func__, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
131 goto error;
132 }
133
134 if (AUDIO_EFFECT_LIBRARY_TAG != desc->tag) {
135 ALOGE("%s: bad tag %08x in lib info struct", __func__, desc->tag);
136 goto error;
137 }
138
139 if (EFFECT_API_VERSION_MAJOR(desc->version) !=
140 EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION)) {
141 ALOGE("%s: bad lib version %08x", __func__, desc->version);
142 goto error;
143 }
144
145 qahw_effect_lib = (qahw_effect_lib_t *)calloc(1, sizeof(qahw_effect_lib_t));
146 if (qahw_effect_lib == NULL) {
147 ALOGE("%s: calloc failed", __func__);
148 goto error;
149 }
150
151 if (!effect_libraries_count)
152 list_init(&effect_libraries_list);
153 effect_libraries_count++;
154
155 /* init and load effect lib into global list */
156 strlcpy(qahw_effect_lib->lib_path, lib_path, PATH_MAX);
157 pthread_mutex_init(&qahw_effect_lib->lock, (const pthread_mutexattr_t *) NULL);
158 qahw_effect_lib->ref_count = 1;
159 qahw_effect_lib->desc = desc;
160 qahw_effect_lib->handle = handle;
161
162 list_add_tail(&effect_libraries_list, &qahw_effect_lib->lib_list);
163
164done:
165 pthread_mutex_unlock(&effect_libraries_lock);
166 return (qahw_effect_lib_handle_t)desc;
167
168error:
169 if (handle != NULL)
170 dlclose(handle);
171
172 pthread_mutex_unlock(&effect_libraries_lock);
173 return NULL;
174}
175
176
Trinath Thammishetty85b19292017-12-18 14:56:50 +0530177int32_t qahw_effect_unload_library_l(qahw_effect_lib_handle_t handle) {
Weiyin Jianga3719ac2016-11-23 19:29:35 +0800178 qahw_effect_lib_t *qahw_effect_lib;
179
180 pthread_mutex_lock(&effect_libraries_lock);
181 if (effect_libraries_count <= 0) {
182 ALOGW("%s: no valid libraries loaded", __func__);
183 pthread_mutex_unlock(&effect_libraries_lock);
184 return -EINVAL;
185 }
186
187 qahw_effect_lib = get_qahw_effect_lib_by_desc(handle);
188 if (qahw_effect_lib == NULL) {
189 ALOGW("%s: effect lib handle(%p) not in loaded queue", __func__, (void *)handle);
190 pthread_mutex_unlock(&effect_libraries_lock);
191 return -EINVAL;
192 }
193
194 pthread_mutex_lock(&qahw_effect_lib->lock);
195 qahw_effect_lib->ref_count--;
196 if (qahw_effect_lib->ref_count > 0) {
197 ALOGW("%s: skip unloading effect lib, ref count %d", __func__, qahw_effect_lib->ref_count);
198 pthread_mutex_unlock(&qahw_effect_lib->lock);
199 goto done;
200 }
201
202 if (qahw_effect_lib->handle)
203 dlclose(qahw_effect_lib->handle);
204 effect_libraries_count--;
205 list_remove(&qahw_effect_lib->lib_list);
206 pthread_mutex_unlock(&qahw_effect_lib->lock);
207 pthread_mutex_destroy(&qahw_effect_lib->lock);
208 free(qahw_effect_lib);
209
210done:
211 pthread_mutex_unlock(&effect_libraries_lock);
212 return 0;
213}
214
215
Trinath Thammishetty85b19292017-12-18 14:56:50 +0530216int32_t qahw_effect_create_l(qahw_effect_lib_handle_t handle,
Weiyin Jianga3719ac2016-11-23 19:29:35 +0800217 const qahw_effect_uuid_t *uuid,
218 int32_t io_handle,
219 qahw_effect_handle_t *effect_handle) {
220 int32_t rc = -EINVAL;
221 audio_effect_library_t *desc = (audio_effect_library_t *)handle;
222
223 if (desc != NULL) {
224 rc = desc->create_effect((const effect_uuid_t *)uuid, 0, io_handle,
225 (effect_handle_t *)effect_handle);
226 }
227
228 return rc;
229}
230
231
Trinath Thammishetty85b19292017-12-18 14:56:50 +0530232int32_t qahw_effect_release_l(qahw_effect_lib_handle_t handle,
Weiyin Jianga3719ac2016-11-23 19:29:35 +0800233 qahw_effect_handle_t effect_handle) {
234 int32_t rc = -EINVAL;
235 audio_effect_library_t *desc = (audio_effect_library_t *)handle;
236
237 if (desc != NULL) {
238 rc = desc->release_effect((effect_handle_t)effect_handle);
239 }
240
241 return rc;
242}
243
244
Trinath Thammishetty85b19292017-12-18 14:56:50 +0530245int32_t qahw_effect_get_descriptor_l(qahw_effect_lib_handle_t handle,
Weiyin Jianga3719ac2016-11-23 19:29:35 +0800246 const qahw_effect_uuid_t *uuid,
247 qahw_effect_descriptor_t *effect_desc) {
248 int32_t rc = -EINVAL;
249 audio_effect_library_t *desc = (audio_effect_library_t *)handle;
250
251 if (desc != NULL) {
252 rc = desc->get_descriptor((const effect_uuid_t *)uuid, (effect_descriptor_t *)effect_desc);
253 }
254
255 return rc;
256}
257
258
Trinath Thammishetty85b19292017-12-18 14:56:50 +0530259int32_t qahw_effect_get_version_l() {
Weiyin Jianga3719ac2016-11-23 19:29:35 +0800260 return QAHW_EFFECT_API_VERSION_CURRENT;
261}
262
263
Trinath Thammishetty85b19292017-12-18 14:56:50 +0530264int32_t qahw_effect_process_l(qahw_effect_handle_t self,
Weiyin Jianga3719ac2016-11-23 19:29:35 +0800265 qahw_audio_buffer_t *in_buffer,
266 qahw_audio_buffer_t *out_buffer) {
267 int32_t rc = -EINVAL;
268 struct effect_interface_s *itfe;
269
270 if (self) {
271 itfe = *((struct effect_interface_s **)self);
272 if (itfe) {
273 rc = itfe->process((effect_handle_t)self,
274 (audio_buffer_t *)in_buffer,
275 (audio_buffer_t *)out_buffer);
276 }
277 }
278
279 return rc;
280}
281
282
Trinath Thammishetty85b19292017-12-18 14:56:50 +0530283int32_t qahw_effect_command_l(qahw_effect_handle_t self,
Weiyin Jianga3719ac2016-11-23 19:29:35 +0800284 uint32_t cmd_code,
285 uint32_t cmd_size,
286 void *cmd_data,
287 uint32_t *reply_size,
288 void *reply_data) {
289 int32_t rc = -EINVAL;
290 struct effect_interface_s *itfe;
291
292 if (self) {
293 itfe = *((struct effect_interface_s **)self);
294 if (itfe) {
295 rc = itfe->command((effect_handle_t)self, cmd_code, cmd_size,
296 cmd_data, reply_size, reply_data);
297 }
298 }
299
300 return rc;
301}
302
303
Trinath Thammishetty85b19292017-12-18 14:56:50 +0530304int32_t qahw_effect_process_reverse_l(qahw_effect_handle_t self,
Weiyin Jianga3719ac2016-11-23 19:29:35 +0800305 qahw_audio_buffer_t *in_buffer,
306 qahw_audio_buffer_t *out_buffer) {
307 int32_t rc = -EINVAL;
308 struct effect_interface_s *itfe;
309
310 if (self) {
311 itfe = *((struct effect_interface_s **)self);
312 if (itfe) {
313 rc = itfe->process_reverse((effect_handle_t)self,
314 (audio_buffer_t *)in_buffer,
315 (audio_buffer_t *)out_buffer);
316 }
317 }
318
319 return rc;
320}
321