blob: 2eff79f2d721020e50cc22a6f2728a58aa4a0465 [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#include "qahw_effect_api.h"
43
44// The current effect API version.
45#define QAHW_EFFECT_API_VERSION_CURRENT QAHW_EFFECT_API_VERSION_0_0
46#define PATH_MAX 4096
47
48typedef struct {
49 char lib_path[PATH_MAX];
50 pthread_mutex_t lock;
51 uint32_t ref_count;
52 audio_effect_library_t *desc;
53 void *handle;
54 struct listnode lib_list;
55} qahw_effect_lib_t;
56
57// list of loaded effect libraries
58static struct listnode effect_libraries_list;
59static int effect_libraries_count = 0;
60static pthread_mutex_t effect_libraries_lock = PTHREAD_MUTEX_INITIALIZER;
61
62qahw_effect_lib_t *get_qahw_effect_lib_by_name(const char *lib_path) {
63 struct listnode *node = NULL;
64 qahw_effect_lib_t *effect_lib = NULL, *effect_lib_temp = NULL;
65
66 if (lib_path == NULL)
67 goto exit;
68
69 list_for_each(node, &effect_libraries_list) {
70 effect_lib_temp = node_to_item(node, qahw_effect_lib_t, lib_list);
71 if(!strncmp(lib_path, effect_lib_temp->lib_path, PATH_MAX)) {
72 effect_lib = effect_lib_temp;
73 break;
74 }
75 }
76exit:
77 return effect_lib;
78}
79
80
81qahw_effect_lib_t *get_qahw_effect_lib_by_desc(qahw_effect_lib_handle_t handle) {
82 struct listnode *node = NULL;
83 qahw_effect_lib_t *effect_lib = NULL, *effect_lib_temp = NULL;
84
85 if (handle == NULL)
86 goto exit;
87
88 list_for_each(node, &effect_libraries_list) {
89 effect_lib_temp = node_to_item(node, qahw_effect_lib_t, lib_list);
90 if (effect_lib_temp->desc == (audio_effect_library_t *)handle) {
91 effect_lib = effect_lib_temp;
92 break;
93 }
94 }
95exit:
96 return effect_lib;
97}
98
99
100qahw_effect_lib_handle_t qahw_effect_load_library(const char *lib_path) {
101 audio_effect_library_t *desc;
102 qahw_effect_lib_t *qahw_effect_lib;
103 void *handle;
104
105 if (strlen(lib_path) >= PATH_MAX -1) {
106 ALOGE("%s: effect libraries path too long", __func__);
107 return NULL;
108 }
109
110 /* return existing lib handler if already loaded */
111 pthread_mutex_lock(&effect_libraries_lock);
112 if (effect_libraries_count > 0) {
113 qahw_effect_lib = get_qahw_effect_lib_by_name(lib_path);
114 if (qahw_effect_lib != NULL) {
115 desc = qahw_effect_lib->desc;
116 pthread_mutex_lock(&qahw_effect_lib->lock);
117 qahw_effect_lib->ref_count++;
118 pthread_mutex_unlock(&qahw_effect_lib->lock);
119 goto done;
120 }
121 }
122
123 handle = dlopen(lib_path, RTLD_NOW);
124 if (handle == NULL) {
125 ALOGE("%s: failed to dlopen lib %s", __func__, lib_path);
126 goto error;
127 }
128
129 desc = (audio_effect_library_t *)dlsym(handle, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
130 if (desc == NULL) {
131 ALOGE("%s: could not find symbol %s", __func__, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
132 goto error;
133 }
134
135 if (AUDIO_EFFECT_LIBRARY_TAG != desc->tag) {
136 ALOGE("%s: bad tag %08x in lib info struct", __func__, desc->tag);
137 goto error;
138 }
139
140 if (EFFECT_API_VERSION_MAJOR(desc->version) !=
141 EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION)) {
142 ALOGE("%s: bad lib version %08x", __func__, desc->version);
143 goto error;
144 }
145
146 qahw_effect_lib = (qahw_effect_lib_t *)calloc(1, sizeof(qahw_effect_lib_t));
147 if (qahw_effect_lib == NULL) {
148 ALOGE("%s: calloc failed", __func__);
149 goto error;
150 }
151
152 if (!effect_libraries_count)
153 list_init(&effect_libraries_list);
154 effect_libraries_count++;
155
156 /* init and load effect lib into global list */
157 strlcpy(qahw_effect_lib->lib_path, lib_path, PATH_MAX);
158 pthread_mutex_init(&qahw_effect_lib->lock, (const pthread_mutexattr_t *) NULL);
159 qahw_effect_lib->ref_count = 1;
160 qahw_effect_lib->desc = desc;
161 qahw_effect_lib->handle = handle;
162
163 list_add_tail(&effect_libraries_list, &qahw_effect_lib->lib_list);
164
165done:
166 pthread_mutex_unlock(&effect_libraries_lock);
167 return (qahw_effect_lib_handle_t)desc;
168
169error:
170 if (handle != NULL)
171 dlclose(handle);
172
173 pthread_mutex_unlock(&effect_libraries_lock);
174 return NULL;
175}
176
177
178int32_t qahw_effect_unload_library(qahw_effect_lib_handle_t handle) {
179 qahw_effect_lib_t *qahw_effect_lib;
180
181 pthread_mutex_lock(&effect_libraries_lock);
182 if (effect_libraries_count <= 0) {
183 ALOGW("%s: no valid libraries loaded", __func__);
184 pthread_mutex_unlock(&effect_libraries_lock);
185 return -EINVAL;
186 }
187
188 qahw_effect_lib = get_qahw_effect_lib_by_desc(handle);
189 if (qahw_effect_lib == NULL) {
190 ALOGW("%s: effect lib handle(%p) not in loaded queue", __func__, (void *)handle);
191 pthread_mutex_unlock(&effect_libraries_lock);
192 return -EINVAL;
193 }
194
195 pthread_mutex_lock(&qahw_effect_lib->lock);
196 qahw_effect_lib->ref_count--;
197 if (qahw_effect_lib->ref_count > 0) {
198 ALOGW("%s: skip unloading effect lib, ref count %d", __func__, qahw_effect_lib->ref_count);
199 pthread_mutex_unlock(&qahw_effect_lib->lock);
200 goto done;
201 }
202
203 if (qahw_effect_lib->handle)
204 dlclose(qahw_effect_lib->handle);
205 effect_libraries_count--;
206 list_remove(&qahw_effect_lib->lib_list);
207 pthread_mutex_unlock(&qahw_effect_lib->lock);
208 pthread_mutex_destroy(&qahw_effect_lib->lock);
209 free(qahw_effect_lib);
210
211done:
212 pthread_mutex_unlock(&effect_libraries_lock);
213 return 0;
214}
215
216
217int32_t qahw_effect_create(qahw_effect_lib_handle_t handle,
218 const qahw_effect_uuid_t *uuid,
219 int32_t io_handle,
220 qahw_effect_handle_t *effect_handle) {
221 int32_t rc = -EINVAL;
222 audio_effect_library_t *desc = (audio_effect_library_t *)handle;
223
224 if (desc != NULL) {
225 rc = desc->create_effect((const effect_uuid_t *)uuid, 0, io_handle,
226 (effect_handle_t *)effect_handle);
227 }
228
229 return rc;
230}
231
232
233int32_t qahw_effect_release(qahw_effect_lib_handle_t handle,
234 qahw_effect_handle_t effect_handle) {
235 int32_t rc = -EINVAL;
236 audio_effect_library_t *desc = (audio_effect_library_t *)handle;
237
238 if (desc != NULL) {
239 rc = desc->release_effect((effect_handle_t)effect_handle);
240 }
241
242 return rc;
243}
244
245
246int32_t qahw_effect_get_descriptor(qahw_effect_lib_handle_t handle,
247 const qahw_effect_uuid_t *uuid,
248 qahw_effect_descriptor_t *effect_desc) {
249 int32_t rc = -EINVAL;
250 audio_effect_library_t *desc = (audio_effect_library_t *)handle;
251
252 if (desc != NULL) {
253 rc = desc->get_descriptor((const effect_uuid_t *)uuid, (effect_descriptor_t *)effect_desc);
254 }
255
256 return rc;
257}
258
259
260int32_t qahw_effect_get_version() {
261 return QAHW_EFFECT_API_VERSION_CURRENT;
262}
263
264
265int32_t qahw_effect_process(qahw_effect_handle_t self,
266 qahw_audio_buffer_t *in_buffer,
267 qahw_audio_buffer_t *out_buffer) {
268 int32_t rc = -EINVAL;
269 struct effect_interface_s *itfe;
270
271 if (self) {
272 itfe = *((struct effect_interface_s **)self);
273 if (itfe) {
274 rc = itfe->process((effect_handle_t)self,
275 (audio_buffer_t *)in_buffer,
276 (audio_buffer_t *)out_buffer);
277 }
278 }
279
280 return rc;
281}
282
283
284int32_t qahw_effect_command(qahw_effect_handle_t self,
285 uint32_t cmd_code,
286 uint32_t cmd_size,
287 void *cmd_data,
288 uint32_t *reply_size,
289 void *reply_data) {
290 int32_t rc = -EINVAL;
291 struct effect_interface_s *itfe;
292
293 if (self) {
294 itfe = *((struct effect_interface_s **)self);
295 if (itfe) {
296 rc = itfe->command((effect_handle_t)self, cmd_code, cmd_size,
297 cmd_data, reply_size, reply_data);
298 }
299 }
300
301 return rc;
302}
303
304
305int32_t qahw_effect_process_reverse(qahw_effect_handle_t self,
306 qahw_audio_buffer_t *in_buffer,
307 qahw_audio_buffer_t *out_buffer) {
308 int32_t rc = -EINVAL;
309 struct effect_interface_s *itfe;
310
311 if (self) {
312 itfe = *((struct effect_interface_s **)self);
313 if (itfe) {
314 rc = itfe->process_reverse((effect_handle_t)self,
315 (audio_buffer_t *)in_buffer,
316 (audio_buffer_t *)out_buffer);
317 }
318 }
319
320 return rc;
321}
322