| Eric Laurent | 801a118 | 2010-06-09 00:17:29 -0700 | [diff] [blame] | 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 <cutils/atomic.h> | 
 | 31 | #include <binder/IPCThreadState.h> | 
 | 32 |  | 
 | 33 |  | 
 | 34 |  | 
 | 35 | namespace android { | 
 | 36 |  | 
 | 37 | // --------------------------------------------------------------------------- | 
 | 38 |  | 
 | 39 | AudioEffect::AudioEffect() | 
 | 40 |     : mStatus(NO_INIT) | 
 | 41 | { | 
 | 42 | } | 
 | 43 |  | 
 | 44 |  | 
 | 45 | AudioEffect::AudioEffect(const effect_uuid_t *type, | 
 | 46 |                 const effect_uuid_t *uuid, | 
 | 47 |                 int32_t priority, | 
 | 48 |                 effect_callback_t cbf, | 
 | 49 |                 void* user, | 
 | 50 |                 int sessionId, | 
 | 51 |                 audio_io_handle_t output | 
 | 52 |                 ) | 
 | 53 |     : mStatus(NO_INIT) | 
 | 54 | { | 
| Jean-Michel Trivi | 42a050f | 2010-07-09 12:11:49 -0700 | [diff] [blame^] | 55 |     mStatus = set(type, uuid, priority, cbf, user, sessionId, output); | 
| Eric Laurent | 801a118 | 2010-06-09 00:17:29 -0700 | [diff] [blame] | 56 | } | 
 | 57 |  | 
 | 58 | AudioEffect::AudioEffect(const char *typeStr, | 
 | 59 |                 const char *uuidStr, | 
 | 60 |                 int32_t priority, | 
 | 61 |                 effect_callback_t cbf, | 
 | 62 |                 void* user, | 
 | 63 |                 int sessionId, | 
 | 64 |                 audio_io_handle_t output | 
 | 65 |                 ) | 
 | 66 |     : mStatus(NO_INIT) | 
 | 67 | { | 
 | 68 |     effect_uuid_t type; | 
 | 69 |     effect_uuid_t *pType = NULL; | 
 | 70 |     effect_uuid_t uuid; | 
 | 71 |     effect_uuid_t *pUuid = NULL; | 
 | 72 |  | 
 | 73 |     LOGV("Constructor string\n - type: %s\n - uuid: %s", typeStr, uuidStr); | 
 | 74 |  | 
 | 75 |     if (typeStr != NULL) { | 
 | 76 |         if (stringToGuid(typeStr, &type) == NO_ERROR) { | 
 | 77 |             pType = &type; | 
 | 78 |         } | 
 | 79 |     } | 
 | 80 |  | 
 | 81 |     if (uuidStr != NULL) { | 
 | 82 |         if (stringToGuid(uuidStr, &uuid) == NO_ERROR) { | 
 | 83 |             pUuid = &uuid; | 
 | 84 |         } | 
 | 85 |     } | 
 | 86 |  | 
| Jean-Michel Trivi | 42a050f | 2010-07-09 12:11:49 -0700 | [diff] [blame^] | 87 |     mStatus = set(pType, pUuid, priority, cbf, user, sessionId, output); | 
| Eric Laurent | 801a118 | 2010-06-09 00:17:29 -0700 | [diff] [blame] | 88 | } | 
 | 89 |  | 
 | 90 | status_t AudioEffect::set(const effect_uuid_t *type, | 
 | 91 |                 const effect_uuid_t *uuid, | 
 | 92 |                 int32_t priority, | 
 | 93 |                 effect_callback_t cbf, | 
 | 94 |                 void* user, | 
 | 95 |                 int sessionId, | 
 | 96 |                 audio_io_handle_t output) | 
 | 97 | { | 
 | 98 |     sp<IEffect> iEffect; | 
 | 99 |     sp<IMemory> cblk; | 
 | 100 |     int enabled; | 
 | 101 |  | 
 | 102 |     LOGV("set %p mUserData: %p", this, user); | 
 | 103 |  | 
 | 104 |     if (mIEffect != 0) { | 
 | 105 |         LOGW("Effect already in use"); | 
 | 106 |         return INVALID_OPERATION; | 
 | 107 |     } | 
 | 108 |  | 
 | 109 |     const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); | 
 | 110 |     if (audioFlinger == 0) { | 
 | 111 |         LOGE("set(): Could not get audioflinger"); | 
 | 112 |         return NO_INIT; | 
 | 113 |     } | 
 | 114 |  | 
 | 115 |     if (type == NULL && uuid == NULL) { | 
 | 116 |         LOGW("Must specify at least type or uuid"); | 
 | 117 |         return BAD_VALUE; | 
 | 118 |     } | 
 | 119 |  | 
 | 120 |     mPriority = priority; | 
 | 121 |     mCbf = cbf; | 
 | 122 |     mUserData = user; | 
 | 123 |     mSessionId = sessionId; | 
 | 124 |  | 
 | 125 |     memset(&mDescriptor, 0, sizeof(effect_descriptor_t)); | 
 | 126 |     memcpy(&mDescriptor.type, EFFECT_UUID_NULL, sizeof(effect_uuid_t)); | 
 | 127 |     memcpy(&mDescriptor.uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t)); | 
 | 128 |  | 
 | 129 |     if (type != NULL) { | 
 | 130 |         memcpy(&mDescriptor.type, type, sizeof(effect_uuid_t)); | 
 | 131 |     } | 
 | 132 |     if (uuid != NULL) { | 
 | 133 |         memcpy(&mDescriptor.uuid, uuid, sizeof(effect_uuid_t)); | 
 | 134 |     } | 
 | 135 |  | 
 | 136 |     mIEffectClient = new EffectClient(this); | 
 | 137 |  | 
 | 138 |     iEffect = audioFlinger->createEffect(getpid(), (effect_descriptor_t *)&mDescriptor, | 
 | 139 |             mIEffectClient, priority, output, mSessionId, &mStatus, &mId, &enabled); | 
 | 140 |  | 
 | 141 |     if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) { | 
 | 142 |         LOGE("set(): AudioFlinger could not create effect, status: %d", mStatus); | 
 | 143 |         return mStatus; | 
 | 144 |     } | 
 | 145 |  | 
 | 146 |     mEnabled = (volatile int32_t)enabled; | 
 | 147 |  | 
 | 148 |     mIEffect = iEffect; | 
 | 149 |     cblk = iEffect->getCblk(); | 
 | 150 |     if (cblk == 0) { | 
 | 151 |         mStatus = NO_INIT; | 
 | 152 |         LOGE("Could not get control block"); | 
 | 153 |         return mStatus; | 
 | 154 |     } | 
 | 155 |  | 
 | 156 |     mIEffect = iEffect; | 
 | 157 |     mCblkMemory = cblk; | 
 | 158 |     mCblk = static_cast<effect_param_cblk_t*>(cblk->pointer()); | 
 | 159 |     int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int); | 
 | 160 |     mCblk->buffer = (uint8_t *)mCblk + bufOffset; | 
 | 161 |  | 
 | 162 |     iEffect->asBinder()->linkToDeath(mIEffectClient); | 
 | 163 |     LOGV("set() %p OK effect: %s id: %d status %d enabled %d, ", this, mDescriptor.name, mId, mStatus, mEnabled); | 
 | 164 |  | 
 | 165 |     return mStatus; | 
 | 166 | } | 
 | 167 |  | 
 | 168 |  | 
 | 169 | AudioEffect::~AudioEffect() | 
 | 170 | { | 
 | 171 |     LOGV("Destructor %p", this); | 
 | 172 |  | 
 | 173 |     if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) { | 
| Eric Laurent | da7581b | 2010-07-02 08:12:41 -0700 | [diff] [blame] | 174 |         setEnabled(false); | 
| Eric Laurent | 801a118 | 2010-06-09 00:17:29 -0700 | [diff] [blame] | 175 |         if (mIEffect != NULL) { | 
 | 176 |             mIEffect->disconnect(); | 
 | 177 |             mIEffect->asBinder()->unlinkToDeath(mIEffectClient); | 
 | 178 |         } | 
 | 179 |          IPCThreadState::self()->flushCommands(); | 
 | 180 |     } | 
 | 181 |     mIEffect.clear(); | 
 | 182 |     mIEffectClient.clear(); | 
 | 183 |     mCblkMemory.clear(); | 
 | 184 | } | 
 | 185 |  | 
 | 186 |  | 
 | 187 | status_t AudioEffect::initCheck() const | 
 | 188 | { | 
 | 189 |     return mStatus; | 
 | 190 | } | 
 | 191 |  | 
 | 192 | // ------------------------------------------------------------------------- | 
 | 193 |  | 
 | 194 | effect_descriptor_t AudioEffect::descriptor() const | 
 | 195 | { | 
 | 196 |     return mDescriptor; | 
 | 197 | } | 
 | 198 |  | 
