1 /*
2  * Copyright (C) 2010 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 
17 #define LOG_TAG "EffectsFactory"
18 //#define LOG_NDEBUG 0
19 
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 
24 #include <cutils/properties.h>
25 #include <log/log.h>
26 
27 #include <media/EffectsFactoryApi.h>
28 
29 #include "EffectsConfigLoader.h"
30 #include "EffectsFactoryState.h"
31 #include "EffectsXmlConfigLoader.h"
32 
33 #include "EffectsFactory.h"
34 
35 static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
36 static uint32_t gNumEffects;         // total number number of effects
37 static list_elem_t *gCurLib;    // current library in enumeration process
38 static list_elem_t *gCurEffect; // current effect in enumeration process
39 static uint32_t gCurEffectIdx;       // current effect index in enumeration process
40 /** Number of elements skipped during the effects configuration loading.
41  *  -1 if the config loader failed
42  *  -2 if config load was skipped
43  */
44 static ssize_t gConfigNbElemSkipped = -2;
45 
46 static int gInitDone; // true is global initialization has been preformed
47 static int gCanQueryEffect; // indicates that call to EffectQueryEffect() is valid, i.e. that the list of effects
48                           // was not modified since last call to EffectQueryNumberEffects()
49 /////////////////////////////////////////////////
50 //      Local functions prototypes
51 /////////////////////////////////////////////////
52 
53 static int init();
54 static void resetEffectEnumeration();
55 static uint32_t updateNumEffects();
56 // To search a subeffect in the gSubEffectList
57 static int findSubEffect(const effect_uuid_t *uuid,
58                lib_entry_t **lib,
59                effect_descriptor_t **desc);
60 
61 /////////////////////////////////////////////////
62 //      Effect Control Interface functions
63 /////////////////////////////////////////////////
64 
Effect_Process(effect_handle_t self,audio_buffer_t * inBuffer,audio_buffer_t * outBuffer)65 int Effect_Process(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
66 {
67     int ret = init();
68     if (ret < 0) {
69         return ret;
70     }
71     effect_entry_t *fx = (effect_entry_t *)self;
72     pthread_mutex_lock(&gLibLock);
73     if (fx->lib == NULL) {
74         pthread_mutex_unlock(&gLibLock);
75         return -EPIPE;
76     }
77     pthread_mutex_lock(&fx->lib->lock);
78     pthread_mutex_unlock(&gLibLock);
79 
80     ret = (*fx->subItfe)->process(fx->subItfe, inBuffer, outBuffer);
81     pthread_mutex_unlock(&fx->lib->lock);
82     return ret;
83 }
84 
Effect_Command(effect_handle_t self,uint32_t cmdCode,uint32_t cmdSize,void * pCmdData,uint32_t * replySize,void * pReplyData)85 int Effect_Command(effect_handle_t self,
86                    uint32_t cmdCode,
87                    uint32_t cmdSize,
88                    void *pCmdData,
89                    uint32_t *replySize,
90                    void *pReplyData)
91 {
92     int ret = init();
93     if (ret < 0) {
94         return ret;
95     }
96     effect_entry_t *fx = (effect_entry_t *)self;
97     pthread_mutex_lock(&gLibLock);
98     if (fx->lib == NULL) {
99         pthread_mutex_unlock(&gLibLock);
100         return -EPIPE;
101     }
102     pthread_mutex_lock(&fx->lib->lock);
103     pthread_mutex_unlock(&gLibLock);
104 
105     ret = (*fx->subItfe)->command(fx->subItfe, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
106     pthread_mutex_unlock(&fx->lib->lock);
107     return ret;
108 }
109 
Effect_GetDescriptor(effect_handle_t self,effect_descriptor_t * desc)110 int Effect_GetDescriptor(effect_handle_t self,
111                          effect_descriptor_t *desc)
112 {
113     int ret = init();
114     if (ret < 0) {
115         return ret;
116     }
117     effect_entry_t *fx = (effect_entry_t *)self;
118     pthread_mutex_lock(&gLibLock);
119     if (fx->lib == NULL) {
120         pthread_mutex_unlock(&gLibLock);
121         return -EPIPE;
122     }
123     pthread_mutex_lock(&fx->lib->lock);
124     pthread_mutex_unlock(&gLibLock);
125 
126     ret = (*fx->subItfe)->get_descriptor(fx->subItfe, desc);
127     pthread_mutex_unlock(&fx->lib->lock);
128     return ret;
129 }
130 
Effect_ProcessReverse(effect_handle_t self,audio_buffer_t * inBuffer,audio_buffer_t * outBuffer)131 int Effect_ProcessReverse(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
132 {
133     int ret = init();
134     if (ret < 0) {
135         return ret;
136     }
137     effect_entry_t *fx = (effect_entry_t *)self;
138     pthread_mutex_lock(&gLibLock);
139     if (fx->lib == NULL) {
140         pthread_mutex_unlock(&gLibLock);
141         return -EPIPE;
142     }
143     pthread_mutex_lock(&fx->lib->lock);
144     pthread_mutex_unlock(&gLibLock);
145 
146     if ((*fx->subItfe)->process_reverse != NULL) {
147         ret = (*fx->subItfe)->process_reverse(fx->subItfe, inBuffer, outBuffer);
148     } else {
149         ret = -ENOSYS;
150     }
151     pthread_mutex_unlock(&fx->lib->lock);
152     return ret;
153 }
154 
155 
156 const struct effect_interface_s gInterface = {
157         Effect_Process,
158         Effect_Command,
159         Effect_GetDescriptor,
160         NULL
161 };
162 
163 const struct effect_interface_s gInterfaceWithReverse = {
164         Effect_Process,
165         Effect_Command,
166         Effect_GetDescriptor,
167         Effect_ProcessReverse
168 };
169 
170 /////////////////////////////////////////////////
171 //      Effect Factory Interface functions
172 /////////////////////////////////////////////////
173 
EffectQueryNumberEffects(uint32_t * pNumEffects)174 int EffectQueryNumberEffects(uint32_t *pNumEffects)
175 {
176     int ret = init();
177     if (ret < 0) {
178         return ret;
179     }
180     if (pNumEffects == NULL) {
181         return -EINVAL;
182     }
183 
184     pthread_mutex_lock(&gLibLock);
185     *pNumEffects = gNumEffects;
186     gCanQueryEffect = 1;
187     pthread_mutex_unlock(&gLibLock);
188     ALOGV("EffectQueryNumberEffects(): %d", *pNumEffects);
189     return ret;
190 }
191 
EffectQueryEffect(uint32_t index,effect_descriptor_t * pDescriptor)192 int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
193 {
194     int ret = init();
195     if (ret < 0) {
196         return ret;
197     }
198     if (pDescriptor == NULL ||
199         index >= gNumEffects) {
200         return -EINVAL;
201     }
202     if (gCanQueryEffect == 0) {
203         return -ENOSYS;
204     }
205 
206     pthread_mutex_lock(&gLibLock);
207     ret = -ENOENT;
208     if (index < gCurEffectIdx) {
209         resetEffectEnumeration();
210     }
211     while (gCurLib) {
212         if (gCurEffect) {
213             if (index == gCurEffectIdx) {
214                 *pDescriptor = *(effect_descriptor_t *)gCurEffect->object;
215                 ret = 0;
216                 break;
217             } else {
218                 gCurEffect = gCurEffect->next;
219                 gCurEffectIdx++;
220             }
221         } else {
222             gCurLib = gCurLib->next;
223             gCurEffect = ((lib_entry_t *)gCurLib->object)->effects;
224         }
225     }
226 
227 #if (LOG_NDEBUG == 0)
228     char str[512];
229     dumpEffectDescriptor(pDescriptor, str, sizeof(str), 0 /* indent */);
230     ALOGV("EffectQueryEffect() desc:%s", str);
231 #endif
232     pthread_mutex_unlock(&gLibLock);
233     return ret;
234 }
235 
EffectGetDescriptor(const effect_uuid_t * uuid,effect_descriptor_t * pDescriptor)236 int EffectGetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor)
237 {
238     lib_entry_t *l = NULL;
239     effect_descriptor_t *d = NULL;
240 
241     int ret = init();
242     if (ret < 0) {
243         return ret;
244     }
245     if (pDescriptor == NULL || uuid == NULL) {
246         return -EINVAL;
247     }
248     pthread_mutex_lock(&gLibLock);
249     ret = findEffect(NULL, uuid, &l, &d);
250     if (ret == 0) {
251         *pDescriptor = *d;
252     }
253     pthread_mutex_unlock(&gLibLock);
254     return ret;
255 }
256 
doEffectCreate(const effect_uuid_t * uuid,int32_t sessionId,int32_t ioId,int32_t deviceId,effect_handle_t * pHandle)257 int doEffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, int32_t deviceId,
258         effect_handle_t *pHandle)
259 {
260     list_elem_t *e = gLibraryList;
261     lib_entry_t *l = NULL;
262     effect_descriptor_t *d = NULL;
263     effect_handle_t itfe;
264     effect_entry_t *fx;
265     int ret;
266 
267     if (uuid == NULL || pHandle == NULL) {
268         return -EINVAL;
269     }
270 
271     ALOGV("EffectCreate() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
272           uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
273           uuid->clockSeq, uuid->node[0], uuid->node[1], uuid->node[2],
274           uuid->node[3], uuid->node[4], uuid->node[5]);
275 
276     ret = init();
277 
278     if (ret < 0) {
279         ALOGW("EffectCreate() init error: %d", ret);
280         return ret;
281     }
282 
283     pthread_mutex_lock(&gLibLock);
284 
285     ret = findEffect(NULL, uuid, &l, &d);
286     if (ret < 0) {
287         // Sub effects are not associated with the library->effects,
288         // so, findEffect will fail. Search for the effect in gSubEffectList.
289         ret = findSubEffect(uuid, &l, &d);
290         if (ret < 0) {
291             goto exit;
292         }
293     }
294 
295     // create effect in library
296     if (sessionId == AUDIO_SESSION_DEVICE) {
297         if (l->desc->version >= EFFECT_LIBRARY_API_VERSION_3_1) {
298             ALOGI("EffectCreate() create_effect_3_1");
299             ret = l->desc->create_effect_3_1(uuid, sessionId, ioId, deviceId, &itfe);
300         } else {
301             ALOGE("EffectCreate() cannot create device effect on library with API version < 3.1");
302             ret = -ENOSYS;
303         }
304     } else {
305         ALOGI("EffectCreate() create_effect");
306         ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe);
307     }
308 
309     if (ret != 0) {
310         ALOGW("EffectCreate() library %s: could not create fx %s, error %d", l->name, d->name, ret);
311         goto exit;
312     }
313 
314     // add entry to effect list
315     fx = (effect_entry_t *)malloc(sizeof(effect_entry_t));
316     fx->subItfe = itfe;
317     if ((*itfe)->process_reverse != NULL) {
318         fx->itfe = (struct effect_interface_s *)&gInterfaceWithReverse;
319         ALOGV("EffectCreate() gInterfaceWithReverse");
320     }   else {
321         fx->itfe = (struct effect_interface_s *)&gInterface;
322         ALOGV("EffectCreate() gInterface");
323     }
324     fx->lib = l;
325 
326     e = (list_elem_t *)malloc(sizeof(list_elem_t));
327     e->object = fx;
328     e->next = gEffectList;
329     gEffectList = e;
330 
331     *pHandle = (effect_handle_t)fx;
332 
333     ALOGV("EffectCreate() created entry %p with sub itfe %p in library %s", *pHandle, itfe, l->name);
334 
335 exit:
336     pthread_mutex_unlock(&gLibLock);
337     return ret;
338 }
339 
EffectCreate(const effect_uuid_t * uuid,int32_t sessionId,int32_t ioId,effect_handle_t * pHandle)340 int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId,
341         effect_handle_t *pHandle) {
342     return doEffectCreate(uuid, sessionId, ioId, AUDIO_PORT_HANDLE_NONE, pHandle);
343 }
344 
EffectCreateOnDevice(const effect_uuid_t * uuid,int32_t deviceId,int32_t ioId,effect_handle_t * pHandle)345 int EffectCreateOnDevice(const effect_uuid_t *uuid, int32_t deviceId, int32_t ioId,
346         effect_handle_t *pHandle) {
347     return doEffectCreate(uuid, AUDIO_SESSION_DEVICE, ioId, deviceId, pHandle);
348 }
349 
EffectRelease(effect_handle_t handle)350 int EffectRelease(effect_handle_t handle)
351 {
352     effect_entry_t *fx;
353     list_elem_t *e1;
354     list_elem_t *e2;
355 
356     int ret = init();
357     if (ret < 0) {
358         return ret;
359     }
360 
361     // remove effect from effect list
362     pthread_mutex_lock(&gLibLock);
363     e1 = gEffectList;
364     e2 = NULL;
365     while (e1) {
366         if (e1->object == handle) {
367             if (e2) {
368                 e2->next = e1->next;
369             } else {
370                 gEffectList = e1->next;
371             }
372             fx = (effect_entry_t *)e1->object;
373             free(e1);
374             break;
375         }
376         e2 = e1;
377         e1 = e1->next;
378     }
379     if (e1 == NULL) {
380         ret = -ENOENT;
381         goto exit;
382     }
383 
384     // release effect in library
385     if (fx->lib == NULL) {
386         ALOGW("EffectRelease() fx %p library already unloaded", handle);
387     } else {
388         pthread_mutex_lock(&fx->lib->lock);
389         fx->lib->desc->release_effect(fx->subItfe);
390         pthread_mutex_unlock(&fx->lib->lock);
391     }
392     free(fx);
393 
394 exit:
395     pthread_mutex_unlock(&gLibLock);
396     return ret;
397 }
398 
EffectIsNullUuid(const effect_uuid_t * uuid)399 int EffectIsNullUuid(const effect_uuid_t *uuid)
400 {
401     if (memcmp(uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t))) {
402         return 0;
403     }
404     return 1;
405 }
406 
407 // Function to get the sub effect descriptors of the effect whose uuid
408 // is pointed by the first argument. It searches the gSubEffectList for the
409 // matching uuid and then copies the corresponding sub effect descriptors
410 // to the inout param
EffectGetSubEffects(const effect_uuid_t * uuid,sub_effect_entry_t ** pSube,size_t size)411 int EffectGetSubEffects(const effect_uuid_t *uuid, sub_effect_entry_t **pSube,
412                         size_t size)
413 {
414    ALOGV("EffectGetSubEffects() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X"
415           "%02X\n",uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
416           uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2],
417           uuid->node[3],uuid->node[4],uuid->node[5]);
418 
419    // Check if the size of the desc buffer is large enough for 2 subeffects
420    if ((uuid == NULL) || (pSube == NULL) || (size < 2)) {
421        ALOGW("NULL pointer or insufficient memory. Cannot query subeffects");
422        return -EINVAL;
423    }
424    int ret = init();
425    if (ret < 0)
426       return ret;
427    list_sub_elem_t *e = gSubEffectList;
428    sub_effect_entry_t *subeffect;
429    effect_descriptor_t *d;
430    int count = 0;
431    while (e != NULL) {
432        d = (effect_descriptor_t*)e->object;
433        if (memcmp(uuid, &d->uuid, sizeof(effect_uuid_t)) == 0) {
434            ALOGV("EffectGetSubEffects: effect found in the list");
435            list_elem_t *subefx = e->sub_elem;
436            while (subefx != NULL) {
437                subeffect = (sub_effect_entry_t*)subefx->object;
438                pSube[count++] = subeffect;
439                subefx = subefx->next;
440            }
441            ALOGV("EffectGetSubEffects end - copied the sub effect structures");
442            return count;
443        }
444        e = e->next;
445    }
446    return -ENOENT;
447 }
448 /////////////////////////////////////////////////
449 //      Local functions
450 /////////////////////////////////////////////////
451 
init()452 int init() {
453     if (gInitDone) {
454         return 0;
455     }
456 
457     // ignore effects or not?
458     const bool ignoreFxConfFiles = property_get_bool(PROPERTY_IGNORE_EFFECTS, false);
459 
460     pthread_mutex_init(&gLibLock, NULL);
461 
462     if (ignoreFxConfFiles) {
463         ALOGI("Audio effects in configuration files will be ignored");
464     } else {
465         gConfigNbElemSkipped = EffectLoadXmlEffectConfig(NULL);
466         if (gConfigNbElemSkipped < 0) {
467             ALOGW("Failed to load XML effect configuration, fallback to .conf");
468             EffectLoadEffectConfig();
469         } else if (gConfigNbElemSkipped > 0) {
470             ALOGE("Effect config is partially invalid, skipped %zd elements", gConfigNbElemSkipped);
471         }
472     }
473 
474     updateNumEffects();
475     gInitDone = 1;
476     ALOGV("init() done");
477     return 0;
478 }
479 
480 // Searches the sub effect matching to the specified uuid
481 // in the gSubEffectList. It gets the lib_entry_t for
482 // the matched sub_effect . Used in EffectCreate of sub effects
findSubEffect(const effect_uuid_t * uuid,lib_entry_t ** lib,effect_descriptor_t ** desc)483 int findSubEffect(const effect_uuid_t *uuid,
484                lib_entry_t **lib,
485                effect_descriptor_t **desc)
486 {
487     list_sub_elem_t *e = gSubEffectList;
488     list_elem_t *subefx;
489     sub_effect_entry_t *effect;
490     lib_entry_t *l = NULL;
491     effect_descriptor_t *d = NULL;
492     int found = 0;
493     int ret = 0;
494 
495     if (uuid == NULL)
496         return -EINVAL;
497 
498     while (e != NULL && !found) {
499         subefx = (list_elem_t*)(e->sub_elem);
500         while (subefx != NULL) {
501             effect = (sub_effect_entry_t*)subefx->object;
502             l = (lib_entry_t *)effect->lib;
503             d = (effect_descriptor_t *)effect->object;
504             if (memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
505                 ALOGV("uuid matched");
506                 found = 1;
507                 break;
508             }
509             subefx = subefx->next;
510         }
511         e = e->next;
512     }
513     if (!found) {
514         ALOGV("findSubEffect() effect not found");
515         ret = -ENOENT;
516     } else {
517         ALOGV("findSubEffect() found effect: %s in lib %s", d->name, l->name);
518         *lib = l;
519         if (desc != NULL) {
520             *desc = d;
521         }
522     }
523     return ret;
524 }
525 
resetEffectEnumeration()526 void resetEffectEnumeration()
527 {
528     gCurLib = gLibraryList;
529     gCurEffect = NULL;
530     if (gCurLib) {
531         gCurEffect = ((lib_entry_t *)gCurLib->object)->effects;
532     }
533     gCurEffectIdx = 0;
534 }
535 
updateNumEffects()536 uint32_t updateNumEffects() {
537     list_elem_t *e;
538     uint32_t cnt = 0;
539 
540     resetEffectEnumeration();
541 
542     e = gLibraryList;
543     while (e) {
544         lib_entry_t *l = (lib_entry_t *)e->object;
545         list_elem_t *efx = l->effects;
546         while (efx) {
547             cnt++;
548             efx = efx->next;
549         }
550         e = e->next;
551     }
552     gNumEffects = cnt;
553     gCanQueryEffect = 0;
554     return cnt;
555 }
556 
EffectDumpEffects(int fd)557 int EffectDumpEffects(int fd) {
558     char s[512];
559 
560     list_elem_t *fe = gLibraryFailedList;
561     lib_failed_entry_t *fl = NULL;
562 
563     dprintf(fd, "Libraries NOT loaded:\n");
564 
565     while (fe) {
566         fl = (lib_failed_entry_t *)fe->object;
567         dprintf(fd, " Library %s\n", fl->name);
568         dprintf(fd, "  path: %s\n", fl->path);
569         fe = fe->next;
570     }
571 
572     list_elem_t *e = gLibraryList;
573     lib_entry_t *l = NULL;
574     effect_descriptor_t *d = NULL;
575     int ret = 0;
576 
577     dprintf(fd, "Libraries loaded:\n");
578     while (e) {
579         l = (lib_entry_t *)e->object;
580         list_elem_t *efx = l->effects;
581         dprintf(fd, " Library %s\n", l->name);
582         dprintf(fd, "  path: %s\n", l->path);
583         if (!efx) {
584             dprintf(fd, "  (no effects)\n");
585         }
586         while (efx) {
587             d = (effect_descriptor_t *)efx->object;
588             dumpEffectDescriptor(d, s, sizeof(s), 2);
589             dprintf(fd, "%s", s);
590             efx = efx->next;
591         }
592         e = e->next;
593     }
594 
595     e = gSkippedEffects;
596     if (e) {
597         dprintf(fd, "Skipped effects\n");
598         while(e) {
599             d = (effect_descriptor_t *)e->object;
600             dumpEffectDescriptor(d, s, sizeof(s), 2 /* indent */);
601             dprintf(fd, "%s", s);
602             e = e->next;
603         }
604     }
605     switch (gConfigNbElemSkipped) {
606     case -2:
607         dprintf(fd, "Effect configuration loading skipped.\n");
608         break;
609     case -1:
610         dprintf(fd, "XML effect configuration failed to load.\n");
611         break;
612     case 0:
613         dprintf(fd, "XML effect configuration loaded successfully.\n");
614         break;
615     default:
616         dprintf(fd, "XML effect configuration partially loaded, skipped %zd elements.\n",
617                 gConfigNbElemSkipped);
618     }
619     return ret;
620 }
621 
622