Home | History | Annotate | Download | only in factory
      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 "EffectsFactory.h"
     21 #include <string.h>
     22 #include <stdlib.h>
     23 #include <dlfcn.h>
     24 
     25 #include <cutils/misc.h>
     26 #include <cutils/config_utils.h>
     27 #include <audio_effects/audio_effects_conf.h>
     28 
     29 static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
     30 static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
     31 static pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER; // controls access to gLibraryList
     32 static uint32_t gNumEffects;         // total number number of effects
     33 static list_elem_t *gCurLib;    // current library in enumeration process
     34 static list_elem_t *gCurEffect; // current effect in enumeration process
     35 static uint32_t gCurEffectIdx;       // current effect index in enumeration process
     36 static lib_entry_t *gCachedLibrary;  // last library accessed by getLibrary()
     37 
     38 static int gInitDone; // true is global initialization has been preformed
     39 static int gCanQueryEffect; // indicates that call to EffectQueryEffect() is valid, i.e. that the list of effects
     40                           // was not modified since last call to EffectQueryNumberEffects()
     41 
     42 
     43 /////////////////////////////////////////////////
     44 //      Local functions prototypes
     45 /////////////////////////////////////////////////
     46 
     47 static int init();
     48 static int loadEffectConfigFile(const char *path);
     49 static int loadLibraries(cnode *root);
     50 static int loadLibrary(cnode *root, const char *name);
     51 static int loadEffects(cnode *root);
     52 static int loadEffect(cnode *node);
     53 static lib_entry_t *getLibrary(const char *path);
     54 static void resetEffectEnumeration();
     55 static uint32_t updateNumEffects();
     56 static int findEffect(effect_uuid_t *type,
     57                effect_uuid_t *uuid,
     58                lib_entry_t **lib,
     59                effect_descriptor_t **desc);
     60 static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len);
     61 static int stringToUuid(const char *str, effect_uuid_t *uuid);
     62 static int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen);
     63 
     64 /////////////////////////////////////////////////
     65 //      Effect Control Interface functions
     66 /////////////////////////////////////////////////
     67 
     68 int Effect_Process(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
     69 {
     70     int ret = init();
     71     if (ret < 0) {
     72         return ret;
     73     }
     74     effect_entry_t *fx = (effect_entry_t *)self;
     75     pthread_mutex_lock(&gLibLock);
     76     if (fx->lib == NULL) {
     77         pthread_mutex_unlock(&gLibLock);
     78         return -EPIPE;
     79     }
     80     pthread_mutex_lock(&fx->lib->lock);
     81     pthread_mutex_unlock(&gLibLock);
     82 
     83     ret = (*fx->subItfe)->process(fx->subItfe, inBuffer, outBuffer);
     84     pthread_mutex_unlock(&fx->lib->lock);
     85     return ret;
     86 }
     87 
     88 int Effect_Command(effect_handle_t self,
     89                    uint32_t cmdCode,
     90                    uint32_t cmdSize,
     91                    void *pCmdData,
     92                    uint32_t *replySize,
     93                    void *pReplyData)
     94 {
     95     int ret = init();
     96     if (ret < 0) {
     97         return ret;
     98     }
     99     effect_entry_t *fx = (effect_entry_t *)self;
    100     pthread_mutex_lock(&gLibLock);
    101     if (fx->lib == NULL) {
    102         pthread_mutex_unlock(&gLibLock);
    103         return -EPIPE;
    104     }
    105     pthread_mutex_lock(&fx->lib->lock);
    106     pthread_mutex_unlock(&gLibLock);
    107 
    108     ret = (*fx->subItfe)->command(fx->subItfe, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
    109     pthread_mutex_unlock(&fx->lib->lock);
    110     return ret;
    111 }
    112 
    113 int Effect_GetDescriptor(effect_handle_t self,
    114                          effect_descriptor_t *desc)
    115 {
    116     int ret = init();
    117     if (ret < 0) {
    118         return ret;
    119     }
    120     effect_entry_t *fx = (effect_entry_t *)self;
    121     pthread_mutex_lock(&gLibLock);
    122     if (fx->lib == NULL) {
    123         pthread_mutex_unlock(&gLibLock);
    124         return -EPIPE;
    125     }
    126     pthread_mutex_lock(&fx->lib->lock);
    127     pthread_mutex_unlock(&gLibLock);
    128 
    129     ret = (*fx->subItfe)->get_descriptor(fx->subItfe, desc);
    130     pthread_mutex_unlock(&fx->lib->lock);
    131     return ret;
    132 }
    133 
    134 int Effect_ProcessReverse(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
    135 {
    136     int ret = init();
    137     if (ret < 0) {
    138         return ret;
    139     }
    140     effect_entry_t *fx = (effect_entry_t *)self;
    141     pthread_mutex_lock(&gLibLock);
    142     if (fx->lib == NULL) {
    143         pthread_mutex_unlock(&gLibLock);
    144         return -EPIPE;
    145     }
    146     pthread_mutex_lock(&fx->lib->lock);
    147     pthread_mutex_unlock(&gLibLock);
    148 
    149     if ((*fx->subItfe)->process_reverse != NULL) {
    150         ret = (*fx->subItfe)->process_reverse(fx->subItfe, inBuffer, outBuffer);
    151     } else {
    152         ret = -ENOSYS;
    153     }
    154     pthread_mutex_unlock(&fx->lib->lock);
    155     return ret;
    156 }
    157 
    158 
    159 const struct effect_interface_s gInterface = {
    160         Effect_Process,
    161         Effect_Command,
    162         Effect_GetDescriptor,
    163         NULL
    164 };
    165 
    166 const struct effect_interface_s gInterfaceWithReverse = {
    167         Effect_Process,
    168         Effect_Command,
    169         Effect_GetDescriptor,
    170         Effect_ProcessReverse
    171 };
    172 
    173 /////////////////////////////////////////////////
    174 //      Effect Factory Interface functions
    175 /////////////////////////////////////////////////
    176 
    177 int EffectQueryNumberEffects(uint32_t *pNumEffects)
    178 {
    179     int ret = init();
    180     if (ret < 0) {
    181         return ret;
    182     }
    183     if (pNumEffects == NULL) {
    184         return -EINVAL;
    185     }
    186 
    187     pthread_mutex_lock(&gLibLock);
    188     *pNumEffects = gNumEffects;
    189     gCanQueryEffect = 1;
    190     pthread_mutex_unlock(&gLibLock);
    191     LOGV("EffectQueryNumberEffects(): %d", *pNumEffects);
    192     return ret;
    193 }
    194 
    195 int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
    196 {
    197     int ret = init();
    198     if (ret < 0) {
    199         return ret;
    200     }
    201     if (pDescriptor == NULL ||
    202         index >= gNumEffects) {
    203         return -EINVAL;
    204     }
    205     if (gCanQueryEffect == 0) {
    206         return -ENOSYS;
    207     }
    208 
    209     pthread_mutex_lock(&gLibLock);
    210     ret = -ENOENT;
    211     if (index < gCurEffectIdx) {
    212         resetEffectEnumeration();
    213     }
    214     while (gCurLib) {
    215         if (gCurEffect) {
    216             if (index == gCurEffectIdx) {
    217                 memcpy(pDescriptor, gCurEffect->object, sizeof(effect_descriptor_t));
    218                 ret = 0;
    219                 break;
    220             } else {
    221                 gCurEffect = gCurEffect->next;
    222                 gCurEffectIdx++;
    223             }
    224         } else {
    225             gCurLib = gCurLib->next;
    226             gCurEffect = ((lib_entry_t *)gCurLib->object)->effects;
    227         }
    228     }
    229 
    230 #if (LOG_NDEBUG == 0)
    231     char str[256];
    232     dumpEffectDescriptor(pDescriptor, str, 256);
    233     LOGV("EffectQueryEffect() desc:%s", str);
    234 #endif
    235     pthread_mutex_unlock(&gLibLock);
    236     return ret;
    237 }
    238 
    239 int EffectGetDescriptor(effect_uuid_t *uuid, effect_descriptor_t *pDescriptor)
    240 {
    241     lib_entry_t *l = NULL;
    242     effect_descriptor_t *d = NULL;
    243 
    244     int ret = init();
    245     if (ret < 0) {
    246         return ret;
    247     }
    248     if (pDescriptor == NULL || uuid == NULL) {
    249         return -EINVAL;
    250     }
    251     pthread_mutex_lock(&gLibLock);
    252     ret = findEffect(NULL, uuid, &l, &d);
    253     if (ret == 0) {
    254         memcpy(pDescriptor, d, sizeof(effect_descriptor_t));
    255     }
    256     pthread_mutex_unlock(&gLibLock);
    257     return ret;
    258 }
    259 
    260 int EffectCreate(effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle)
    261 {
    262     list_elem_t *e = gLibraryList;
    263     lib_entry_t *l = NULL;
    264     effect_descriptor_t *d = NULL;
    265     effect_handle_t itfe;
    266     effect_entry_t *fx;
    267     int found = 0;
    268     int ret;
    269 
    270     if (uuid == NULL || pHandle == NULL) {
    271         return -EINVAL;
    272     }
    273 
    274     LOGV("EffectCreate() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
    275             uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
    276             uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2],
    277             uuid->node[3],uuid->node[4],uuid->node[5]);
    278 
    279     ret = init();
    280 
    281     if (ret < 0) {
    282         LOGW("EffectCreate() init error: %d", ret);
    283         return ret;
    284     }
    285 
    286     pthread_mutex_lock(&gLibLock);
    287 
    288     ret = findEffect(NULL, uuid, &l, &d);
    289     if (ret < 0){
    290         goto exit;
    291     }
    292 
    293     // create effect in library
    294     ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe);
    295     if (ret != 0) {
    296         LOGW("EffectCreate() library %s: could not create fx %s, error %d", l->name, d->name, ret);
    297         goto exit;
    298     }
    299 
    300     // add entry to effect list
    301     fx = (effect_entry_t *)malloc(sizeof(effect_entry_t));
    302     fx->subItfe = itfe;
    303     if ((*itfe)->process_reverse != NULL) {
    304         fx->itfe = (struct effect_interface_s *)&gInterfaceWithReverse;
    305         LOGV("EffectCreate() gInterfaceWithReverse");
    306     }   else {
    307         fx->itfe = (struct effect_interface_s *)&gInterface;
    308         LOGV("EffectCreate() gInterface");
    309     }
    310     fx->lib = l;
    311 
    312     e = (list_elem_t *)malloc(sizeof(list_elem_t));
    313     e->object = fx;
    314     e->next = gEffectList;
    315     gEffectList = e;
    316 
    317     *pHandle = (effect_handle_t)fx;
    318 
    319     LOGV("EffectCreate() created entry %p with sub itfe %p in library %s", *pHandle, itfe, l->name);
    320 
    321 exit:
    322     pthread_mutex_unlock(&gLibLock);
    323     return ret;
    324 }
    325 
    326 int EffectRelease(effect_handle_t handle)
    327 {
    328     effect_entry_t *fx;
    329     list_elem_t *e1;
    330     list_elem_t *e2;
    331 
    332     int ret = init();
    333     if (ret < 0) {
    334         return ret;
    335     }
    336 
    337     // remove effect from effect list
    338     pthread_mutex_lock(&gLibLock);
    339     e1 = gEffectList;
    340     e2 = NULL;
    341     while (e1) {
    342         if (e1->object == handle) {
    343             if (e2) {
    344                 e2->next = e1->next;
    345             } else {
    346                 gEffectList = e1->next;
    347             }
    348             fx = (effect_entry_t *)e1->object;
    349             free(e1);
    350             break;
    351         }
    352         e2 = e1;
    353         e1 = e1->next;
    354     }
    355     if (e1 == NULL) {
    356         ret = -ENOENT;
    357         goto exit;
    358     }
    359 
    360     // release effect in library
    361     if (fx->lib == NULL) {
    362         LOGW("EffectRelease() fx %p library already unloaded", handle);
    363     } else {
    364         pthread_mutex_lock(&fx->lib->lock);
    365         fx->lib->desc->release_effect(fx->subItfe);
    366         pthread_mutex_unlock(&fx->lib->lock);
    367     }
    368     free(fx);
    369 
    370 exit:
    371     pthread_mutex_unlock(&gLibLock);
    372     return ret;
    373 }
    374 
    375 int EffectIsNullUuid(effect_uuid_t *uuid)
    376 {
    377     if (memcmp(uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t))) {
    378         return 0;
    379     }
    380     return 1;
    381 }
    382 
    383 /////////////////////////////////////////////////
    384 //      Local functions
    385 /////////////////////////////////////////////////
    386 
    387 int init() {
    388     int hdl;
    389 
    390     if (gInitDone) {
    391         return 0;
    392     }
    393 
    394     pthread_mutex_init(&gLibLock, NULL);
    395 
    396     if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
    397         loadEffectConfigFile(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
    398     } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
    399         loadEffectConfigFile(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
    400     }
    401 
    402     updateNumEffects();
    403     gInitDone = 1;
    404     LOGV("init() done");
    405     return 0;
    406 }
    407 
    408 int loadEffectConfigFile(const char *path)
    409 {
    410     cnode *root;
    411     char *data;
    412 
    413     data = load_file(path, NULL);
    414     if (data == NULL) {
    415         return -ENODEV;
    416     }
    417     root = config_node("", "");
    418     config_load(root, data);
    419     loadLibraries(root);
    420     loadEffects(root);
    421     config_free(root);
    422     free(root);
    423     free(data);
    424 
    425     return 0;
    426 }
    427 
    428 int loadLibraries(cnode *root)
    429 {
    430     cnode *node;
    431 
    432     node = config_find(root, LIBRARIES_TAG);
    433     if (node == NULL) {
    434         return -ENOENT;
    435     }
    436     node = node->first_child;
    437     while (node) {
    438         loadLibrary(node, node->name);
    439         node = node->next;
    440     }
    441     return 0;
    442 }
    443 
    444 int loadLibrary(cnode *root, const char *name)
    445 {
    446     cnode *node;
    447     void *hdl;
    448     audio_effect_library_t *desc;
    449     list_elem_t *e;
    450     lib_entry_t *l;
    451 
    452     node = config_find(root, PATH_TAG);
    453     if (node == NULL) {
    454         return -EINVAL;
    455     }
    456 
    457     hdl = dlopen(node->value, RTLD_NOW);
    458     if (hdl == NULL) {
    459         LOGW("loadLibrary() failed to open %s", node->value);
    460         goto error;
    461     }
    462 
    463     desc = (audio_effect_library_t *)dlsym(hdl, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
    464     if (desc == NULL) {
    465         LOGW("loadLibrary() could not find symbol %s", AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
    466         goto error;
    467     }
    468 
    469     if (AUDIO_EFFECT_LIBRARY_TAG != desc->tag) {
    470         LOGW("getLibrary() bad tag %08x in lib info struct", desc->tag);
    471         goto error;
    472     }
    473 
    474     if (EFFECT_API_VERSION_MAJOR(desc->version) !=
    475             EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION)) {
    476         LOGW("loadLibrary() bad lib version %08x", desc->version);
    477         goto error;
    478     }
    479 
    480     // add entry for library in gLibraryList
    481     l = malloc(sizeof(lib_entry_t));
    482     l->name = strndup(name, PATH_MAX);
    483     l->path = strndup(node->value, PATH_MAX);
    484     l->handle = hdl;
    485     l->desc = desc;
    486     l->effects = NULL;
    487     pthread_mutex_init(&l->lock, NULL);
    488 
    489     e = malloc(sizeof(list_elem_t));
    490     e->object = l;
    491     pthread_mutex_lock(&gLibLock);
    492     e->next = gLibraryList;
    493     gLibraryList = e;
    494     pthread_mutex_unlock(&gLibLock);
    495     LOGV("getLibrary() linked library %p for path %s", l, node->value);
    496 
    497     return 0;
    498 
    499 error:
    500     if (hdl != NULL) {
    501         dlclose(hdl);
    502     }
    503     return -EINVAL;
    504 }
    505 
    506 int loadEffects(cnode *root)
    507 {
    508     cnode *node;
    509 
    510     node = config_find(root, EFFECTS_TAG);
    511     if (node == NULL) {
    512         return -ENOENT;
    513     }
    514     node = node->first_child;
    515     while (node) {
    516         loadEffect(node);
    517         node = node->next;
    518     }
    519     return 0;
    520 }
    521 
    522 int loadEffect(cnode *root)
    523 {
    524     cnode *node;
    525     effect_uuid_t uuid;
    526     lib_entry_t *l;
    527     effect_descriptor_t *d;
    528     list_elem_t *e;
    529 
    530     node = config_find(root, LIBRARY_TAG);
    531     if (node == NULL) {
    532         return -EINVAL;
    533     }
    534 
    535     l = getLibrary(node->value);
    536     if (l == NULL) {
    537         LOGW("loadEffect() could not get library %s", node->value);
    538         return -EINVAL;
    539     }
    540 
    541     node = config_find(root, UUID_TAG);
    542     if (node == NULL) {
    543         return -EINVAL;
    544     }
    545     if (stringToUuid(node->value, &uuid) != 0) {
    546         LOGW("loadEffect() invalid uuid %s", node->value);
    547         return -EINVAL;
    548     }
    549 
    550     d = malloc(sizeof(effect_descriptor_t));
    551     if (l->desc->get_descriptor(&uuid, d) != 0) {
    552         char s[40];
    553         uuidToString(&uuid, s, 40);
    554         LOGW("Error querying effect %s on lib %s", s, l->name);
    555         free(d);
    556         return -EINVAL;
    557     }
    558 #if (LOG_NDEBUG==0)
    559     char s[256];
    560     dumpEffectDescriptor(d, s, 256);
    561     LOGV("loadEffect() read descriptor %p:%s",d, s);
    562 #endif
    563     if (EFFECT_API_VERSION_MAJOR(d->apiVersion) !=
    564             EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) {
    565         LOGW("Bad API version %08x on lib %s", d->apiVersion, l->name);
    566         free(d);
    567         return -EINVAL;
    568     }
    569     e = malloc(sizeof(list_elem_t));
    570     e->object = d;
    571     e->next = l->effects;
    572     l->effects = e;
    573 
    574     return 0;
    575 }
    576 
    577 lib_entry_t *getLibrary(const char *name)
    578 {
    579     list_elem_t *e;
    580 
    581     if (gCachedLibrary &&
    582             !strncmp(gCachedLibrary->name, name, PATH_MAX)) {
    583         return gCachedLibrary;
    584     }
    585 
    586     e = gLibraryList;
    587     while (e) {
    588         lib_entry_t *l = (lib_entry_t *)e->object;
    589         if (!strcmp(l->name, name)) {
    590             gCachedLibrary = l;
    591             return l;
    592         }
    593         e = e->next;
    594     }
    595 
    596     return NULL;
    597 }
    598 
    599 
    600 void resetEffectEnumeration()
    601 {
    602     gCurLib = gLibraryList;
    603     gCurEffect = NULL;
    604     if (gCurLib) {
    605         gCurEffect = ((lib_entry_t *)gCurLib->object)->effects;
    606     }
    607     gCurEffectIdx = 0;
    608 }
    609 
    610 uint32_t updateNumEffects() {
    611     list_elem_t *e;
    612     uint32_t cnt = 0;
    613 
    614     resetEffectEnumeration();
    615 
    616     e = gLibraryList;
    617     while (e) {
    618         lib_entry_t *l = (lib_entry_t *)e->object;
    619         list_elem_t *efx = l->effects;
    620         while (efx) {
    621             cnt++;
    622             efx = efx->next;
    623         }
    624         e = e->next;
    625     }
    626     gNumEffects = cnt;
    627     gCanQueryEffect = 0;
    628     return cnt;
    629 }
    630 
    631 int findEffect(effect_uuid_t *type,
    632                effect_uuid_t *uuid,
    633                lib_entry_t **lib,
    634                effect_descriptor_t **desc)
    635 {
    636     list_elem_t *e = gLibraryList;
    637     lib_entry_t *l = NULL;
    638     effect_descriptor_t *d = NULL;
    639     int found = 0;
    640     int ret = 0;
    641 
    642     while (e && !found) {
    643         l = (lib_entry_t *)e->object;
    644         list_elem_t *efx = l->effects;
    645         while (efx) {
    646             d = (effect_descriptor_t *)efx->object;
    647             if (type != NULL && memcmp(&d->type, type, sizeof(effect_uuid_t)) == 0) {
    648                 found = 1;
    649                 break;
    650             }
    651             if (uuid != NULL && memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
    652                 found = 1;
    653                 break;
    654             }
    655             efx = efx->next;
    656         }
    657         e = e->next;
    658     }
    659     if (!found) {
    660         LOGV("findEffect() effect not found");
    661         ret = -ENOENT;
    662     } else {
    663         LOGV("findEffect() found effect: %s in lib %s", d->name, l->name);
    664         *lib = l;
    665         if (desc) {
    666             *desc = d;
    667         }
    668     }
    669 
    670     return ret;
    671 }
    672 
    673 void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len) {
    674     char s[256];
    675 
    676     snprintf(str, len, "\nEffect Descriptor %p:\n", desc);
    677     strncat(str, "- TYPE: ", len);
    678     uuidToString(&desc->uuid, s, 256);
    679     snprintf(str, len, "- UUID: %s\n", s);
    680     uuidToString(&desc->type, s, 256);
    681     snprintf(str, len, "- TYPE: %s\n", s);
    682     sprintf(s, "- apiVersion: %08X\n- flags: %08X\n",
    683             desc->apiVersion, desc->flags);
    684     strncat(str, s, len);
    685     sprintf(s, "- name: %s\n", desc->name);
    686     strncat(str, s, len);
    687     sprintf(s, "- implementor: %s\n", desc->implementor);
    688     strncat(str, s, len);
    689 }
    690 
    691 int stringToUuid(const char *str, effect_uuid_t *uuid)
    692 {
    693     int tmp[10];
    694 
    695     if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
    696             tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
    697         return -EINVAL;
    698     }
    699     uuid->timeLow = (uint32_t)tmp[0];
    700     uuid->timeMid = (uint16_t)tmp[1];
    701     uuid->timeHiAndVersion = (uint16_t)tmp[2];
    702     uuid->clockSeq = (uint16_t)tmp[3];
    703     uuid->node[0] = (uint8_t)tmp[4];
    704     uuid->node[1] = (uint8_t)tmp[5];
    705     uuid->node[2] = (uint8_t)tmp[6];
    706     uuid->node[3] = (uint8_t)tmp[7];
    707     uuid->node[4] = (uint8_t)tmp[8];
    708     uuid->node[5] = (uint8_t)tmp[9];
    709 
    710     return 0;
    711 }
    712 
    713 int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen)
    714 {
    715 
    716     snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
    717             uuid->timeLow,
    718             uuid->timeMid,
    719             uuid->timeHiAndVersion,
    720             uuid->clockSeq,
    721             uuid->node[0],
    722             uuid->node[1],
    723             uuid->node[2],
    724             uuid->node[3],
    725             uuid->node[4],
    726             uuid->node[5]);
    727 
    728     return 0;
    729 }
    730 
    731