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