1/* 2 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. 3 * Not a Contribution. 4 * 5 * Copyright (C) 2013 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20#define LOG_TAG "offload_effect_equalizer" 21#define LOG_NDEBUG 0 22 23#include <cutils/list.h> 24#include <cutils/log.h> 25#include <tinyalsa/asoundlib.h> 26#include <sound/audio_effects.h> 27#include <audio_effects/effect_equalizer.h> 28 29#include "effect_api.h" 30#include "equalizer.h" 31 32/* Offload equalizer UUID: a0dac280-401c-11e3-9379-0002a5d5c51b */ 33const effect_descriptor_t equalizer_descriptor = { 34 {0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type 35 {0xa0dac280, 0x401c, 0x11e3, 0x9379, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid 36 EFFECT_CONTROL_API_VERSION, 37 (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_HW_ACC_TUNNEL), 38 0, /* TODO */ 39 1, 40 "MSM offload equalizer", 41 "The Android Open Source Project", 42}; 43 44static const char *equalizer_preset_names[] = { 45 "Normal", 46 "Classical", 47 "Dance", 48 "Flat", 49 "Folk", 50 "Heavy Metal", 51 "Hip Hop", 52 "Jazz", 53 "Pop", 54 "Rock" 55}; 56 57static const uint32_t equalizer_band_freq_range[NUM_EQ_BANDS][2] = { 58 {30000, 120000}, 59 {120001, 460000}, 60 {460001, 1800000}, 61 {1800001, 7000000}, 62 {7000001, 20000000}}; 63 64static const int16_t equalizer_band_presets_level[] = { 65 3, 0, 0, 0, 3, /* Normal Preset */ 66 5, 3, -2, 4, 4, /* Classical Preset */ 67 6, 0, 2, 4, 1, /* Dance Preset */ 68 0, 0, 0, 0, 0, /* Flat Preset */ 69 3, 0, 0, 2, -1, /* Folk Preset */ 70 4, 1, 9, 3, 0, /* Heavy Metal Preset */ 71 5, 3, 0, 1, 3, /* Hip Hop Preset */ 72 4, 2, -2, 2, 5, /* Jazz Preset */ 73 -1, 2, 5, 1, -2, /* Pop Preset */ 74 5, 3, -1, 3, 5}; /* Rock Preset */ 75 76const uint16_t equalizer_band_presets_freq[NUM_EQ_BANDS] = { 77 60, /* Frequencies in Hz */ 78 230, 79 910, 80 3600, 81 14000 82}; 83 84/* 85 * Equalizer operations 86 */ 87 88int equalizer_get_band_level(equalizer_context_t *context, int32_t band) 89{ 90 ALOGV("%s: ctxt %p, band: %d level: %d", __func__, context, band, 91 context->band_levels[band] * 100); 92 return context->band_levels[band] * 100; 93} 94 95int equalizer_set_band_level(equalizer_context_t *context, int32_t band, 96 int32_t level) 97{ 98 ALOGV("%s: ctxt %p, band: %d, level: %d", __func__, context, band, level); 99 if (level > 0) { 100 level = (int)((level+50)/100); 101 } else { 102 level = (int)((level-50)/100); 103 } 104 context->band_levels[band] = level; 105 context->preset = PRESET_CUSTOM; 106 107 offload_eq_set_preset(&(context->offload_eq), PRESET_CUSTOM); 108 offload_eq_set_bands_level(&(context->offload_eq), 109 NUM_EQ_BANDS, 110 equalizer_band_presets_freq, 111 context->band_levels); 112 if (context->ctl) 113 offload_eq_send_params(context->ctl, context->offload_eq, 114 OFFLOAD_SEND_EQ_ENABLE_FLAG | 115 OFFLOAD_SEND_EQ_BANDS_LEVEL); 116 return 0; 117} 118 119int equalizer_get_center_frequency(equalizer_context_t *context, int32_t band) 120{ 121 ALOGV("%s: ctxt %p, band: %d", __func__, context, band); 122 return (equalizer_band_freq_range[band][0] + 123 equalizer_band_freq_range[band][1]) / 2; 124} 125 126int equalizer_get_band_freq_range(equalizer_context_t *context, int32_t band, 127 uint32_t *low, uint32_t *high) 128{ 129 ALOGV("%s: ctxt %p, band: %d", __func__, context, band); 130 *low = equalizer_band_freq_range[band][0]; 131 *high = equalizer_band_freq_range[band][1]; 132 return 0; 133} 134 135int equalizer_get_band(equalizer_context_t *context, uint32_t freq) 136{ 137 int i; 138 139 ALOGV("%s: ctxt %p, freq: %d", __func__, context, freq); 140 for(i = 0; i < NUM_EQ_BANDS; i++) { 141 if (freq <= equalizer_band_freq_range[i][1]) { 142 return i; 143 } 144 } 145 return NUM_EQ_BANDS - 1; 146} 147 148int equalizer_get_preset(equalizer_context_t *context) 149{ 150 ALOGV("%s: ctxt %p, preset: %d", __func__, context, context->preset); 151 return context->preset; 152} 153 154int equalizer_set_preset(equalizer_context_t *context, int preset) 155{ 156 int i; 157 158 ALOGV("%s: ctxt %p, preset: %d", __func__, context, preset); 159 context->preset = preset; 160 for (i=0; i<NUM_EQ_BANDS; i++) 161 context->band_levels[i] = 162 equalizer_band_presets_level[i + preset * NUM_EQ_BANDS]; 163 164 offload_eq_set_preset(&(context->offload_eq), preset); 165 offload_eq_set_bands_level(&(context->offload_eq), 166 NUM_EQ_BANDS, 167 equalizer_band_presets_freq, 168 context->band_levels); 169 if(context->ctl) 170 offload_eq_send_params(context->ctl, context->offload_eq, 171 OFFLOAD_SEND_EQ_ENABLE_FLAG | 172 OFFLOAD_SEND_EQ_PRESET); 173 return 0; 174} 175 176const char * equalizer_get_preset_name(equalizer_context_t *context, 177 int32_t preset) 178{ 179 ALOGV("%s: ctxt %p, preset: %s", __func__, context, 180 equalizer_preset_names[preset]); 181 if (preset == PRESET_CUSTOM) { 182 return "Custom"; 183 } else { 184 return equalizer_preset_names[preset]; 185 } 186} 187 188int equalizer_get_num_presets(equalizer_context_t *context) 189{ 190 ALOGV("%s: ctxt %p, presets_num: %d", __func__, context, 191 sizeof(equalizer_preset_names)/sizeof(char *)); 192 return sizeof(equalizer_preset_names)/sizeof(char *); 193} 194 195int equalizer_get_parameter(effect_context_t *context, effect_param_t *p, 196 uint32_t *size) 197{ 198 equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; 199 int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); 200 int32_t *param_tmp = (int32_t *)p->data; 201 int32_t param = *param_tmp++; 202 int32_t param2; 203 char *name; 204 void *value = p->data + voffset; 205 int i; 206 207 ALOGV("%s: ctxt %p, param %d", __func__, eq_ctxt, param); 208 209 p->status = 0; 210 211 switch (param) { 212 case EQ_PARAM_NUM_BANDS: 213 case EQ_PARAM_CUR_PRESET: 214 case EQ_PARAM_GET_NUM_OF_PRESETS: 215 case EQ_PARAM_BAND_LEVEL: 216 case EQ_PARAM_GET_BAND: 217 if (p->vsize < sizeof(int16_t)) 218 p->status = -EINVAL; 219 p->vsize = sizeof(int16_t); 220 break; 221 222 case EQ_PARAM_LEVEL_RANGE: 223 if (p->vsize < 2 * sizeof(int16_t)) 224 p->status = -EINVAL; 225 p->vsize = 2 * sizeof(int16_t); 226 break; 227 case EQ_PARAM_BAND_FREQ_RANGE: 228 if (p->vsize < 2 * sizeof(int32_t)) 229 p->status = -EINVAL; 230 p->vsize = 2 * sizeof(int32_t); 231 break; 232 233 case EQ_PARAM_CENTER_FREQ: 234 if (p->vsize < sizeof(int32_t)) 235 p->status = -EINVAL; 236 p->vsize = sizeof(int32_t); 237 break; 238 239 case EQ_PARAM_GET_PRESET_NAME: 240 break; 241 242 case EQ_PARAM_PROPERTIES: 243 if (p->vsize < (2 + NUM_EQ_BANDS) * sizeof(uint16_t)) 244 p->status = -EINVAL; 245 p->vsize = (2 + NUM_EQ_BANDS) * sizeof(uint16_t); 246 break; 247 248 default: 249 p->status = -EINVAL; 250 } 251 252 *size = sizeof(effect_param_t) + voffset + p->vsize; 253 254 if (p->status != 0) 255 return 0; 256 257 switch (param) { 258 case EQ_PARAM_NUM_BANDS: 259 *(uint16_t *)value = (uint16_t)NUM_EQ_BANDS; 260 break; 261 262 case EQ_PARAM_LEVEL_RANGE: 263 *(int16_t *)value = -1500; 264 *((int16_t *)value + 1) = 1500; 265 break; 266 267 case EQ_PARAM_BAND_LEVEL: 268 param2 = *param_tmp; 269 if (param2 >= NUM_EQ_BANDS) { 270 p->status = -EINVAL; 271 break; 272 } 273 *(int16_t *)value = (int16_t)equalizer_get_band_level(eq_ctxt, param2); 274 break; 275 276 case EQ_PARAM_CENTER_FREQ: 277 param2 = *param_tmp; 278 if (param2 >= NUM_EQ_BANDS) { 279 p->status = -EINVAL; 280 break; 281 } 282 *(int32_t *)value = equalizer_get_center_frequency(eq_ctxt, param2); 283 break; 284 285 case EQ_PARAM_BAND_FREQ_RANGE: 286 param2 = *param_tmp; 287 if (param2 >= NUM_EQ_BANDS) { 288 p->status = -EINVAL; 289 break; 290 } 291 equalizer_get_band_freq_range(eq_ctxt, param2, (uint32_t *)value, 292 ((uint32_t *)value + 1)); 293 break; 294 295 case EQ_PARAM_GET_BAND: 296 param2 = *param_tmp; 297 *(uint16_t *)value = (uint16_t)equalizer_get_band(eq_ctxt, param2); 298 break; 299 300 case EQ_PARAM_CUR_PRESET: 301 *(uint16_t *)value = (uint16_t)equalizer_get_preset(eq_ctxt); 302 break; 303 304 case EQ_PARAM_GET_NUM_OF_PRESETS: 305 *(uint16_t *)value = (uint16_t)equalizer_get_num_presets(eq_ctxt); 306 break; 307 308 case EQ_PARAM_GET_PRESET_NAME: 309 param2 = *param_tmp; 310 ALOGV("%s: EQ_PARAM_GET_PRESET_NAME: param2: %d", __func__, param2); 311 if (param2 >= equalizer_get_num_presets(eq_ctxt)) { 312 p->status = -EINVAL; 313 break; 314 } 315 name = (char *)value; 316 strlcpy(name, equalizer_get_preset_name(eq_ctxt, param2), p->vsize - 1); 317 name[p->vsize - 1] = 0; 318 p->vsize = strlen(name) + 1; 319 break; 320 321 case EQ_PARAM_PROPERTIES: { 322 int16_t *prop = (int16_t *)value; 323 prop[0] = (int16_t)equalizer_get_preset(eq_ctxt); 324 prop[1] = (int16_t)NUM_EQ_BANDS; 325 for (i = 0; i < NUM_EQ_BANDS; i++) { 326 prop[2 + i] = (int16_t)equalizer_get_band_level(eq_ctxt, i); 327 } 328 } break; 329 330 default: 331 p->status = -EINVAL; 332 break; 333 } 334 335 return 0; 336} 337 338int equalizer_set_parameter(effect_context_t *context, effect_param_t *p, 339 uint32_t size __unused) 340{ 341 equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; 342 int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t); 343 void *value = p->data + voffset; 344 int32_t *param_tmp = (int32_t *)p->data; 345 int32_t param = *param_tmp++; 346 int32_t preset; 347 int32_t band; 348 int32_t level; 349 int i; 350 351 ALOGV("%s: ctxt %p, param %d", __func__, eq_ctxt, param); 352 353 p->status = 0; 354 355 switch (param) { 356 case EQ_PARAM_CUR_PRESET: 357 preset = (int32_t)(*(uint16_t *)value); 358 359 if ((preset >= equalizer_get_num_presets(eq_ctxt)) || (preset < 0)) { 360 p->status = -EINVAL; 361 break; 362 } 363 equalizer_set_preset(eq_ctxt, preset); 364 break; 365 case EQ_PARAM_BAND_LEVEL: 366 band = *param_tmp; 367 level = (int32_t)(*(int16_t *)value); 368 if (band >= NUM_EQ_BANDS) { 369 p->status = -EINVAL; 370 break; 371 } 372 equalizer_set_band_level(eq_ctxt, band, level); 373 break; 374 case EQ_PARAM_PROPERTIES: { 375 int16_t *prop = (int16_t *)value; 376 if ((int)prop[0] >= equalizer_get_num_presets(eq_ctxt)) { 377 p->status = -EINVAL; 378 break; 379 } 380 if (prop[0] >= 0) { 381 equalizer_set_preset(eq_ctxt, (int)prop[0]); 382 } else { 383 if ((int)prop[1] != NUM_EQ_BANDS) { 384 p->status = -EINVAL; 385 break; 386 } 387 for (i = 0; i < NUM_EQ_BANDS; i++) { 388 equalizer_set_band_level(eq_ctxt, i, (int)prop[2 + i]); 389 } 390 } 391 } break; 392 default: 393 p->status = -EINVAL; 394 break; 395 } 396 397 return 0; 398} 399 400int equalizer_set_device(effect_context_t *context, uint32_t device) 401{ 402 ALOGV("%s: ctxt %p, device: 0x%x", __func__, context, device); 403 equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; 404 eq_ctxt->device = device; 405 offload_eq_set_device(&(eq_ctxt->offload_eq), device); 406 return 0; 407} 408 409int equalizer_reset(effect_context_t *context) 410{ 411 equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; 412 413 return 0; 414} 415 416int equalizer_init(effect_context_t *context) 417{ 418 ALOGV("%s: ctxt %p", __func__, context); 419 equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; 420 421 context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; 422 context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; 423 context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; 424 context->config.inputCfg.samplingRate = 44100; 425 context->config.inputCfg.bufferProvider.getBuffer = NULL; 426 context->config.inputCfg.bufferProvider.releaseBuffer = NULL; 427 context->config.inputCfg.bufferProvider.cookie = NULL; 428 context->config.inputCfg.mask = EFFECT_CONFIG_ALL; 429 context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; 430 context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; 431 context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; 432 context->config.outputCfg.samplingRate = 44100; 433 context->config.outputCfg.bufferProvider.getBuffer = NULL; 434 context->config.outputCfg.bufferProvider.releaseBuffer = NULL; 435 context->config.outputCfg.bufferProvider.cookie = NULL; 436 context->config.outputCfg.mask = EFFECT_CONFIG_ALL; 437 438 set_config(context, &context->config); 439 440 memset(&(eq_ctxt->offload_eq), 0, sizeof(struct eq_params)); 441 offload_eq_set_preset(&(eq_ctxt->offload_eq), INVALID_PRESET); 442 443 return 0; 444} 445 446int equalizer_enable(effect_context_t *context) 447{ 448 equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; 449 450 ALOGV("%s: ctxt %p", __func__, context); 451 452 if (!offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) { 453 offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), true); 454 if (eq_ctxt->ctl) 455 offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq, 456 OFFLOAD_SEND_EQ_ENABLE_FLAG | 457 OFFLOAD_SEND_EQ_BANDS_LEVEL); 458 } 459 return 0; 460} 461 462int equalizer_disable(effect_context_t *context) 463{ 464 equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; 465 466 ALOGV("%s:ctxt %p", __func__, eq_ctxt); 467 if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) { 468 offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), false); 469 if (eq_ctxt->ctl) 470 offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq, 471 OFFLOAD_SEND_EQ_ENABLE_FLAG); 472 } 473 return 0; 474} 475 476int equalizer_start(effect_context_t *context, output_context_t *output) 477{ 478 equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; 479 480 ALOGV("%s: ctxt %p, ctl %p", __func__, eq_ctxt, output->ctl); 481 eq_ctxt->ctl = output->ctl; 482 if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) 483 if (eq_ctxt->ctl) 484 offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq, 485 OFFLOAD_SEND_EQ_ENABLE_FLAG | 486 OFFLOAD_SEND_EQ_BANDS_LEVEL); 487 return 0; 488} 489 490int equalizer_stop(effect_context_t *context, output_context_t *output __unused) 491{ 492 equalizer_context_t *eq_ctxt = (equalizer_context_t *)context; 493 494 ALOGV("%s: ctxt %p", __func__, eq_ctxt); 495 eq_ctxt->ctl = NULL; 496 return 0; 497} 498