• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(const effect_uuid_t *type,
57                const 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 
Effect_Process(effect_handle_t self,audio_buffer_t * inBuffer,audio_buffer_t * outBuffer)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 
Effect_Command(effect_handle_t self,uint32_t cmdCode,uint32_t cmdSize,void * pCmdData,uint32_t * replySize,void * pReplyData)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 
Effect_GetDescriptor(effect_handle_t self,effect_descriptor_t * desc)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 
Effect_ProcessReverse(effect_handle_t self,audio_buffer_t * inBuffer,audio_buffer_t * outBuffer)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 
EffectQueryNumberEffects(uint32_t * pNumEffects)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     ALOGV("EffectQueryNumberEffects(): %d", *pNumEffects);
192     return ret;
193 }
194 
EffectQueryEffect(uint32_t index,effect_descriptor_t * pDescriptor)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                 *pDescriptor = *(effect_descriptor_t *)gCurEffect->object;
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     ALOGV("EffectQueryEffect() desc:%s", str);
234 #endif
235     pthread_mutex_unlock(&gLibLock);
236     return ret;
237 }
238 
EffectGetDescriptor(const effect_uuid_t * uuid,effect_descriptor_t * pDescriptor)239 int EffectGetDescriptor(const 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         *pDescriptor = *d;
255     }
256     pthread_mutex_unlock(&gLibLock);
257     return ret;
258 }
259 
EffectCreate(const effect_uuid_t * uuid,int32_t sessionId,int32_t ioId,effect_handle_t * pHandle)260 int EffectCreate(const 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     ALOGV("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         ALOGW("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         ALOGW("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         ALOGV("EffectCreate() gInterfaceWithReverse");
306     }   else {
307         fx->itfe = (struct effect_interface_s *)&gInterface;
308         ALOGV("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     ALOGV("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 
EffectRelease(effect_handle_t handle)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         ALOGW("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 
EffectIsNullUuid(const effect_uuid_t * uuid)375 int EffectIsNullUuid(const 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 
init()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     ALOGV("init() done");
405     return 0;
406 }
407 
loadEffectConfigFile(const char * path)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 
loadLibraries(cnode * root)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 
loadLibrary(cnode * root,const char * name)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         ALOGW("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         ALOGW("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         ALOGW("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         ALOGW("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     ALOGV("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 
loadEffects(cnode * root)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 
loadEffect(cnode * root)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         ALOGW("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         ALOGW("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         ALOGW("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     ALOGV("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         ALOGW("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 
getLibrary(const char * name)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 
resetEffectEnumeration()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 
updateNumEffects()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 
findEffect(const effect_uuid_t * type,const effect_uuid_t * uuid,lib_entry_t ** lib,effect_descriptor_t ** desc)631 int findEffect(const effect_uuid_t *type,
632                const 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         ALOGV("findEffect() effect not found");
661         ret = -ENOENT;
662     } else {
663         ALOGV("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 
dumpEffectDescriptor(effect_descriptor_t * desc,char * str,size_t len)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 
stringToUuid(const char * str,effect_uuid_t * uuid)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 
uuidToString(const effect_uuid_t * uuid,char * str,size_t maxLen)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