1 /*
2 **
3 ** Copyright 2010, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 
19 //#define LOG_NDEBUG 0
20 #define LOG_TAG "AudioEffect"
21 
22 #include <stdint.h>
23 #include <sys/types.h>
24 #include <limits.h>
25 
26 #include <private/media/AudioEffectShared.h>
27 #include <media/AudioEffect.h>
28 
29 #include <utils/Log.h>
30 #include <binder/IPCThreadState.h>
31 
32 
33 
34 namespace android {
35 
36 // ---------------------------------------------------------------------------
37 
AudioEffect(const String16 & opPackageName)38 AudioEffect::AudioEffect(const String16& opPackageName)
39     : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName)
40 {
41 }
42 
43 
AudioEffect(const effect_uuid_t * type,const String16 & opPackageName,const effect_uuid_t * uuid,int32_t priority,effect_callback_t cbf,void * user,audio_session_t sessionId,audio_io_handle_t io,const AudioDeviceTypeAddr & device,bool probe)44 AudioEffect::AudioEffect(const effect_uuid_t *type,
45                 const String16& opPackageName,
46                 const effect_uuid_t *uuid,
47                 int32_t priority,
48                 effect_callback_t cbf,
49                 void* user,
50                 audio_session_t sessionId,
51                 audio_io_handle_t io,
52                 const AudioDeviceTypeAddr& device,
53                 bool probe
54                 )
55     : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName)
56 {
57     AutoMutex lock(mConstructLock);
58     mStatus = set(type, uuid, priority, cbf, user, sessionId, io, device, probe);
59 }
60 
AudioEffect(const char * typeStr,const String16 & opPackageName,const char * uuidStr,int32_t priority,effect_callback_t cbf,void * user,audio_session_t sessionId,audio_io_handle_t io,const AudioDeviceTypeAddr & device,bool probe)61 AudioEffect::AudioEffect(const char *typeStr,
62                 const String16& opPackageName,
63                 const char *uuidStr,
64                 int32_t priority,
65                 effect_callback_t cbf,
66                 void* user,
67                 audio_session_t sessionId,
68                 audio_io_handle_t io,
69                 const AudioDeviceTypeAddr& device,
70                 bool probe
71                 )
72     : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName)
73 {
74     effect_uuid_t type;
75     effect_uuid_t *pType = NULL;
76     effect_uuid_t uuid;
77     effect_uuid_t *pUuid = NULL;
78 
79     ALOGV("Constructor string\n - type: %s\n - uuid: %s", typeStr, uuidStr);
80 
81     if (typeStr != NULL) {
82         if (stringToGuid(typeStr, &type) == NO_ERROR) {
83             pType = &type;
84         }
85     }
86 
87     if (uuidStr != NULL) {
88         if (stringToGuid(uuidStr, &uuid) == NO_ERROR) {
89             pUuid = &uuid;
90         }
91     }
92 
93     AutoMutex lock(mConstructLock);
94     mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io, device, probe);
95 }
96 
set(const effect_uuid_t * type,const effect_uuid_t * uuid,int32_t priority,effect_callback_t cbf,void * user,audio_session_t sessionId,audio_io_handle_t io,const AudioDeviceTypeAddr & device,bool probe)97 status_t AudioEffect::set(const effect_uuid_t *type,
98                 const effect_uuid_t *uuid,
99                 int32_t priority,
100                 effect_callback_t cbf,
101                 void* user,
102                 audio_session_t sessionId,
103                 audio_io_handle_t io,
104                 const AudioDeviceTypeAddr& device,
105                 bool probe)
106 {
107     sp<IEffect> iEffect;
108     sp<IMemory> cblk;
109     int enabled;
110 
111     ALOGV("set %p mUserData: %p uuid: %p timeLow %08x", this, user, type, type ? type->timeLow : 0);
112 
113     if (mIEffect != 0) {
114         ALOGW("Effect already in use");
115         return INVALID_OPERATION;
116     }
117 
118     if (sessionId == AUDIO_SESSION_DEVICE && io != AUDIO_IO_HANDLE_NONE) {
119         ALOGW("IO handle should not be specified for device effect");
120         return BAD_VALUE;
121     }
122     const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
123     if (audioFlinger == 0) {
124         ALOGE("set(): Could not get audioflinger");
125         return NO_INIT;
126     }
127 
128     if (type == NULL && uuid == NULL) {
129         ALOGW("Must specify at least type or uuid");
130         return BAD_VALUE;
131     }
132     mProbe = probe;
133     mPriority = priority;
134     mCbf = cbf;
135     mUserData = user;
136     mSessionId = sessionId;
137 
138     memset(&mDescriptor, 0, sizeof(effect_descriptor_t));
139     mDescriptor.type = *(type != NULL ? type : EFFECT_UUID_NULL);
140     mDescriptor.uuid = *(uuid != NULL ? uuid : EFFECT_UUID_NULL);
141 
142     mIEffectClient = new EffectClient(this);
143     mClientPid = IPCThreadState::self()->getCallingPid();
144     mClientUid = IPCThreadState::self()->getCallingUid();
145 
146     iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor,
147             mIEffectClient, priority, io, mSessionId, device, mOpPackageName, mClientPid,
148             probe, &mStatus, &mId, &enabled);
149 
150     // In probe mode, we stop here and return the status: the IEffect interface to
151     // audio flinger will not be retained. initCheck() will return the creation status
152     // but all other APIs will return invalid operation.
153     if (probe || iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
154         char typeBuffer[64] = {}, uuidBuffer[64] = {};
155         guidToString(type, typeBuffer, sizeof(typeBuffer));
156         guidToString(uuid, uuidBuffer, sizeof(uuidBuffer));
157         ALOGE_IF(!probe, "set(): AudioFlinger could not create effect %s / %s, status: %d",
158                 type != nullptr ? typeBuffer : "NULL",
159                 uuid != nullptr ? uuidBuffer : "NULL",
160                 mStatus);
161         if (!probe && iEffect == 0) {
162             mStatus = NO_INIT;
163         }
164         return mStatus;
165     }
166 
167     mEnabled = (volatile int32_t)enabled;
168 
169     cblk = iEffect->getCblk();
170     if (cblk == 0) {
171         mStatus = NO_INIT;
172         ALOGE("Could not get control block");
173         return mStatus;
174     }
175 
176     mIEffect = iEffect;
177     mCblkMemory = cblk;
178     // TODO: Using unsecurePointer() has some associated security pitfalls
179     //       (see declaration for details).
180     //       Either document why it is safe in this case or address the
181     //       issue (e.g. by copying).
182     mCblk = static_cast<effect_param_cblk_t*>(cblk->unsecurePointer());
183     int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
184     mCblk->buffer = (uint8_t *)mCblk + bufOffset;
185 
186     IInterface::asBinder(iEffect)->linkToDeath(mIEffectClient);
187     ALOGV("set() %p OK effect: %s id: %d status %d enabled %d pid %d", this, mDescriptor.name, mId,
188             mStatus, mEnabled, mClientPid);
189 
190     if (!audio_is_global_session(mSessionId)) {
191         AudioSystem::acquireAudioSessionId(mSessionId, mClientPid, mClientUid);
192     }
193 
194     return mStatus;
195 }
196 
197 
~AudioEffect()198 AudioEffect::~AudioEffect()
199 {
200     ALOGV("Destructor %p", this);
201 
202     if (!mProbe && (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS)) {
203         if (!audio_is_global_session(mSessionId)) {
204             AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
205         }
206         if (mIEffect != NULL) {
207             mIEffect->disconnect();
208             IInterface::asBinder(mIEffect)->unlinkToDeath(mIEffectClient);
209         }
210         mIEffect.clear();
211         mCblkMemory.clear();
212     }
213     mIEffectClient.clear();
214     IPCThreadState::self()->flushCommands();
215 }
216 
217 
initCheck() const218 status_t AudioEffect::initCheck() const
219 {
220     return mStatus;
221 }
222 
223 // -------------------------------------------------------------------------
224 
descriptor() const225 effect_descriptor_t AudioEffect::descriptor() const
226 {
227     return mDescriptor;
228 }
229 
getEnabled() const230 bool AudioEffect::getEnabled() const
231 {
232     return (mEnabled != 0);
233 }
234 
setEnabled(bool enabled)235 status_t AudioEffect::setEnabled(bool enabled)
236 {
237     if (mProbe) {
238         return INVALID_OPERATION;
239     }
240     if (mStatus != NO_ERROR) {
241         return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
242     }
243 
244     status_t status = NO_ERROR;
245 
246     AutoMutex lock(mLock);
247     if (enabled != mEnabled) {
248         if (enabled) {
249             ALOGV("enable %p", this);
250             status = mIEffect->enable();
251         } else {
252             ALOGV("disable %p", this);
253             status = mIEffect->disable();
254         }
255         if (status == NO_ERROR) {
256             mEnabled = enabled;
257         }
258     }
259     return status;
260 }
261 
command(uint32_t cmdCode,uint32_t cmdSize,void * cmdData,uint32_t * replySize,void * replyData)262 status_t AudioEffect::command(uint32_t cmdCode,
263                               uint32_t cmdSize,
264                               void *cmdData,
265                               uint32_t *replySize,
266                               void *replyData)
267 {
268     if (mProbe) {
269         return INVALID_OPERATION;
270     }
271     if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
272         ALOGV("command() bad status %d", mStatus);
273         return mStatus;
274     }
275 
276     if (cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) {
277         if (mEnabled == (cmdCode == EFFECT_CMD_ENABLE)) {
278             return NO_ERROR;
279         }
280         if (replySize == NULL || *replySize != sizeof(status_t) || replyData == NULL) {
281             return BAD_VALUE;
282         }
283         mLock.lock();
284     }
285 
286     status_t status = mIEffect->command(cmdCode, cmdSize, cmdData, replySize, replyData);
287 
288     if (cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) {
289         if (status == NO_ERROR) {
290             status = *(status_t *)replyData;
291         }
292         if (status == NO_ERROR) {
293             mEnabled = (cmdCode == EFFECT_CMD_ENABLE);
294         }
295         mLock.unlock();
296     }
297 
298     return status;
299 }
300 
301 
setParameter(effect_param_t * param)302 status_t AudioEffect::setParameter(effect_param_t *param)
303 {
304     if (mProbe) {
305         return INVALID_OPERATION;
306     }
307     if (mStatus != NO_ERROR) {
308         return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
309     }
310 
311     if (param == NULL || param->psize == 0 || param->vsize == 0) {
312         return BAD_VALUE;
313     }
314 
315     uint32_t size = sizeof(int);
316     uint32_t psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
317 
318     ALOGV("setParameter: param: %d, param2: %d", *(int *)param->data,
319             (param->psize == 8) ? *((int *)param->data + 1): -1);
320 
321     return mIEffect->command(EFFECT_CMD_SET_PARAM, sizeof (effect_param_t) + psize, param, &size,
322             &param->status);
323 }
324 
setParameterDeferred(effect_param_t * param)325 status_t AudioEffect::setParameterDeferred(effect_param_t *param)
326 {
327     if (mProbe) {
328         return INVALID_OPERATION;
329     }
330     if (mStatus != NO_ERROR) {
331         return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
332     }
333 
334     if (param == NULL || param->psize == 0 || param->vsize == 0) {
335         return BAD_VALUE;
336     }
337 
338     Mutex::Autolock _l(mCblk->lock);
339 
340     int psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
341     int size = ((sizeof(effect_param_t) + psize - 1) / sizeof(int) + 1) * sizeof(int);
342 
343     if (mCblk->clientIndex + size > EFFECT_PARAM_BUFFER_SIZE) {
344         return NO_MEMORY;
345     }
346     int *p = (int *)(mCblk->buffer + mCblk->clientIndex);
347     *p++ = size;
348     memcpy(p, param, sizeof(effect_param_t) + psize);
349     mCblk->clientIndex += size;
350 
351     return NO_ERROR;
352 }
353 
setParameterCommit()354 status_t AudioEffect::setParameterCommit()
355 {
356     if (mProbe) {
357         return INVALID_OPERATION;
358     }
359     if (mStatus != NO_ERROR) {
360         return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
361     }
362 
363     Mutex::Autolock _l(mCblk->lock);
364     if (mCblk->clientIndex == 0) {
365         return INVALID_OPERATION;
366     }
367     uint32_t size = 0;
368     return mIEffect->command(EFFECT_CMD_SET_PARAM_COMMIT, 0, NULL, &size, NULL);
369 }
370 
getParameter(effect_param_t * param)371 status_t AudioEffect::getParameter(effect_param_t *param)
372 {
373     if (mProbe) {
374         return INVALID_OPERATION;
375     }
376     if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
377         return mStatus;
378     }
379 
380     if (param == NULL || param->psize == 0 || param->vsize == 0) {
381         return BAD_VALUE;
382     }
383 
384     ALOGV("getParameter: param: %d, param2: %d", *(int *)param->data,
385             (param->psize == 8) ? *((int *)param->data + 1): -1);
386 
387     uint32_t psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) +
388             param->vsize;
389 
390     return mIEffect->command(EFFECT_CMD_GET_PARAM, sizeof(effect_param_t) + param->psize, param,
391             &psize, param);
392 }
393 
394 
395 // -------------------------------------------------------------------------
396 
binderDied()397 void AudioEffect::binderDied()
398 {
399     ALOGW("IEffect died");
400     mStatus = DEAD_OBJECT;
401     if (mCbf != NULL) {
402         status_t status = DEAD_OBJECT;
403         mCbf(EVENT_ERROR, mUserData, &status);
404     }
405     mIEffect.clear();
406 }
407 
408 // -------------------------------------------------------------------------
409 
controlStatusChanged(bool controlGranted)410 void AudioEffect::controlStatusChanged(bool controlGranted)
411 {
412     ALOGV("controlStatusChanged %p control %d callback %p mUserData %p", this, controlGranted, mCbf,
413             mUserData);
414     if (controlGranted) {
415         if (mStatus == ALREADY_EXISTS) {
416             mStatus = NO_ERROR;
417         }
418     } else {
419         if (mStatus == NO_ERROR) {
420             mStatus = ALREADY_EXISTS;
421         }
422     }
423     if (mCbf != NULL) {
424         mCbf(EVENT_CONTROL_STATUS_CHANGED, mUserData, &controlGranted);
425     }
426 }
427 
enableStatusChanged(bool enabled)428 void AudioEffect::enableStatusChanged(bool enabled)
429 {
430     ALOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf);
431     if (mStatus == ALREADY_EXISTS) {
432         mEnabled = enabled;
433         if (mCbf != NULL) {
434             mCbf(EVENT_ENABLE_STATUS_CHANGED, mUserData, &enabled);
435         }
436     }
437 }
438 
commandExecuted(uint32_t cmdCode,uint32_t cmdSize __unused,void * cmdData,uint32_t replySize __unused,void * replyData)439 void AudioEffect::commandExecuted(uint32_t cmdCode,
440                                   uint32_t cmdSize __unused,
441                                   void *cmdData,
442                                   uint32_t replySize __unused,
443                                   void *replyData)
444 {
445     if (cmdData == NULL || replyData == NULL) {
446         return;
447     }
448 
449     if (mCbf != NULL && cmdCode == EFFECT_CMD_SET_PARAM) {
450         effect_param_t *cmd = (effect_param_t *)cmdData;
451         cmd->status = *(int32_t *)replyData;
452         mCbf(EVENT_PARAMETER_CHANGED, mUserData, cmd);
453     }
454 }
455 
456 // -------------------------------------------------------------------------
457 
queryNumberEffects(uint32_t * numEffects)458 status_t AudioEffect::queryNumberEffects(uint32_t *numEffects)
459 {
460     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
461     if (af == 0) return PERMISSION_DENIED;
462     return af->queryNumberEffects(numEffects);
463 }
464 
queryEffect(uint32_t index,effect_descriptor_t * descriptor)465 status_t AudioEffect::queryEffect(uint32_t index, effect_descriptor_t *descriptor)
466 {
467     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
468     if (af == 0) return PERMISSION_DENIED;
469     return af->queryEffect(index, descriptor);
470 }
471 
getEffectDescriptor(const effect_uuid_t * uuid,const effect_uuid_t * type,uint32_t preferredTypeFlag,effect_descriptor_t * descriptor)472 status_t AudioEffect::getEffectDescriptor(const effect_uuid_t *uuid,
473                                           const effect_uuid_t *type,
474                                           uint32_t preferredTypeFlag,
475                                           effect_descriptor_t *descriptor)
476 {
477     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
478     if (af == 0) return PERMISSION_DENIED;
479     return af->getEffectDescriptor(uuid, type, preferredTypeFlag, descriptor);
480 }
481 
queryDefaultPreProcessing(audio_session_t audioSession,effect_descriptor_t * descriptors,uint32_t * count)482 status_t AudioEffect::queryDefaultPreProcessing(audio_session_t audioSession,
483                                           effect_descriptor_t *descriptors,
484                                           uint32_t *count)
485 {
486     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
487     if (aps == 0) return PERMISSION_DENIED;
488     return aps->queryDefaultPreProcessing(audioSession, descriptors, count);
489 }
490 
newEffectUniqueId(audio_unique_id_t * id)491 status_t AudioEffect::newEffectUniqueId(audio_unique_id_t* id)
492 {
493     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
494     if (af == 0) return PERMISSION_DENIED;
495     *id = af->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
496     return NO_ERROR;
497 }
498 
addSourceDefaultEffect(const char * typeStr,const String16 & opPackageName,const char * uuidStr,int32_t priority,audio_source_t source,audio_unique_id_t * id)499 status_t AudioEffect::addSourceDefaultEffect(const char *typeStr,
500                                              const String16& opPackageName,
501                                              const char *uuidStr,
502                                              int32_t priority,
503                                              audio_source_t source,
504                                              audio_unique_id_t *id)
505 {
506     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
507     if (aps == 0) return PERMISSION_DENIED;
508 
509     if (typeStr == NULL && uuidStr == NULL) return BAD_VALUE;
510 
511     // Convert type & uuid from string to effect_uuid_t.
512     effect_uuid_t type;
513     if (typeStr != NULL) {
514         status_t res = stringToGuid(typeStr, &type);
515         if (res != OK) return res;
516     } else {
517         type = *EFFECT_UUID_NULL;
518     }
519 
520     effect_uuid_t uuid;
521     if (uuidStr != NULL) {
522         status_t res = stringToGuid(uuidStr, &uuid);
523         if (res != OK) return res;
524     } else {
525         uuid = *EFFECT_UUID_NULL;
526     }
527 
528     return aps->addSourceDefaultEffect(&type, opPackageName, &uuid, priority, source, id);
529 }
530 
addStreamDefaultEffect(const char * typeStr,const String16 & opPackageName,const char * uuidStr,int32_t priority,audio_usage_t usage,audio_unique_id_t * id)531 status_t AudioEffect::addStreamDefaultEffect(const char *typeStr,
532                                              const String16& opPackageName,
533                                              const char *uuidStr,
534                                              int32_t priority,
535                                              audio_usage_t usage,
536                                              audio_unique_id_t *id)
537 {
538     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
539     if (aps == 0) return PERMISSION_DENIED;
540 
541     if (typeStr == NULL && uuidStr == NULL) return BAD_VALUE;
542 
543     // Convert type & uuid from string to effect_uuid_t.
544     effect_uuid_t type;
545     if (typeStr != NULL) {
546         status_t res = stringToGuid(typeStr, &type);
547         if (res != OK) return res;
548     } else {
549         type = *EFFECT_UUID_NULL;
550     }
551 
552     effect_uuid_t uuid;
553     if (uuidStr != NULL) {
554         status_t res = stringToGuid(uuidStr, &uuid);
555         if (res != OK) return res;
556     } else {
557         uuid = *EFFECT_UUID_NULL;
558     }
559 
560     return aps->addStreamDefaultEffect(&type, opPackageName, &uuid, priority, usage, id);
561 }
562 
removeSourceDefaultEffect(audio_unique_id_t id)563 status_t AudioEffect::removeSourceDefaultEffect(audio_unique_id_t id)
564 {
565     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
566     if (aps == 0) return PERMISSION_DENIED;
567 
568     return aps->removeSourceDefaultEffect(id);
569 }
570 
removeStreamDefaultEffect(audio_unique_id_t id)571 status_t AudioEffect::removeStreamDefaultEffect(audio_unique_id_t id)
572 {
573     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
574     if (aps == 0) return PERMISSION_DENIED;
575 
576     return aps->removeStreamDefaultEffect(id);
577 }
578 
579 // -------------------------------------------------------------------------
580 
stringToGuid(const char * str,effect_uuid_t * guid)581 status_t AudioEffect::stringToGuid(const char *str, effect_uuid_t *guid)
582 {
583     if (str == NULL || guid == NULL) {
584         return BAD_VALUE;
585     }
586 
587     int tmp[10];
588 
589     if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
590             tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
591         return BAD_VALUE;
592     }
593     guid->timeLow = (uint32_t)tmp[0];
594     guid->timeMid = (uint16_t)tmp[1];
595     guid->timeHiAndVersion = (uint16_t)tmp[2];
596     guid->clockSeq = (uint16_t)tmp[3];
597     guid->node[0] = (uint8_t)tmp[4];
598     guid->node[1] = (uint8_t)tmp[5];
599     guid->node[2] = (uint8_t)tmp[6];
600     guid->node[3] = (uint8_t)tmp[7];
601     guid->node[4] = (uint8_t)tmp[8];
602     guid->node[5] = (uint8_t)tmp[9];
603 
604     return NO_ERROR;
605 }
606 
guidToString(const effect_uuid_t * guid,char * str,size_t maxLen)607 status_t AudioEffect::guidToString(const effect_uuid_t *guid, char *str, size_t maxLen)
608 {
609     if (guid == NULL || str == NULL) {
610         return BAD_VALUE;
611     }
612 
613     snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
614             guid->timeLow,
615             guid->timeMid,
616             guid->timeHiAndVersion,
617             guid->clockSeq,
618             guid->node[0],
619             guid->node[1],
620             guid->node[2],
621             guid->node[3],
622             guid->node[4],
623             guid->node[5]);
624 
625     return NO_ERROR;
626 }
627 
628 
629 } // namespace android
630