AudioPolicyEffects.cpp revision 7de5ac1f067ec61f7ea424d5534cfd40987b11fa
1/* 2 * Copyright (C) 2014 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 "AudioPolicyEffects" 18//#define LOG_NDEBUG 0 19 20#include <stdlib.h> 21#include <stdio.h> 22#include <string.h> 23#include <cutils/misc.h> 24#include <media/AudioEffect.h> 25#include <system/audio.h> 26#include <hardware/audio_effect.h> 27#include <audio_effects/audio_effects_conf.h> 28#include <utils/Vector.h> 29#include <utils/SortedVector.h> 30#include <cutils/config_utils.h> 31#include "AudioPolicyEffects.h" 32#include "ServiceUtilities.h" 33 34namespace android { 35 36// ---------------------------------------------------------------------------- 37// AudioPolicyEffects Implementation 38// ---------------------------------------------------------------------------- 39 40AudioPolicyEffects::AudioPolicyEffects() 41{ 42 // load automatic audio effect modules 43 if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) { 44 loadAudioEffectConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE); 45 } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) { 46 loadAudioEffectConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE); 47 } 48} 49 50 51AudioPolicyEffects::~AudioPolicyEffects() 52{ 53 size_t i = 0; 54 // release audio input processing resources 55 for (i = 0; i < mInputSources.size(); i++) { 56 delete mInputSources.valueAt(i); 57 } 58 mInputSources.clear(); 59 60 for (i = 0; i < mInputs.size(); i++) { 61 mInputs.valueAt(i)->mEffects.clear(); 62 delete mInputs.valueAt(i); 63 } 64 mInputs.clear(); 65 66 // release audio output processing resources 67 for (i = 0; i < mOutputStreams.size(); i++) { 68 delete mOutputStreams.valueAt(i); 69 } 70 mOutputStreams.clear(); 71 72 for (i = 0; i < mOutputSessions.size(); i++) { 73 mOutputSessions.valueAt(i)->mEffects.clear(); 74 delete mOutputSessions.valueAt(i); 75 } 76 mOutputSessions.clear(); 77} 78 79 80status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input, 81 audio_source_t inputSource, 82 int audioSession) 83{ 84 status_t status = NO_ERROR; 85 86 // create audio pre processors according to input source 87 audio_source_t aliasSource = (inputSource == AUDIO_SOURCE_HOTWORD) ? 88 AUDIO_SOURCE_VOICE_RECOGNITION : inputSource; 89 90 Mutex::Autolock _l(mLock); 91 ssize_t index = mInputSources.indexOfKey(aliasSource); 92 if (index < 0) { 93 ALOGV("addInputEffects(): no processing needs to be attached to this source"); 94 return status; 95 } 96 ssize_t idx = mInputs.indexOfKey(input); 97 EffectVector *inputDesc; 98 if (idx < 0) { 99 inputDesc = new EffectVector(audioSession); 100 mInputs.add(input, inputDesc); 101 } else { 102 // EffectVector is existing and we just need to increase ref count 103 inputDesc = mInputs.valueAt(idx); 104 } 105 inputDesc->mRefCount++; 106 107 ALOGV("addInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount); 108 if (inputDesc->mRefCount == 1) { 109 Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects; 110 for (size_t i = 0; i < effects.size(); i++) { 111 EffectDesc *effect = effects[i]; 112 sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, 113 audioSession, input); 114 status_t status = fx->initCheck(); 115 if (status != NO_ERROR && status != ALREADY_EXISTS) { 116 ALOGW("addInputEffects(): failed to create Fx %s on source %d", 117 effect->mName, (int32_t)aliasSource); 118 // fx goes out of scope and strong ref on AudioEffect is released 119 continue; 120 } 121 for (size_t j = 0; j < effect->mParams.size(); j++) { 122 fx->setParameter(effect->mParams[j]); 123 } 124 ALOGV("addInputEffects(): added Fx %s on source: %d", 125 effect->mName, (int32_t)aliasSource); 126 inputDesc->mEffects.add(fx); 127 } 128 inputDesc->setProcessorEnabled(true); 129 } 130 return status; 131} 132 133 134status_t AudioPolicyEffects::releaseInputEffects(audio_io_handle_t input) 135{ 136 status_t status = NO_ERROR; 137 138 Mutex::Autolock _l(mLock); 139 ssize_t index = mInputs.indexOfKey(input); 140 if (index < 0) { 141 return status; 142 } 143 EffectVector *inputDesc = mInputs.valueAt(index); 144 inputDesc->mRefCount--; 145 ALOGV("releaseInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount); 146 if (inputDesc->mRefCount == 0) { 147 inputDesc->setProcessorEnabled(false); 148 delete inputDesc; 149 mInputs.removeItemsAt(index); 150 ALOGV("releaseInputEffects(): all effects released"); 151 } 152 return status; 153} 154 155status_t AudioPolicyEffects::queryDefaultInputEffects(int audioSession, 156 effect_descriptor_t *descriptors, 157 uint32_t *count) 158{ 159 status_t status = NO_ERROR; 160 161 Mutex::Autolock _l(mLock); 162 size_t index; 163 for (index = 0; index < mInputs.size(); index++) { 164 if (mInputs.valueAt(index)->mSessionId == audioSession) { 165 break; 166 } 167 } 168 if (index == mInputs.size()) { 169 *count = 0; 170 return BAD_VALUE; 171 } 172 Vector< sp<AudioEffect> > effects = mInputs.valueAt(index)->mEffects; 173 174 for (size_t i = 0; i < effects.size(); i++) { 175 effect_descriptor_t desc = effects[i]->descriptor(); 176 if (i < *count) { 177 descriptors[i] = desc; 178 } 179 } 180 if (effects.size() > *count) { 181 status = NO_MEMORY; 182 } 183 *count = effects.size(); 184 return status; 185} 186 187 188status_t AudioPolicyEffects::queryDefaultOutputSessionEffects(int audioSession, 189 effect_descriptor_t *descriptors, 190 uint32_t *count) 191{ 192 status_t status = NO_ERROR; 193 194 Mutex::Autolock _l(mLock); 195 size_t index; 196 for (index = 0; index < mOutputSessions.size(); index++) { 197 if (mOutputSessions.valueAt(index)->mSessionId == audioSession) { 198 break; 199 } 200 } 201 if (index == mOutputSessions.size()) { 202 *count = 0; 203 return BAD_VALUE; 204 } 205 Vector< sp<AudioEffect> > effects = mOutputSessions.valueAt(index)->mEffects; 206 207 for (size_t i = 0; i < effects.size(); i++) { 208 effect_descriptor_t desc = effects[i]->descriptor(); 209 if (i < *count) { 210 descriptors[i] = desc; 211 } 212 } 213 if (effects.size() > *count) { 214 status = NO_MEMORY; 215 } 216 *count = effects.size(); 217 return status; 218} 219 220 221status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output, 222 audio_stream_type_t stream, 223 int audioSession) 224{ 225 status_t status = NO_ERROR; 226 227 Mutex::Autolock _l(mLock); 228 // create audio processors according to stream 229 ssize_t index = mOutputStreams.indexOfKey(stream); 230 if (index < 0) { 231 ALOGV("addOutputSessionEffects(): no output processing needed for this stream"); 232 return NO_ERROR; 233 } 234 235 ssize_t idx = mOutputSessions.indexOfKey(audioSession); 236 EffectVector *procDesc; 237 if (idx < 0) { 238 procDesc = new EffectVector(audioSession); 239 mOutputSessions.add(audioSession, procDesc); 240 } else { 241 // EffectVector is existing and we just need to increase ref count 242 procDesc = mOutputSessions.valueAt(idx); 243 } 244 procDesc->mRefCount++; 245 246 ALOGV("addOutputSessionEffects(): session: %d, refCount: %d", 247 audioSession, procDesc->mRefCount); 248 if (procDesc->mRefCount == 1) { 249 Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects; 250 for (size_t i = 0; i < effects.size(); i++) { 251 EffectDesc *effect = effects[i]; 252 sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, 0, 0, 0, 253 audioSession, output); 254 status_t status = fx->initCheck(); 255 if (status != NO_ERROR && status != ALREADY_EXISTS) { 256 ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d", 257 effect->mName, audioSession); 258 // fx goes out of scope and strong ref on AudioEffect is released 259 continue; 260 } 261 ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d", 262 effect->mName, audioSession, (int32_t)stream); 263 procDesc->mEffects.add(fx); 264 } 265 266 procDesc->setProcessorEnabled(true); 267 } 268 return status; 269} 270 271status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t output, 272 audio_stream_type_t stream, 273 int audioSession) 274{ 275 status_t status = NO_ERROR; 276 (void) output; // argument not used for now 277 (void) stream; // argument not used for now 278 279 Mutex::Autolock _l(mLock); 280 ssize_t index = mOutputSessions.indexOfKey(audioSession); 281 if (index < 0) { 282 ALOGV("releaseOutputSessionEffects: no output processing was attached to this stream"); 283 return NO_ERROR; 284 } 285 286 EffectVector *procDesc = mOutputSessions.valueAt(index); 287 procDesc->mRefCount--; 288 ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d", 289 audioSession, procDesc->mRefCount); 290 if (procDesc->mRefCount == 0) { 291 procDesc->setProcessorEnabled(false); 292 procDesc->mEffects.clear(); 293 delete procDesc; 294 mOutputSessions.removeItemsAt(index); 295 ALOGV("releaseOutputSessionEffects(): output processing released from session: %d", 296 audioSession); 297 } 298 return status; 299} 300 301 302void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled) 303{ 304 for (size_t i = 0; i < mEffects.size(); i++) { 305 mEffects.itemAt(i)->setEnabled(enabled); 306 } 307} 308 309 310// ---------------------------------------------------------------------------- 311// Audio processing configuration 312// ---------------------------------------------------------------------------- 313 314/*static*/ const char * const AudioPolicyEffects::kInputSourceNames[AUDIO_SOURCE_CNT -1] = { 315 MIC_SRC_TAG, 316 VOICE_UL_SRC_TAG, 317 VOICE_DL_SRC_TAG, 318 VOICE_CALL_SRC_TAG, 319 CAMCORDER_SRC_TAG, 320 VOICE_REC_SRC_TAG, 321 VOICE_COMM_SRC_TAG 322}; 323 324// returns the audio_source_t enum corresponding to the input source name or 325// AUDIO_SOURCE_CNT is no match found 326/*static*/ audio_source_t AudioPolicyEffects::inputSourceNameToEnum(const char *name) 327{ 328 int i; 329 for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) { 330 if (strcmp(name, kInputSourceNames[i - AUDIO_SOURCE_MIC]) == 0) { 331 ALOGV("inputSourceNameToEnum found source %s %d", name, i); 332 break; 333 } 334 } 335 return (audio_source_t)i; 336} 337 338const char *AudioPolicyEffects::kStreamNames[AUDIO_STREAM_CNT+1] = { 339 AUDIO_STREAM_DEFAULT_TAG, 340 AUDIO_STREAM_VOICE_CALL_TAG, 341 AUDIO_STREAM_SYSTEM_TAG, 342 AUDIO_STREAM_RING_TAG, 343 AUDIO_STREAM_MUSIC_TAG, 344 AUDIO_STREAM_ALARM_TAG, 345 AUDIO_STREAM_NOTIFICATION_TAG, 346 AUDIO_STREAM_BLUETOOTH_SCO_TAG, 347 AUDIO_STREAM_ENFORCED_AUDIBLE_TAG, 348 AUDIO_STREAM_DTMF_TAG, 349 AUDIO_STREAM_TTS_TAG 350}; 351 352// returns the audio_stream_t enum corresponding to the output stream name or 353// AUDIO_STREAM_CNT is no match found 354audio_stream_type_t AudioPolicyEffects::streamNameToEnum(const char *name) 355{ 356 int i; 357 for (i = AUDIO_STREAM_DEFAULT; i < AUDIO_STREAM_CNT; i++) { 358 if (strcmp(name, kStreamNames[i - AUDIO_STREAM_DEFAULT]) == 0) { 359 ALOGV("streamNameToEnum found stream %s %d", name, i); 360 break; 361 } 362 } 363 return (audio_stream_type_t)i; 364} 365 366// ---------------------------------------------------------------------------- 367// Audio Effect Config parser 368// ---------------------------------------------------------------------------- 369 370size_t AudioPolicyEffects::growParamSize(char *param, 371 size_t size, 372 size_t *curSize, 373 size_t *totSize) 374{ 375 // *curSize is at least sizeof(effect_param_t) + 2 * sizeof(int) 376 size_t pos = ((*curSize - 1 ) / size + 1) * size; 377 378 if (pos + size > *totSize) { 379 while (pos + size > *totSize) { 380 *totSize += ((*totSize + 7) / 8) * 4; 381 } 382 param = (char *)realloc(param, *totSize); 383 } 384 *curSize = pos + size; 385 return pos; 386} 387 388size_t AudioPolicyEffects::readParamValue(cnode *node, 389 char *param, 390 size_t *curSize, 391 size_t *totSize) 392{ 393 if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) { 394 size_t pos = growParamSize(param, sizeof(short), curSize, totSize); 395 *(short *)((char *)param + pos) = (short)atoi(node->value); 396 ALOGV("readParamValue() reading short %d", *(short *)((char *)param + pos)); 397 return sizeof(short); 398 } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) { 399 size_t pos = growParamSize(param, sizeof(int), curSize, totSize); 400 *(int *)((char *)param + pos) = atoi(node->value); 401 ALOGV("readParamValue() reading int %d", *(int *)((char *)param + pos)); 402 return sizeof(int); 403 } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) { 404 size_t pos = growParamSize(param, sizeof(float), curSize, totSize); 405 *(float *)((char *)param + pos) = (float)atof(node->value); 406 ALOGV("readParamValue() reading float %f",*(float *)((char *)param + pos)); 407 return sizeof(float); 408 } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) { 409 size_t pos = growParamSize(param, sizeof(bool), curSize, totSize); 410 if (strncmp(node->value, "false", strlen("false") + 1) == 0) { 411 *(bool *)((char *)param + pos) = false; 412 } else { 413 *(bool *)((char *)param + pos) = true; 414 } 415 ALOGV("readParamValue() reading bool %s",*(bool *)((char *)param + pos) ? "true" : "false"); 416 return sizeof(bool); 417 } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) { 418 size_t len = strnlen(node->value, EFFECT_STRING_LEN_MAX); 419 if (*curSize + len + 1 > *totSize) { 420 *totSize = *curSize + len + 1; 421 param = (char *)realloc(param, *totSize); 422 } 423 strncpy(param + *curSize, node->value, len); 424 *curSize += len; 425 param[*curSize] = '\0'; 426 ALOGV("readParamValue() reading string %s", param + *curSize - len); 427 return len; 428 } 429 ALOGW("readParamValue() unknown param type %s", node->name); 430 return 0; 431} 432 433effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root) 434{ 435 cnode *param; 436 cnode *value; 437 size_t curSize = sizeof(effect_param_t); 438 size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int); 439 effect_param_t *fx_param = (effect_param_t *)malloc(totSize); 440 441 param = config_find(root, PARAM_TAG); 442 value = config_find(root, VALUE_TAG); 443 if (param == NULL && value == NULL) { 444 // try to parse simple parameter form {int int} 445 param = root->first_child; 446 if (param != NULL) { 447 // Note: that a pair of random strings is read as 0 0 448 int *ptr = (int *)fx_param->data; 449 int *ptr2 = (int *)((char *)param + sizeof(effect_param_t)); 450 ALOGW("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2); 451 *ptr++ = atoi(param->name); 452 *ptr = atoi(param->value); 453 fx_param->psize = sizeof(int); 454 fx_param->vsize = sizeof(int); 455 return fx_param; 456 } 457 } 458 if (param == NULL || value == NULL) { 459 ALOGW("loadEffectParameter() invalid parameter description %s", root->name); 460 goto error; 461 } 462 463 fx_param->psize = 0; 464 param = param->first_child; 465 while (param) { 466 ALOGV("loadEffectParameter() reading param of type %s", param->name); 467 size_t size = readParamValue(param, (char *)fx_param, &curSize, &totSize); 468 if (size == 0) { 469 goto error; 470 } 471 fx_param->psize += size; 472 param = param->next; 473 } 474 475 // align start of value field on 32 bit boundary 476 curSize = ((curSize - 1 ) / sizeof(int) + 1) * sizeof(int); 477 478 fx_param->vsize = 0; 479 value = value->first_child; 480 while (value) { 481 ALOGV("loadEffectParameter() reading value of type %s", value->name); 482 size_t size = readParamValue(value, (char *)fx_param, &curSize, &totSize); 483 if (size == 0) { 484 goto error; 485 } 486 fx_param->vsize += size; 487 value = value->next; 488 } 489 490 return fx_param; 491 492error: 493 delete fx_param; 494 return NULL; 495} 496 497void AudioPolicyEffects::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params) 498{ 499 cnode *node = root->first_child; 500 while (node) { 501 ALOGV("loadEffectParameters() loading param %s", node->name); 502 effect_param_t *param = loadEffectParameter(node); 503 if (param == NULL) { 504 node = node->next; 505 continue; 506 } 507 params.add(param); 508 node = node->next; 509 } 510} 511 512 513AudioPolicyEffects::EffectDescVector *AudioPolicyEffects::loadEffectConfig( 514 cnode *root, 515 const Vector <EffectDesc *>& effects) 516{ 517 cnode *node = root->first_child; 518 if (node == NULL) { 519 ALOGW("loadInputSource() empty element %s", root->name); 520 return NULL; 521 } 522 EffectDescVector *desc = new EffectDescVector(); 523 while (node) { 524 size_t i; 525 for (i = 0; i < effects.size(); i++) { 526 if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) { 527 ALOGV("loadEffectConfig() found effect %s in list", node->name); 528 break; 529 } 530 } 531 if (i == effects.size()) { 532 ALOGV("loadEffectConfig() effect %s not in list", node->name); 533 node = node->next; 534 continue; 535 } 536 EffectDesc *effect = new EffectDesc(*effects[i]); // deep copy 537 loadEffectParameters(node, effect->mParams); 538 ALOGV("loadEffectConfig() adding effect %s uuid %08x", 539 effect->mName, effect->mUuid.timeLow); 540 desc->mEffects.add(effect); 541 node = node->next; 542 } 543 if (desc->mEffects.size() == 0) { 544 ALOGW("loadEffectConfig() no valid effects found in config %s", root->name); 545 delete desc; 546 return NULL; 547 } 548 return desc; 549} 550 551status_t AudioPolicyEffects::loadInputEffectConfigurations(cnode *root, 552 const Vector <EffectDesc *>& effects) 553{ 554 cnode *node = config_find(root, PREPROCESSING_TAG); 555 if (node == NULL) { 556 return -ENOENT; 557 } 558 node = node->first_child; 559 while (node) { 560 audio_source_t source = inputSourceNameToEnum(node->name); 561 if (source == AUDIO_SOURCE_CNT) { 562 ALOGW("loadInputSources() invalid input source %s", node->name); 563 node = node->next; 564 continue; 565 } 566 ALOGV("loadInputSources() loading input source %s", node->name); 567 EffectDescVector *desc = loadEffectConfig(node, effects); 568 if (desc == NULL) { 569 node = node->next; 570 continue; 571 } 572 mInputSources.add(source, desc); 573 node = node->next; 574 } 575 return NO_ERROR; 576} 577 578status_t AudioPolicyEffects::loadStreamEffectConfigurations(cnode *root, 579 const Vector <EffectDesc *>& effects) 580{ 581 cnode *node = config_find(root, OUTPUT_SESSION_PROCESSING_TAG); 582 if (node == NULL) { 583 return -ENOENT; 584 } 585 node = node->first_child; 586 while (node) { 587 audio_stream_type_t stream = streamNameToEnum(node->name); 588 if (stream == AUDIO_STREAM_CNT) { 589 ALOGW("loadStreamEffectConfigurations() invalid output stream %s", node->name); 590 node = node->next; 591 continue; 592 } 593 ALOGV("loadStreamEffectConfigurations() loading output stream %s", node->name); 594 EffectDescVector *desc = loadEffectConfig(node, effects); 595 if (desc == NULL) { 596 node = node->next; 597 continue; 598 } 599 mOutputStreams.add(stream, desc); 600 node = node->next; 601 } 602 return NO_ERROR; 603} 604 605AudioPolicyEffects::EffectDesc *AudioPolicyEffects::loadEffect(cnode *root) 606{ 607 cnode *node = config_find(root, UUID_TAG); 608 if (node == NULL) { 609 return NULL; 610 } 611 effect_uuid_t uuid; 612 if (AudioEffect::stringToGuid(node->value, &uuid) != NO_ERROR) { 613 ALOGW("loadEffect() invalid uuid %s", node->value); 614 return NULL; 615 } 616 return new EffectDesc(root->name, uuid); 617} 618 619status_t AudioPolicyEffects::loadEffects(cnode *root, Vector <EffectDesc *>& effects) 620{ 621 cnode *node = config_find(root, EFFECTS_TAG); 622 if (node == NULL) { 623 return -ENOENT; 624 } 625 node = node->first_child; 626 while (node) { 627 ALOGV("loadEffects() loading effect %s", node->name); 628 EffectDesc *effect = loadEffect(node); 629 if (effect == NULL) { 630 node = node->next; 631 continue; 632 } 633 effects.add(effect); 634 node = node->next; 635 } 636 return NO_ERROR; 637} 638 639status_t AudioPolicyEffects::loadAudioEffectConfig(const char *path) 640{ 641 cnode *root; 642 char *data; 643 644 data = (char *)load_file(path, NULL); 645 if (data == NULL) { 646 return -ENODEV; 647 } 648 root = config_node("", ""); 649 config_load(root, data); 650 651 Vector <EffectDesc *> effects; 652 loadEffects(root, effects); 653 loadInputEffectConfigurations(root, effects); 654 loadStreamEffectConfigurations(root, effects); 655 656 config_free(root); 657 free(root); 658 free(data); 659 660 return NO_ERROR; 661} 662 663 664}; // namespace android 665