| Eric Laurent | da7581b | 2010-07-02 08:12:41 -0700 | [diff] [blame] | 199 | bool AudioEffect::getEnabled() const | 
| Eric Laurent | 801a118 | 2010-06-09 00:17:29 -0700 | [diff] [blame] | 200 | { | 
 | 201 |     return (mEnabled != 0); | 
 | 202 | } | 
 | 203 |  | 
| Eric Laurent | da7581b | 2010-07-02 08:12:41 -0700 | [diff] [blame] | 204 | status_t AudioEffect::setEnabled(bool enabled) | 
| Eric Laurent | 801a118 | 2010-06-09 00:17:29 -0700 | [diff] [blame] | 205 | { | 
 | 206 |     if (mStatus != NO_ERROR) { | 
 | 207 |         return INVALID_OPERATION; | 
 | 208 |     } | 
| Eric Laurent | 801a118 | 2010-06-09 00:17:29 -0700 | [diff] [blame] | 209 |  | 
| Eric Laurent | da7581b | 2010-07-02 08:12:41 -0700 | [diff] [blame] | 210 |     if (enabled) { | 
 | 211 |         LOGV("enable %p", this); | 
 | 212 |         if (android_atomic_or(1, &mEnabled) == 0) { | 
 | 213 |            return mIEffect->enable(); | 
 | 214 |         } | 
 | 215 |     } else { | 
 | 216 |         LOGV("disable %p", this); | 
 | 217 |         if (android_atomic_and(~1, &mEnabled) == 1) { | 
 | 218 |            return mIEffect->disable(); | 
 | 219 |         } | 
| Eric Laurent | 801a118 | 2010-06-09 00:17:29 -0700 | [diff] [blame] | 220 |     } | 
| Eric Laurent | 801a118 | 2010-06-09 00:17:29 -0700 | [diff] [blame] | 221 |     return INVALID_OPERATION; | 
 | 222 | } | 
 | 223 |  | 
 | 224 | status_t AudioEffect::command(int32_t cmdCode, int32_t cmdSize, void *cmdData, int32_t *replySize, void *replyData) | 
 | 225 | { | 
 | 226 |     if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) { | 
 | 227 |         return INVALID_OPERATION; | 
 | 228 |     } | 
 | 229 |  | 
 | 230 |     return mIEffect->command(cmdCode, cmdSize, cmdData, replySize, replyData); | 
 | 231 | } | 
 | 232 |  | 
 | 233 |  | 
 | 234 | status_t AudioEffect::setParameter(effect_param_t *param) | 
 | 235 | { | 
 | 236 |     if (mStatus != NO_ERROR) { | 
 | 237 |         return INVALID_OPERATION; | 
 | 238 |     } | 
 | 239 |  | 
 | 240 |     if (param == NULL || param->psize == 0 || param->vsize == 0) { | 
 | 241 |         return BAD_VALUE; | 
 | 242 |     } | 
 | 243 |  | 
 | 244 |     int size = sizeof(int); | 
 | 245 |     int psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize; | 
 | 246 |  | 
 | 247 |     LOGV("setParameter: param: %d, param2: %d", *(int *)param->data, (param->psize == 8) ? *((int *)param->data + 1): -1); | 
 | 248 |  | 
 | 249 |     return mIEffect->command(EFFECT_CMD_SET_PARAM, sizeof (effect_param_t) + psize, param, &size, ¶m->status); | 
 | 250 | } | 
 | 251 |  | 
 | 252 | status_t AudioEffect::setParameterDeferred(effect_param_t *param) | 
 | 253 | { | 
 | 254 |     if (mStatus != NO_ERROR) { | 
 | 255 |         return INVALID_OPERATION; | 
 | 256 |     } | 
 | 257 |  | 
 | 258 |     if (param == NULL || param->psize == 0 || param->vsize == 0) { | 
 | 259 |         return BAD_VALUE; | 
 | 260 |     } | 
 | 261 |  | 
 | 262 |     Mutex::Autolock _l(mCblk->lock); | 
 | 263 |  | 
 | 264 |     int psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize; | 
 | 265 |     int size = ((sizeof(effect_param_t) + psize - 1) / sizeof(int) + 1) * sizeof(int); | 
 | 266 |  | 
 | 267 |     if (mCblk->clientIndex + size > EFFECT_PARAM_BUFFER_SIZE) { | 
 | 268 |         return NO_MEMORY; | 
 | 269 |     } | 
 | 270 |     int *p = (int *)(mCblk->buffer + mCblk->clientIndex); | 
 | 271 |     *p++ = size; | 
 | 272 |     memcpy(p, param, sizeof(effect_param_t) + psize); | 
 | 273 |     mCblk->clientIndex += size; | 
 | 274 |  | 
 | 275 |     return NO_ERROR; | 
 | 276 | } | 
 | 277 |  | 
 | 278 | status_t AudioEffect::setParameterCommit() | 
 | 279 | { | 
 | 280 |     if (mStatus != NO_ERROR) { | 
 | 281 |         return INVALID_OPERATION; | 
 | 282 |     } | 
 | 283 |  | 
 | 284 |     Mutex::Autolock _l(mCblk->lock); | 
 | 285 |     if (mCblk->clientIndex == 0) { | 
 | 286 |         return INVALID_OPERATION; | 
 | 287 |     } | 
 | 288 |     int size = 0; | 
 | 289 |     return mIEffect->command(EFFECT_CMD_SET_PARAM_COMMIT, 0, NULL, &size, NULL); | 
 | 290 | } | 
 | 291 |  | 
 | 292 | status_t AudioEffect::getParameter(effect_param_t *param) | 
 | 293 | { | 
 | 294 |     if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) { | 
 | 295 |         return INVALID_OPERATION; | 
 | 296 |     } | 
 | 297 |  | 
 | 298 |     if (param == NULL || param->psize == 0 || param->vsize == 0) { | 
 | 299 |         return BAD_VALUE; | 
 | 300 |     } | 
 | 301 |  | 
 | 302 |     LOGV("getParameter: param: %d, param2: %d", *(int *)param->data, (param->psize == 8) ? *((int *)param->data + 1): -1); | 
 | 303 |  | 
 | 304 |     int psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize; | 
 | 305 |  | 
 | 306 |     return mIEffect->command(EFFECT_CMD_GET_PARAM, sizeof(effect_param_t) + param->psize, param, &psize, param); | 
 | 307 | } | 
 | 308 |  | 
 | 309 |  | 
 | 310 | // ------------------------------------------------------------------------- | 
 | 311 |  | 
 | 312 | void AudioEffect::binderDied() | 
 | 313 | { | 
 | 314 |     LOGW("IEffect died"); | 
 | 315 |     mStatus = NO_INIT; | 
 | 316 |     if (mCbf) { | 
 | 317 |         status_t status = DEAD_OBJECT; | 
 | 318 |         mCbf(EVENT_ERROR, mUserData, &status); | 
 | 319 |     } | 
 | 320 |     mIEffect.clear(); | 
 | 321 | } | 
 | 322 |  | 
 | 323 | // ------------------------------------------------------------------------- | 
 | 324 |  | 
 | 325 | void AudioEffect::controlStatusChanged(bool controlGranted) | 
 | 326 | { | 
 | 327 |     LOGV("controlStatusChanged %p control %d callback %p mUserData %p", this, controlGranted, mCbf, mUserData); | 
 | 328 |     if (controlGranted) { | 
 | 329 |         if (mStatus == ALREADY_EXISTS) { | 
 | 330 |             mStatus = NO_ERROR; | 
 | 331 |         } | 
 | 332 |     } else { | 
 | 333 |         if (mStatus == NO_ERROR) { | 
 | 334 |             mStatus = ALREADY_EXISTS; | 
 | 335 |         } | 
 | 336 |     } | 
 | 337 |     if (mCbf) { | 
 | 338 |         mCbf(EVENT_CONTROL_STATUS_CHANGED, mUserData, &controlGranted); | 
 | 339 |     } | 
 | 340 | } | 
 | 341 |  | 
 | 342 | void AudioEffect::enableStatusChanged(bool enabled) | 
 | 343 | { | 
| Eric Laurent | da7581b | 2010-07-02 08:12:41 -0700 | [diff] [blame] | 344 |     LOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf); | 
| Eric Laurent | 801a118 | 2010-06-09 00:17:29 -0700 | [diff] [blame] | 345 |     if (mStatus == ALREADY_EXISTS) { | 
 | 346 |         mEnabled = enabled; | 
 | 347 |         if (mCbf) { | 
 | 348 |             mCbf(EVENT_ENABLE_STATUS_CHANGED, mUserData, &enabled); | 
 | 349 |         } | 
 | 350 |     } | 
 | 351 | } | 
 | 352 |  | 
 | 353 | void AudioEffect::commandExecuted(int cmdCode, int cmdSize, void *cmdData, int replySize, void *replyData) | 
 | 354 | { | 
 | 355 |     if (cmdData == NULL || replyData == NULL) { | 
 | 356 |         return; | 
 | 357 |     } | 
 | 358 |  | 
 | 359 |     if (mCbf && cmdCode == EFFECT_CMD_SET_PARAM) { | 
 | 360 |         effect_param_t *cmd = (effect_param_t *)cmdData; | 
 | 361 |         cmd->status = *(int32_t *)replyData; | 
 | 362 |         mCbf(EVENT_PARAMETER_CHANGED, mUserData, cmd); | 
 | 363 |     } | 
 | 364 | } | 
 | 365 |  | 
 | 366 | // ------------------------------------------------------------------------- | 
 | 367 |  | 
 | 368 | status_t AudioEffect::loadEffectLibrary(const char *libPath, int *handle) | 
 | 369 | { | 
 | 370 |     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); | 
 | 371 |     if (af == 0) return PERMISSION_DENIED; | 
 | 372 |     return af->loadEffectLibrary(libPath, handle); | 
 | 373 | } | 
 | 374 |  | 
 | 375 | status_t AudioEffect::unloadEffectLibrary(int handle) | 
 | 376 | { | 
 | 377 |     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); | 
 | 378 |     if (af == 0) return PERMISSION_DENIED; | 
 | 379 |     return af->unloadEffectLibrary(handle); | 
 | 380 | } | 
 | 381 |  | 
 | 382 | status_t AudioEffect::queryNumberEffects(uint32_t *numEffects) | 
 | 383 | { | 
 | 384 |     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); | 
 | 385 |     if (af == 0) return PERMISSION_DENIED; | 
 | 386 |     return af->queryNumberEffects(numEffects); | 
 | 387 | } | 
 | 388 |  | 
