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