EffectDownmix.c revision 32fa3c6fab55b075c916f4dad38e42e239bb7813
1/* 2 * Copyright (C) 2012 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 "EffectDownmix" 18//#define LOG_NDEBUG 0 19#include <log/log.h> 20#include <inttypes.h> 21#include <stdlib.h> 22#include <string.h> 23#include <stdbool.h> 24#include "EffectDownmix.h" 25 26// Do not submit with DOWNMIX_TEST_CHANNEL_INDEX defined, strictly for testing 27//#define DOWNMIX_TEST_CHANNEL_INDEX 0 28// Do not submit with DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER defined, strictly for testing 29//#define DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER 0 30 31#define MINUS_3_DB_IN_Q19_12 2896 // -3dB = 0.707 * 2^12 = 2896 32 33typedef enum { 34 CHANNEL_MASK_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD, 35 // like AUDIO_CHANNEL_OUT_QUAD with *_SIDE_* instead of *_BACK_*, same channel order 36 CHANNEL_MASK_QUAD_SIDE = 37 AUDIO_CHANNEL_OUT_FRONT_LEFT | 38 AUDIO_CHANNEL_OUT_FRONT_RIGHT | 39 AUDIO_CHANNEL_OUT_SIDE_LEFT | 40 AUDIO_CHANNEL_OUT_SIDE_RIGHT, 41 CHANNEL_MASK_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1, 42 // like AUDIO_CHANNEL_OUT_5POINT1 with *_SIDE_* instead of *_BACK_*, same channel order 43 CHANNEL_MASK_5POINT1_SIDE = 44 AUDIO_CHANNEL_OUT_FRONT_LEFT | 45 AUDIO_CHANNEL_OUT_FRONT_RIGHT | 46 AUDIO_CHANNEL_OUT_FRONT_CENTER | 47 AUDIO_CHANNEL_OUT_LOW_FREQUENCY | 48 AUDIO_CHANNEL_OUT_SIDE_LEFT | 49 AUDIO_CHANNEL_OUT_SIDE_RIGHT, 50 CHANNEL_MASK_7POINT1_SIDE_BACK = AUDIO_CHANNEL_OUT_7POINT1, 51} downmix_input_channel_mask_t; 52 53// effect_handle_t interface implementation for downmix effect 54const struct effect_interface_s gDownmixInterface = { 55 Downmix_Process, 56 Downmix_Command, 57 Downmix_GetDescriptor, 58 NULL /* no process_reverse function, no reference stream needed */ 59}; 60 61// This is the only symbol that needs to be exported 62__attribute__ ((visibility ("default"))) 63audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { 64 .tag = AUDIO_EFFECT_LIBRARY_TAG, 65 .version = EFFECT_LIBRARY_API_VERSION, 66 .name = "Downmix Library", 67 .implementor = "The Android Open Source Project", 68 .create_effect = DownmixLib_Create, 69 .release_effect = DownmixLib_Release, 70 .get_descriptor = DownmixLib_GetDescriptor, 71}; 72 73 74// AOSP insert downmix UUID: 93f04452-e4fe-41cc-91f9-e475b6d1d69f 75static const effect_descriptor_t gDownmixDescriptor = { 76 EFFECT_UIID_DOWNMIX__, //type 77 {0x93f04452, 0xe4fe, 0x41cc, 0x91f9, {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}}, // uuid 78 EFFECT_CONTROL_API_VERSION, 79 EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST, 80 0, //FIXME what value should be reported? // cpu load 81 0, //FIXME what value should be reported? // memory usage 82 "Multichannel Downmix To Stereo", // human readable effect name 83 "The Android Open Source Project" // human readable effect implementor name 84}; 85 86// gDescriptors contains pointers to all defined effect descriptor in this library 87static const effect_descriptor_t * const gDescriptors[] = { 88 &gDownmixDescriptor 89}; 90 91// number of effects in this library 92const int kNbEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *); 93 94 95/*---------------------------------------------------------------------------- 96 * Test code 97 *--------------------------------------------------------------------------*/ 98#ifdef DOWNMIX_TEST_CHANNEL_INDEX 99// strictly for testing, logs the indices of the channels for a given mask, 100// uses the same code as Downmix_foldGeneric() 101void Downmix_testIndexComputation(uint32_t mask) { 102 ALOGI("Testing index computation for 0x%" PRIx32 ":", mask); 103 // check against unsupported channels 104 if (mask & kUnsupported) { 105 ALOGE("Unsupported channels (top or front left/right of center)"); 106 return; 107 } 108 // verify has FL/FR 109 if ((mask & AUDIO_CHANNEL_OUT_STEREO) != AUDIO_CHANNEL_OUT_STEREO) { 110 ALOGE("Front channels must be present"); 111 return; 112 } 113 // verify uses SIDE as a pair (ok if not using SIDE at all) 114 bool hasSides = false; 115 if ((mask & kSides) != 0) { 116 if ((mask & kSides) != kSides) { 117 ALOGE("Side channels must be used as a pair"); 118 return; 119 } 120 hasSides = true; 121 } 122 // verify uses BACK as a pair (ok if not using BACK at all) 123 bool hasBacks = false; 124 if ((mask & kBacks) != 0) { 125 if ((mask & kBacks) != kBacks) { 126 ALOGE("Back channels must be used as a pair"); 127 return; 128 } 129 hasBacks = true; 130 } 131 132 const int numChan = popcount(mask); 133 const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER); 134 const bool hasLFE = 135 ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY); 136 const bool hasBC = ((mask & AUDIO_CHANNEL_OUT_BACK_CENTER) == AUDIO_CHANNEL_OUT_BACK_CENTER); 137 // compute at what index each channel is: samples will be in the following order: 138 // FL FR FC LFE BL BR BC SL SR 139 // when a channel is not present, its index is set to the same as the index of the preceding 140 // channel 141 const int indexFC = hasFC ? 2 : 1; // front center 142 const int indexLFE = hasLFE ? indexFC + 1 : indexFC; // low frequency 143 const int indexBL = hasBacks ? indexLFE + 1 : indexLFE; // back left 144 const int indexBR = hasBacks ? indexBL + 1 : indexBL; // back right 145 const int indexBC = hasBC ? indexBR + 1 : indexBR; // back center 146 const int indexSL = hasSides ? indexBC + 1 : indexBC; // side left 147 const int indexSR = hasSides ? indexSL + 1 : indexSL; // side right 148 149 ALOGI(" FL FR FC LFE BL BR BC SL SR"); 150 ALOGI(" %d %d %d %d %d %d %d %d %d", 151 0, 1, indexFC, indexLFE, indexBL, indexBR, indexBC, indexSL, indexSR); 152} 153#endif 154 155 156/*---------------------------------------------------------------------------- 157 * Effect API implementation 158 *--------------------------------------------------------------------------*/ 159 160/*--- Effect Library Interface Implementation ---*/ 161 162int32_t DownmixLib_Create(const effect_uuid_t *uuid, 163 int32_t sessionId, 164 int32_t ioId, 165 effect_handle_t *pHandle) { 166 int ret; 167 int i; 168 downmix_module_t *module; 169 const effect_descriptor_t *desc; 170 171 ALOGV("DownmixLib_Create()"); 172 173#ifdef DOWNMIX_TEST_CHANNEL_INDEX 174 // should work (won't log an error) 175 ALOGI("DOWNMIX_TEST_CHANNEL_INDEX: should work:"); 176 Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT | 177 AUDIO_CHANNEL_OUT_LOW_FREQUENCY | AUDIO_CHANNEL_OUT_BACK_CENTER); 178 Downmix_testIndexComputation(CHANNEL_MASK_QUAD_SIDE | CHANNEL_MASK_QUAD_BACK); 179 Downmix_testIndexComputation(CHANNEL_MASK_5POINT1_SIDE | AUDIO_CHANNEL_OUT_BACK_CENTER); 180 Downmix_testIndexComputation(CHANNEL_MASK_5POINT1_BACK | AUDIO_CHANNEL_OUT_BACK_CENTER); 181 // shouldn't work (will log an error, won't display channel indices) 182 ALOGI("DOWNMIX_TEST_CHANNEL_INDEX: should NOT work:"); 183 Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT | 184 AUDIO_CHANNEL_OUT_LOW_FREQUENCY | AUDIO_CHANNEL_OUT_BACK_LEFT); 185 Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT | 186 AUDIO_CHANNEL_OUT_LOW_FREQUENCY | AUDIO_CHANNEL_OUT_SIDE_LEFT); 187 Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | 188 AUDIO_CHANNEL_OUT_BACK_LEFT | AUDIO_CHANNEL_OUT_BACK_RIGHT); 189 Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | 190 AUDIO_CHANNEL_OUT_SIDE_LEFT | AUDIO_CHANNEL_OUT_SIDE_RIGHT); 191#endif 192 193 if (pHandle == NULL || uuid == NULL) { 194 return -EINVAL; 195 } 196 197 for (i = 0 ; i < kNbEffects ; i++) { 198 desc = gDescriptors[i]; 199 if (memcmp(uuid, &desc->uuid, sizeof(effect_uuid_t)) == 0) { 200 break; 201 } 202 } 203 204 if (i == kNbEffects) { 205 return -ENOENT; 206 } 207 208 module = malloc(sizeof(downmix_module_t)); 209 210 module->itfe = &gDownmixInterface; 211 212 module->context.state = DOWNMIX_STATE_UNINITIALIZED; 213 214 ret = Downmix_Init(module); 215 if (ret < 0) { 216 ALOGW("DownmixLib_Create() init failed"); 217 free(module); 218 return ret; 219 } 220 221 *pHandle = (effect_handle_t) module; 222 223 ALOGV("DownmixLib_Create() %p , size %zu", module, sizeof(downmix_module_t)); 224 225 return 0; 226} 227 228 229int32_t DownmixLib_Release(effect_handle_t handle) { 230 downmix_module_t *pDwmModule = (downmix_module_t *)handle; 231 232 ALOGV("DownmixLib_Release() %p", handle); 233 if (handle == NULL) { 234 return -EINVAL; 235 } 236 237 pDwmModule->context.state = DOWNMIX_STATE_UNINITIALIZED; 238 239 free(pDwmModule); 240 return 0; 241} 242 243 244int32_t DownmixLib_GetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) { 245 ALOGV("DownmixLib_GetDescriptor()"); 246 int i; 247 248 if (pDescriptor == NULL || uuid == NULL){ 249 ALOGE("DownmixLib_Create() called with NULL pointer"); 250 return -EINVAL; 251 } 252 ALOGV("DownmixLib_GetDescriptor() nb effects=%d", kNbEffects); 253 for (i = 0; i < kNbEffects; i++) { 254 ALOGV("DownmixLib_GetDescriptor() i=%d", i); 255 if (memcmp(uuid, &gDescriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) { 256 memcpy(pDescriptor, gDescriptors[i], sizeof(effect_descriptor_t)); 257 ALOGV("EffectGetDescriptor - UUID matched downmix type %d, UUID = %" PRIx32, 258 i, gDescriptors[i]->uuid.timeLow); 259 return 0; 260 } 261 } 262 263 return -EINVAL; 264} 265 266 267/*--- Effect Control Interface Implementation ---*/ 268 269static int Downmix_Process(effect_handle_t self, 270 audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) { 271 272 downmix_object_t *pDownmixer; 273 int16_t *pSrc, *pDst; 274 downmix_module_t *pDwmModule = (downmix_module_t *)self; 275 276 if (pDwmModule == NULL) { 277 return -EINVAL; 278 } 279 280 if (inBuffer == NULL || inBuffer->raw == NULL || 281 outBuffer == NULL || outBuffer->raw == NULL || 282 inBuffer->frameCount != outBuffer->frameCount) { 283 return -EINVAL; 284 } 285 286 pDownmixer = (downmix_object_t*) &pDwmModule->context; 287 288 if (pDownmixer->state == DOWNMIX_STATE_UNINITIALIZED) { 289 ALOGE("Downmix_Process error: trying to use an uninitialized downmixer"); 290 return -EINVAL; 291 } else if (pDownmixer->state == DOWNMIX_STATE_INITIALIZED) { 292 ALOGE("Downmix_Process error: trying to use a non-configured downmixer"); 293 return -ENODATA; 294 } 295 296 pSrc = inBuffer->s16; 297 pDst = outBuffer->s16; 298 size_t numFrames = outBuffer->frameCount; 299 300 const bool accumulate = 301 (pDwmModule->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE); 302 const uint32_t downmixInputChannelMask = pDwmModule->config.inputCfg.channels; 303 304 switch(pDownmixer->type) { 305 306 case DOWNMIX_TYPE_STRIP: 307 if (accumulate) { 308 while (numFrames) { 309 pDst[0] = clamp16(pDst[0] + pSrc[0]); 310 pDst[1] = clamp16(pDst[1] + pSrc[1]); 311 pSrc += pDownmixer->input_channel_count; 312 pDst += 2; 313 numFrames--; 314 } 315 } else { 316 while (numFrames) { 317 pDst[0] = pSrc[0]; 318 pDst[1] = pSrc[1]; 319 pSrc += pDownmixer->input_channel_count; 320 pDst += 2; 321 numFrames--; 322 } 323 } 324 break; 325 326 case DOWNMIX_TYPE_FOLD: 327#ifdef DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER 328 // bypass the optimized downmix routines for the common formats 329 if (!Downmix_foldGeneric( 330 downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) { 331 ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported", downmixInputChannelMask); 332 return -EINVAL; 333 } 334 break; 335#endif 336 // optimize for the common formats 337 switch((downmix_input_channel_mask_t)downmixInputChannelMask) { 338 case CHANNEL_MASK_QUAD_BACK: 339 case CHANNEL_MASK_QUAD_SIDE: 340 Downmix_foldFromQuad(pSrc, pDst, numFrames, accumulate); 341 break; 342 case CHANNEL_MASK_5POINT1_BACK: 343 case CHANNEL_MASK_5POINT1_SIDE: 344 Downmix_foldFrom5Point1(pSrc, pDst, numFrames, accumulate); 345 break; 346 case CHANNEL_MASK_7POINT1_SIDE_BACK: 347 Downmix_foldFrom7Point1(pSrc, pDst, numFrames, accumulate); 348 break; 349 default: 350 if (!Downmix_foldGeneric( 351 downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) { 352 ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported", downmixInputChannelMask); 353 return -EINVAL; 354 } 355 break; 356 } 357 break; 358 359 default: 360 return -EINVAL; 361 } 362 363 return 0; 364} 365 366 367static int Downmix_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, 368 void *pCmdData, uint32_t *replySize, void *pReplyData) { 369 370 downmix_module_t *pDwmModule = (downmix_module_t *) self; 371 downmix_object_t *pDownmixer; 372 int retsize; 373 374 if (pDwmModule == NULL || pDwmModule->context.state == DOWNMIX_STATE_UNINITIALIZED) { 375 return -EINVAL; 376 } 377 378 pDownmixer = (downmix_object_t*) &pDwmModule->context; 379 380 ALOGV("Downmix_Command command %" PRIu32 " cmdSize %" PRIu32, cmdCode, cmdSize); 381 382 switch (cmdCode) { 383 case EFFECT_CMD_INIT: 384 if (pReplyData == NULL || *replySize != sizeof(int)) { 385 return -EINVAL; 386 } 387 *(int *) pReplyData = Downmix_Init(pDwmModule); 388 break; 389 390 case EFFECT_CMD_SET_CONFIG: 391 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) 392 || pReplyData == NULL || *replySize != sizeof(int)) { 393 return -EINVAL; 394 } 395 *(int *) pReplyData = Downmix_Configure(pDwmModule, 396 (effect_config_t *)pCmdData, false); 397 break; 398 399 case EFFECT_CMD_RESET: 400 Downmix_Reset(pDownmixer, false); 401 break; 402 403 case EFFECT_CMD_GET_PARAM: 404 ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM pCmdData %p, *replySize %" PRIu32 ", pReplyData: %p", 405 pCmdData, *replySize, pReplyData); 406 if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) || 407 pReplyData == NULL || 408 *replySize < (int) sizeof(effect_param_t) + 2 * sizeof(int32_t)) { 409 return -EINVAL; 410 } 411 effect_param_t *rep = (effect_param_t *) pReplyData; 412 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(int32_t)); 413 ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM param %" PRId32 ", replySize %" PRIu32, 414 *(int32_t *)rep->data, rep->vsize); 415 rep->status = Downmix_getParameter(pDownmixer, *(int32_t *)rep->data, &rep->vsize, 416 rep->data + sizeof(int32_t)); 417 *replySize = sizeof(effect_param_t) + sizeof(int32_t) + rep->vsize; 418 break; 419 420 case EFFECT_CMD_SET_PARAM: 421 ALOGV("Downmix_Command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %" PRIu32 422 ", pReplyData %p", cmdSize, pCmdData, *replySize, pReplyData); 423 if (pCmdData == NULL || (cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t))) 424 || pReplyData == NULL || *replySize != (int)sizeof(int32_t)) { 425 return -EINVAL; 426 } 427 effect_param_t *cmd = (effect_param_t *) pCmdData; 428 *(int *)pReplyData = Downmix_setParameter(pDownmixer, *(int32_t *)cmd->data, 429 cmd->vsize, cmd->data + sizeof(int32_t)); 430 break; 431 432 case EFFECT_CMD_SET_PARAM_DEFERRED: 433 //FIXME implement 434 ALOGW("Downmix_Command command EFFECT_CMD_SET_PARAM_DEFERRED not supported, FIXME"); 435 break; 436 437 case EFFECT_CMD_SET_PARAM_COMMIT: 438 //FIXME implement 439 ALOGW("Downmix_Command command EFFECT_CMD_SET_PARAM_COMMIT not supported, FIXME"); 440 break; 441 442 case EFFECT_CMD_ENABLE: 443 if (pReplyData == NULL || *replySize != sizeof(int)) { 444 return -EINVAL; 445 } 446 if (pDownmixer->state != DOWNMIX_STATE_INITIALIZED) { 447 return -ENOSYS; 448 } 449 pDownmixer->state = DOWNMIX_STATE_ACTIVE; 450 ALOGV("EFFECT_CMD_ENABLE() OK"); 451 *(int *)pReplyData = 0; 452 break; 453 454 case EFFECT_CMD_DISABLE: 455 if (pReplyData == NULL || *replySize != sizeof(int)) { 456 return -EINVAL; 457 } 458 if (pDownmixer->state != DOWNMIX_STATE_ACTIVE) { 459 return -ENOSYS; 460 } 461 pDownmixer->state = DOWNMIX_STATE_INITIALIZED; 462 ALOGV("EFFECT_CMD_DISABLE() OK"); 463 *(int *)pReplyData = 0; 464 break; 465 466 case EFFECT_CMD_SET_DEVICE: 467 if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) { 468 return -EINVAL; 469 } 470 // FIXME change type if playing on headset vs speaker 471 ALOGV("Downmix_Command EFFECT_CMD_SET_DEVICE: 0x%08" PRIx32, *(uint32_t *)pCmdData); 472 break; 473 474 case EFFECT_CMD_SET_VOLUME: { 475 // audio output is always stereo => 2 channel volumes 476 if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t) * 2) { 477 return -EINVAL; 478 } 479 // FIXME change volume 480 ALOGW("Downmix_Command command EFFECT_CMD_SET_VOLUME not supported, FIXME"); 481 float left = (float)(*(uint32_t *)pCmdData) / (1 << 24); 482 float right = (float)(*((uint32_t *)pCmdData + 1)) / (1 << 24); 483 ALOGV("Downmix_Command EFFECT_CMD_SET_VOLUME: left %f, right %f ", left, right); 484 break; 485 } 486 487 case EFFECT_CMD_SET_AUDIO_MODE: 488 if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) { 489 return -EINVAL; 490 } 491 ALOGV("Downmix_Command EFFECT_CMD_SET_AUDIO_MODE: %" PRIu32, *(uint32_t *)pCmdData); 492 break; 493 494 case EFFECT_CMD_SET_CONFIG_REVERSE: 495 case EFFECT_CMD_SET_INPUT_DEVICE: 496 // these commands are ignored by a downmix effect 497 break; 498 499 default: 500 ALOGW("Downmix_Command invalid command %" PRIu32, cmdCode); 501 return -EINVAL; 502 } 503 504 return 0; 505} 506 507 508int Downmix_GetDescriptor(effect_handle_t self, effect_descriptor_t *pDescriptor) 509{ 510 downmix_module_t *pDwnmxModule = (downmix_module_t *) self; 511 512 if (pDwnmxModule == NULL || 513 pDwnmxModule->context.state == DOWNMIX_STATE_UNINITIALIZED) { 514 return -EINVAL; 515 } 516 517 memcpy(pDescriptor, &gDownmixDescriptor, sizeof(effect_descriptor_t)); 518 519 return 0; 520} 521 522 523/*---------------------------------------------------------------------------- 524 * Downmix internal functions 525 *--------------------------------------------------------------------------*/ 526 527/*---------------------------------------------------------------------------- 528 * Downmix_Init() 529 *---------------------------------------------------------------------------- 530 * Purpose: 531 * Initialize downmix context and apply default parameters 532 * 533 * Inputs: 534 * pDwmModule pointer to downmix effect module 535 * 536 * Outputs: 537 * 538 * Returns: 539 * 0 indicates success 540 * 541 * Side Effects: 542 * updates: 543 * pDwmModule->context.type 544 * pDwmModule->context.apply_volume_correction 545 * pDwmModule->config.inputCfg 546 * pDwmModule->config.outputCfg 547 * pDwmModule->config.inputCfg.samplingRate 548 * pDwmModule->config.outputCfg.samplingRate 549 * pDwmModule->context.state 550 * doesn't set: 551 * pDwmModule->itfe 552 * 553 *---------------------------------------------------------------------------- 554 */ 555 556int Downmix_Init(downmix_module_t *pDwmModule) { 557 558 ALOGV("Downmix_Init module %p", pDwmModule); 559 int ret = 0; 560 561 memset(&pDwmModule->context, 0, sizeof(downmix_object_t)); 562 563 pDwmModule->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; 564 pDwmModule->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; 565 pDwmModule->config.inputCfg.channels = AUDIO_CHANNEL_OUT_7POINT1; 566 pDwmModule->config.inputCfg.bufferProvider.getBuffer = NULL; 567 pDwmModule->config.inputCfg.bufferProvider.releaseBuffer = NULL; 568 pDwmModule->config.inputCfg.bufferProvider.cookie = NULL; 569 pDwmModule->config.inputCfg.mask = EFFECT_CONFIG_ALL; 570 571 pDwmModule->config.inputCfg.samplingRate = 44100; 572 pDwmModule->config.outputCfg.samplingRate = pDwmModule->config.inputCfg.samplingRate; 573 574 // set a default value for the access mode, but should be overwritten by caller 575 pDwmModule->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; 576 pDwmModule->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; 577 pDwmModule->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; 578 pDwmModule->config.outputCfg.bufferProvider.getBuffer = NULL; 579 pDwmModule->config.outputCfg.bufferProvider.releaseBuffer = NULL; 580 pDwmModule->config.outputCfg.bufferProvider.cookie = NULL; 581 pDwmModule->config.outputCfg.mask = EFFECT_CONFIG_ALL; 582 583 ret = Downmix_Configure(pDwmModule, &pDwmModule->config, true); 584 if (ret != 0) { 585 ALOGV("Downmix_Init error %d on module %p", ret, pDwmModule); 586 } else { 587 pDwmModule->context.state = DOWNMIX_STATE_INITIALIZED; 588 } 589 590 return ret; 591} 592 593 594/*---------------------------------------------------------------------------- 595 * Downmix_Configure() 596 *---------------------------------------------------------------------------- 597 * Purpose: 598 * Set input and output audio configuration. 599 * 600 * Inputs: 601 * pDwmModule pointer to downmix effect module 602 * pConfig pointer to effect_config_t structure containing input 603 * and output audio parameters configuration 604 * init true if called from init function 605 * 606 * Outputs: 607 * 608 * Returns: 609 * 0 indicates success 610 * 611 * Side Effects: 612 * 613 *---------------------------------------------------------------------------- 614 */ 615 616int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bool init) { 617 618 downmix_object_t *pDownmixer = &pDwmModule->context; 619 620 // Check configuration compatibility with build options, and effect capabilities 621 if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate 622 || pConfig->outputCfg.channels != DOWNMIX_OUTPUT_CHANNELS 623 || pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT 624 || pConfig->outputCfg.format != AUDIO_FORMAT_PCM_16_BIT) { 625 ALOGE("Downmix_Configure error: invalid config"); 626 return -EINVAL; 627 } 628 629 if (&pDwmModule->config != pConfig) { 630 memcpy(&pDwmModule->config, pConfig, sizeof(effect_config_t)); 631 } 632 633 if (init) { 634 pDownmixer->type = DOWNMIX_TYPE_FOLD; 635 pDownmixer->apply_volume_correction = false; 636 pDownmixer->input_channel_count = 8; // matches default input of AUDIO_CHANNEL_OUT_7POINT1 637 } else { 638 // when configuring the effect, do not allow a blank channel mask 639 if (pConfig->inputCfg.channels == 0) { 640 ALOGE("Downmix_Configure error: input channel mask can't be 0"); 641 return -EINVAL; 642 } 643 pDownmixer->input_channel_count = popcount(pConfig->inputCfg.channels); 644 } 645 646 Downmix_Reset(pDownmixer, init); 647 648 return 0; 649} 650 651 652/*---------------------------------------------------------------------------- 653 * Downmix_Reset() 654 *---------------------------------------------------------------------------- 655 * Purpose: 656 * Reset internal states. 657 * 658 * Inputs: 659 * pDownmixer pointer to downmix context 660 * init true if called from init function 661 * 662 * Outputs: 663* 664 * Returns: 665 * 0 indicates success 666 * 667 * Side Effects: 668 * 669 *---------------------------------------------------------------------------- 670 */ 671 672int Downmix_Reset(downmix_object_t *pDownmixer, bool init) { 673 // nothing to do here 674 return 0; 675} 676 677 678/*---------------------------------------------------------------------------- 679 * Downmix_setParameter() 680 *---------------------------------------------------------------------------- 681 * Purpose: 682 * Set a Downmix parameter 683 * 684 * Inputs: 685 * pDownmixer handle to instance data 686 * param parameter 687 * pValue pointer to parameter value 688 * size value size 689 * 690 * Outputs: 691 * 692 * Returns: 693 * 0 indicates success 694 * 695 * Side Effects: 696 * 697 *---------------------------------------------------------------------------- 698 */ 699int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue) { 700 701 int16_t value16; 702 ALOGV("Downmix_setParameter, context %p, param %" PRId32 ", value16 %" PRId16 ", value32 %" PRId32, 703 pDownmixer, param, *(int16_t *)pValue, *(int32_t *)pValue); 704 705 switch (param) { 706 707 case DOWNMIX_PARAM_TYPE: 708 if (size != sizeof(downmix_type_t)) { 709 ALOGE("Downmix_setParameter(DOWNMIX_PARAM_TYPE) invalid size %" PRIu32 ", should be %zu", 710 size, sizeof(downmix_type_t)); 711 return -EINVAL; 712 } 713 value16 = *(int16_t *)pValue; 714 ALOGV("set DOWNMIX_PARAM_TYPE, type %" PRId16, value16); 715 if (!((value16 > DOWNMIX_TYPE_INVALID) && (value16 <= DOWNMIX_TYPE_LAST))) { 716 ALOGE("Downmix_setParameter invalid DOWNMIX_PARAM_TYPE value %" PRId16, value16); 717 return -EINVAL; 718 } else { 719 pDownmixer->type = (downmix_type_t) value16; 720 break; 721 722 default: 723 ALOGE("Downmix_setParameter unknown parameter %" PRId32, param); 724 return -EINVAL; 725 } 726} 727 728 return 0; 729} /* end Downmix_setParameter */ 730 731 732/*---------------------------------------------------------------------------- 733 * Downmix_getParameter() 734 *---------------------------------------------------------------------------- 735 * Purpose: 736 * Get a Downmix parameter 737 * 738 * Inputs: 739 * pDownmixer handle to instance data 740 * param parameter 741 * pValue pointer to variable to hold retrieved value 742 * pSize pointer to value size: maximum size as input 743 * 744 * Outputs: 745 * *pValue updated with parameter value 746 * *pSize updated with actual value size 747 * 748 * Returns: 749 * 0 indicates success 750 * 751 * Side Effects: 752 * 753 *---------------------------------------------------------------------------- 754 */ 755int Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t *pSize, void *pValue) { 756 int16_t *pValue16; 757 758 switch (param) { 759 760 case DOWNMIX_PARAM_TYPE: 761 if (*pSize < sizeof(int16_t)) { 762 ALOGE("Downmix_getParameter invalid parameter size %" PRIu32 " for DOWNMIX_PARAM_TYPE", *pSize); 763 return -EINVAL; 764 } 765 pValue16 = (int16_t *)pValue; 766 *pValue16 = (int16_t) pDownmixer->type; 767 *pSize = sizeof(int16_t); 768 ALOGV("Downmix_getParameter DOWNMIX_PARAM_TYPE is %" PRId16, *pValue16); 769 break; 770 771 default: 772 ALOGE("Downmix_getParameter unknown parameter %" PRId16, param); 773 return -EINVAL; 774 } 775 776 return 0; 777} /* end Downmix_getParameter */ 778 779 780/*---------------------------------------------------------------------------- 781 * Downmix_foldFromQuad() 782 *---------------------------------------------------------------------------- 783 * Purpose: 784 * downmix a quad signal to stereo 785 * 786 * Inputs: 787 * pSrc quad audio samples to downmix 788 * numFrames the number of quad frames to downmix 789 * accumulate whether to mix (when true) the result of the downmix with the contents of pDst, 790 * or overwrite pDst (when false) 791 * 792 * Outputs: 793 * pDst downmixed stereo audio samples 794 * 795 *---------------------------------------------------------------------------- 796 */ 797void Downmix_foldFromQuad(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) { 798 // sample at index 0 is FL 799 // sample at index 1 is FR 800 // sample at index 2 is RL 801 // sample at index 3 is RR 802 if (accumulate) { 803 while (numFrames) { 804 // FL + RL 805 pDst[0] = clamp16(pDst[0] + ((pSrc[0] + pSrc[2]) >> 1)); 806 // FR + RR 807 pDst[1] = clamp16(pDst[1] + ((pSrc[1] + pSrc[3]) >> 1)); 808 pSrc += 4; 809 pDst += 2; 810 numFrames--; 811 } 812 } else { // same code as above but without adding and clamping pDst[i] to itself 813 while (numFrames) { 814 // FL + RL 815 pDst[0] = clamp16((pSrc[0] + pSrc[2]) >> 1); 816 // FR + RR 817 pDst[1] = clamp16((pSrc[1] + pSrc[3]) >> 1); 818 pSrc += 4; 819 pDst += 2; 820 numFrames--; 821 } 822 } 823} 824 825 826/*---------------------------------------------------------------------------- 827 * Downmix_foldFrom5Point1() 828 *---------------------------------------------------------------------------- 829 * Purpose: 830 * downmix a 5.1 signal to stereo 831 * 832 * Inputs: 833 * pSrc 5.1 audio samples to downmix 834 * numFrames the number of 5.1 frames to downmix 835 * accumulate whether to mix (when true) the result of the downmix with the contents of pDst, 836 * or overwrite pDst (when false) 837 * 838 * Outputs: 839 * pDst downmixed stereo audio samples 840 * 841 *---------------------------------------------------------------------------- 842 */ 843void Downmix_foldFrom5Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) { 844 int32_t lt, rt, centerPlusLfeContrib; // samples in Q19.12 format 845 // sample at index 0 is FL 846 // sample at index 1 is FR 847 // sample at index 2 is FC 848 // sample at index 3 is LFE 849 // sample at index 4 is RL 850 // sample at index 5 is RR 851 // code is mostly duplicated between the two values of accumulate to avoid repeating the test 852 // for every sample 853 if (accumulate) { 854 while (numFrames) { 855 // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB) 856 centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12) 857 + (pSrc[3] * MINUS_3_DB_IN_Q19_12); 858 // FL + centerPlusLfeContrib + RL 859 lt = (pSrc[0] << 12) + centerPlusLfeContrib + (pSrc[4] << 12); 860 // FR + centerPlusLfeContrib + RR 861 rt = (pSrc[1] << 12) + centerPlusLfeContrib + (pSrc[5] << 12); 862 // accumulate in destination 863 pDst[0] = clamp16(pDst[0] + (lt >> 13)); 864 pDst[1] = clamp16(pDst[1] + (rt >> 13)); 865 pSrc += 6; 866 pDst += 2; 867 numFrames--; 868 } 869 } else { // same code as above but without adding and clamping pDst[i] to itself 870 while (numFrames) { 871 // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB) 872 centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12) 873 + (pSrc[3] * MINUS_3_DB_IN_Q19_12); 874 // FL + centerPlusLfeContrib + RL 875 lt = (pSrc[0] << 12) + centerPlusLfeContrib + (pSrc[4] << 12); 876 // FR + centerPlusLfeContrib + RR 877 rt = (pSrc[1] << 12) + centerPlusLfeContrib + (pSrc[5] << 12); 878 // store in destination 879 pDst[0] = clamp16(lt >> 13); // differs from when accumulate is true above 880 pDst[1] = clamp16(rt >> 13); // differs from when accumulate is true above 881 pSrc += 6; 882 pDst += 2; 883 numFrames--; 884 } 885 } 886} 887 888 889/*---------------------------------------------------------------------------- 890 * Downmix_foldFrom7Point1() 891 *---------------------------------------------------------------------------- 892 * Purpose: 893 * downmix a 7.1 signal to stereo 894 * 895 * Inputs: 896 * pSrc 7.1 audio samples to downmix 897 * numFrames the number of 7.1 frames to downmix 898 * accumulate whether to mix (when true) the result of the downmix with the contents of pDst, 899 * or overwrite pDst (when false) 900 * 901 * Outputs: 902 * pDst downmixed stereo audio samples 903 * 904 *---------------------------------------------------------------------------- 905 */ 906void Downmix_foldFrom7Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) { 907 int32_t lt, rt, centerPlusLfeContrib; // samples in Q19.12 format 908 // sample at index 0 is FL 909 // sample at index 1 is FR 910 // sample at index 2 is FC 911 // sample at index 3 is LFE 912 // sample at index 4 is RL 913 // sample at index 5 is RR 914 // sample at index 6 is SL 915 // sample at index 7 is SR 916 // code is mostly duplicated between the two values of accumulate to avoid repeating the test 917 // for every sample 918 if (accumulate) { 919 while (numFrames) { 920 // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB) 921 centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12) 922 + (pSrc[3] * MINUS_3_DB_IN_Q19_12); 923 // FL + centerPlusLfeContrib + SL + RL 924 lt = (pSrc[0] << 12) + centerPlusLfeContrib + (pSrc[6] << 12) + (pSrc[4] << 12); 925 // FR + centerPlusLfeContrib + SR + RR 926 rt = (pSrc[1] << 12) + centerPlusLfeContrib + (pSrc[7] << 12) + (pSrc[5] << 12); 927 //accumulate in destination 928 pDst[0] = clamp16(pDst[0] + (lt >> 13)); 929 pDst[1] = clamp16(pDst[1] + (rt >> 13)); 930 pSrc += 8; 931 pDst += 2; 932 numFrames--; 933 } 934 } else { // same code as above but without adding and clamping pDst[i] to itself 935 while (numFrames) { 936 // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB) 937 centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12) 938 + (pSrc[3] * MINUS_3_DB_IN_Q19_12); 939 // FL + centerPlusLfeContrib + SL + RL 940 lt = (pSrc[0] << 12) + centerPlusLfeContrib + (pSrc[6] << 12) + (pSrc[4] << 12); 941 // FR + centerPlusLfeContrib + SR + RR 942 rt = (pSrc[1] << 12) + centerPlusLfeContrib + (pSrc[7] << 12) + (pSrc[5] << 12); 943 // store in destination 944 pDst[0] = clamp16(lt >> 13); // differs from when accumulate is true above 945 pDst[1] = clamp16(rt >> 13); // differs from when accumulate is true above 946 pSrc += 8; 947 pDst += 2; 948 numFrames--; 949 } 950 } 951} 952 953 954/*---------------------------------------------------------------------------- 955 * Downmix_foldGeneric() 956 *---------------------------------------------------------------------------- 957 * Purpose: 958 * downmix to stereo a multichannel signal whose format is: 959 * - has FL/FR 960 * - if using AUDIO_CHANNEL_OUT_SIDE*, it contains both left and right 961 * - if using AUDIO_CHANNEL_OUT_BACK*, it contains both left and right 962 * - doesn't use any of the AUDIO_CHANNEL_OUT_TOP* channels 963 * - doesn't use any of the AUDIO_CHANNEL_OUT_FRONT_*_OF_CENTER channels 964 * Only handles channel masks not enumerated in downmix_input_channel_mask_t 965 * 966 * Inputs: 967 * mask the channel mask of pSrc 968 * pSrc multichannel audio buffer to downmix 969 * numFrames the number of multichannel frames to downmix 970 * accumulate whether to mix (when true) the result of the downmix with the contents of pDst, 971 * or overwrite pDst (when false) 972 * 973 * Outputs: 974 * pDst downmixed stereo audio samples 975 * 976 * Returns: false if multichannel format is not supported 977 * 978 *---------------------------------------------------------------------------- 979 */ 980bool Downmix_foldGeneric( 981 uint32_t mask, int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) { 982 // check against unsupported channels 983 if (mask & kUnsupported) { 984 ALOGE("Unsupported channels (top or front left/right of center)"); 985 return false; 986 } 987 // verify has FL/FR 988 if ((mask & AUDIO_CHANNEL_OUT_STEREO) != AUDIO_CHANNEL_OUT_STEREO) { 989 ALOGE("Front channels must be present"); 990 return false; 991 } 992 // verify uses SIDE as a pair (ok if not using SIDE at all) 993 bool hasSides = false; 994 if ((mask & kSides) != 0) { 995 if ((mask & kSides) != kSides) { 996 ALOGE("Side channels must be used as a pair"); 997 return false; 998 } 999 hasSides = true; 1000 } 1001 // verify uses BACK as a pair (ok if not using BACK at all) 1002 bool hasBacks = false; 1003 if ((mask & kBacks) != 0) { 1004 if ((mask & kBacks) != kBacks) { 1005 ALOGE("Back channels must be used as a pair"); 1006 return false; 1007 } 1008 hasBacks = true; 1009 } 1010 1011 const int numChan = popcount(mask); 1012 const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER); 1013 const bool hasLFE = 1014 ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY); 1015 const bool hasBC = ((mask & AUDIO_CHANNEL_OUT_BACK_CENTER) == AUDIO_CHANNEL_OUT_BACK_CENTER); 1016 // compute at what index each channel is: samples will be in the following order: 1017 // FL FR FC LFE BL BR BC SL SR 1018 // when a channel is not present, its index is set to the same as the index of the preceding 1019 // channel 1020 const int indexFC = hasFC ? 2 : 1; // front center 1021 const int indexLFE = hasLFE ? indexFC + 1 : indexFC; // low frequency 1022 const int indexBL = hasBacks ? indexLFE + 1 : indexLFE; // back left 1023 const int indexBR = hasBacks ? indexBL + 1 : indexBL; // back right 1024 const int indexBC = hasBC ? indexBR + 1 : indexBR; // back center 1025 const int indexSL = hasSides ? indexBC + 1 : indexBC; // side left 1026 const int indexSR = hasSides ? indexSL + 1 : indexSL; // side right 1027 1028 int32_t lt, rt, centersLfeContrib; // samples in Q19.12 format 1029 // code is mostly duplicated between the two values of accumulate to avoid repeating the test 1030 // for every sample 1031 if (accumulate) { 1032 while (numFrames) { 1033 // compute contribution of FC, BC and LFE 1034 centersLfeContrib = 0; 1035 if (hasFC) { centersLfeContrib += pSrc[indexFC]; } 1036 if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; } 1037 if (hasBC) { centersLfeContrib += pSrc[indexBC]; } 1038 centersLfeContrib *= MINUS_3_DB_IN_Q19_12; 1039 // always has FL/FR 1040 lt = (pSrc[0] << 12); 1041 rt = (pSrc[1] << 12); 1042 // mix in sides and backs 1043 if (hasSides) { 1044 lt += pSrc[indexSL] << 12; 1045 rt += pSrc[indexSR] << 12; 1046 } 1047 if (hasBacks) { 1048 lt += pSrc[indexBL] << 12; 1049 rt += pSrc[indexBR] << 12; 1050 } 1051 lt += centersLfeContrib; 1052 rt += centersLfeContrib; 1053 // accumulate in destination 1054 pDst[0] = clamp16(pDst[0] + (lt >> 13)); 1055 pDst[1] = clamp16(pDst[1] + (rt >> 13)); 1056 pSrc += numChan; 1057 pDst += 2; 1058 numFrames--; 1059 } 1060 } else { 1061 while (numFrames) { 1062 // compute contribution of FC, BC and LFE 1063 centersLfeContrib = 0; 1064 if (hasFC) { centersLfeContrib += pSrc[indexFC]; } 1065 if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; } 1066 if (hasBC) { centersLfeContrib += pSrc[indexBC]; } 1067 centersLfeContrib *= MINUS_3_DB_IN_Q19_12; 1068 // always has FL/FR 1069 lt = (pSrc[0] << 12); 1070 rt = (pSrc[1] << 12); 1071 // mix in sides and backs 1072 if (hasSides) { 1073 lt += pSrc[indexSL] << 12; 1074 rt += pSrc[indexSR] << 12; 1075 } 1076 if (hasBacks) { 1077 lt += pSrc[indexBL] << 12; 1078 rt += pSrc[indexBR] << 12; 1079 } 1080 lt += centersLfeContrib; 1081 rt += centersLfeContrib; 1082 // store in destination 1083 pDst[0] = clamp16(lt >> 13); // differs from when accumulate is true above 1084 pDst[1] = clamp16(rt >> 13); // differs from when accumulate is true above 1085 pSrc += numChan; 1086 pDst += 2; 1087 numFrames--; 1088 } 1089 } 1090 return true; 1091} 1092