| Eric Laurent | ffe9c25 | 2010-06-23 17:38:20 -0700 | [diff] [blame] | 389 | status_t AudioEffect::queryEffect(uint32_t index, effect_descriptor_t *descriptor) | 
| Eric Laurent | 801a118 | 2010-06-09 00:17:29 -0700 | [diff] [blame] | 390 | { | 
 | 391 |     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); | 
 | 392 |     if (af == 0) return PERMISSION_DENIED; | 
| Eric Laurent | ffe9c25 | 2010-06-23 17:38:20 -0700 | [diff] [blame] | 393 |     return af->queryEffect(index, descriptor); | 
| Eric Laurent | 801a118 | 2010-06-09 00:17:29 -0700 | [diff] [blame] | 394 | } | 
 | 395 |  | 
 | 396 | status_t AudioEffect::getEffectDescriptor(effect_uuid_t *uuid, effect_descriptor_t *descriptor) | 
 | 397 | { | 
 | 398 |     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); | 
 | 399 |     if (af == 0) return PERMISSION_DENIED; | 
 | 400 |     return af->getEffectDescriptor(uuid, descriptor); | 
 | 401 | } | 
 | 402 |  | 
 | 403 | // ------------------------------------------------------------------------- | 
 | 404 |  | 
 | 405 | status_t AudioEffect::stringToGuid(const char *str, effect_uuid_t *guid) | 
 | 406 | { | 
 | 407 |     if (str == NULL || guid == NULL) { | 
 | 408 |         return BAD_VALUE; | 
 | 409 |     } | 
 | 410 |  | 
 | 411 |     int tmp[10]; | 
 | 412 |  | 
 | 413 |     if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", | 
 | 414 |             tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) { | 
 | 415 |         return BAD_VALUE; | 
 | 416 |     } | 
 | 417 |     guid->timeLow = (uint32_t)tmp[0]; | 
 | 418 |     guid->timeMid = (uint16_t)tmp[1]; | 
 | 419 |     guid->timeHiAndVersion = (uint16_t)tmp[2]; | 
 | 420 |     guid->clockSeq = (uint16_t)tmp[3]; | 
 | 421 |     guid->node[0] = (uint8_t)tmp[4]; | 
 | 422 |     guid->node[1] = (uint8_t)tmp[5]; | 
 | 423 |     guid->node[2] = (uint8_t)tmp[6]; | 
 | 424 |     guid->node[3] = (uint8_t)tmp[7]; | 
 | 425 |     guid->node[4] = (uint8_t)tmp[8]; | 
 | 426 |     guid->node[5] = (uint8_t)tmp[9]; | 
 | 427 |  | 
 | 428 |     return NO_ERROR; | 
 | 429 | } | 
 | 430 |  | 
 | 431 | status_t AudioEffect::guidToString(const effect_uuid_t *guid, char *str, size_t maxLen) | 
 | 432 | { | 
 | 433 |     if (guid == NULL || str == NULL) { | 
 | 434 |         return BAD_VALUE; | 
 | 435 |     } | 
 | 436 |  | 
 | 437 |     snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", | 
 | 438 |             guid->timeLow, | 
 | 439 |             guid->timeMid, | 
 | 440 |             guid->timeHiAndVersion, | 
 | 441 |             guid->clockSeq, | 
 | 442 |             guid->node[0], | 
 | 443 |             guid->node[1], | 
 | 444 |             guid->node[2], | 
 | 445 |             guid->node[3], | 
 | 446 |             guid->node[4], | 
 | 447 |             guid->node[5]); | 
 | 448 |  | 
 | 449 |     return NO_ERROR; | 
 | 450 | } | 
 | 451 |  | 
 | 452 |  | 
 | 453 | }; // namespace android | 
 | 454 |  |