* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"
#include "osal_mem.h"
#include "securec.h"
#include "parse_effect_config.h"
#include "audio_uhdf_log.h"
#define HDF_EFFECT_NUM_MAX 32
#define HDF_EFFECT_CONFIG_SIZE_MAX ((HDF_EFFECT_NUM_MAX) * 1024)
#define HDF_EFFECT_NAME_LEN 64
#define HDF_LOG_TAG HDF_AUDIO_EFFECT
static char *GetAudioEffectConfig(const char *fpath)
{
char *pJsonStr = NULL;
if (fpath == NULL) {
HDF_LOGE("%{public}s: fpath is null!", __func__);
return NULL;
}
char pathBuf[PATH_MAX] = {'\0'};
if (realpath(fpath, pathBuf) == NULL) {
HDF_LOGE("%{public}s: realpath is null! [%{public}d]", __func__, errno);
return NULL;
}
FILE *fp = fopen(pathBuf, "r");
if (fp == NULL) {
HDF_LOGE("%{public}s: can not open config file! [%{public}d]", __func__, errno);
return NULL;
}
if (fseek(fp, 0, SEEK_END) != HDF_SUCCESS) {
HDF_LOGE("%{public}s: fseek fail! [%{public}d]", __func__, errno);
(void)fclose(fp);
return NULL;
}
int32_t jsonStrSize = ftell(fp);
if (jsonStrSize <= 0) {
HDF_LOGE("%{public}s: ftell fail! [%{public}d]", __func__, errno);
(void)fclose(fp);
return NULL;
}
rewind(fp);
if (jsonStrSize > HDF_EFFECT_CONFIG_SIZE_MAX) {
HDF_LOGE("%{public}s: The configuration file is too large to load!", __func__);
(void)fclose(fp);
return NULL;
}
pJsonStr = (char *)OsalMemCalloc((uint32_t)jsonStrSize + 1);
if (pJsonStr == NULL) {
HDF_LOGE("%{public}s: alloc pJsonStr failed!", __func__);
(void)fclose(fp);
return NULL;
}
if (fread(pJsonStr, jsonStrSize, 1, fp) != 1) {
HDF_LOGE("%{public}s: read to file fail! [%{public}d]", __func__, errno);
OsalMemFree((void *)pJsonStr);
(void)fclose(fp);
return NULL;
}
(void)fclose(fp);
return pJsonStr;
}
cJSON *GetAudioEffectConfigToJsonObj(const char *fpath)
{
char *pJsonStr = GetAudioEffectConfig(fpath);
if (pJsonStr == NULL) {
HDF_LOGE("%{public}s: get audio effect config failed!", __func__);
return NULL;
}
cJSON *cJsonObj = cJSON_Parse(pJsonStr);
if (cJsonObj == NULL) {
HDF_LOGE("%{public}s: cJSON_Parse failed!", __func__);
OsalMemFree((void *)pJsonStr);
return NULL;
}
OsalMemFree((void *)pJsonStr);
return cJsonObj;
}
static char *AudioEffectGetAndCheckName(const cJSON *cJSONObj, const char *name)
{
if (cJSONObj == NULL || name == NULL) {
HDF_LOGE("%{public}s: invalid parameter!", __func__);
return NULL;
}
cJSON *cJSONName = cJSON_GetObjectItem(cJSONObj, name);
if (cJSONName == NULL || cJSONName->valuestring == NULL) {
HDF_LOGE("%{public}s: cJSONName or cJSONName->valuestring is null!", __func__);
return NULL;
}
char *effectValue = cJSONName->valuestring;
if (strlen(effectValue) == 0) {
HDF_LOGE("%{public}s: effectValue is null!", __func__);
return NULL;
}
if (strcmp(name, "effectId")) {
if (!isalpha(*effectValue)) {
HDF_LOGE("%{public}s: effectValue is illegal!", __func__);
return NULL;
}
effectValue++;
}
while (*effectValue != '\0') {
if (*effectValue == '_' || (strcmp(name, "effectId") == 0 && *effectValue == '-')) {
effectValue++;
continue;
}
if (!isalnum(*effectValue++)) {
HDF_LOGE("%{public}s: effectValue is illegal!, %{public}c", __func__, *effectValue);
return NULL;
}
}
return cJSONName->valuestring;
}
static int32_t AudioEffectParseItem(const cJSON *cJSONObj, const char *item, const char **dest)
{
if (cJSONObj == NULL || item == NULL || dest == NULL) {
HDF_LOGE("%{public}s: invalid parameter!", __func__);
return HDF_ERR_INVALID_PARAM;
}
const char *itemName = AudioEffectGetAndCheckName(cJSONObj, item);
if (itemName == NULL) {
HDF_LOGE("%{public}s: get %{public}s fail!", __func__, item);
return HDF_FAILURE;
}
*dest = (char *)OsalMemCalloc(HDF_EFFECT_NAME_LEN * sizeof(char));
if (*dest == NULL) {
HDF_LOGE("%{public}s: out of memory! Item is %{public}s", __func__, item);
return HDF_ERR_MALLOC_FAIL;
}
if (memcpy_s((void *)(*dest), HDF_EFFECT_NAME_LEN, itemName, strlen(itemName)) != EOK) {
HDF_LOGE("%{public}s: memcpy_s effect name fail! Item is %{public}s", __func__, item);
OsalMemFree((void *)(*dest));
*dest = NULL;
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t AudioEffectParseEffect(const cJSON *effectObj, struct EffectConfigDescriptor *effectDesc)
{
if (effectObj == NULL || effectDesc == NULL) {
HDF_LOGE("%{public}s: invalid parameter!", __func__);
return HDF_ERR_INVALID_PARAM;
}
if (AudioEffectParseItem(effectObj, "name", &(effectDesc->name)) != HDF_SUCCESS) {
HDF_LOGE("%{public}s: parse item %{public}s fail!", __func__, "name");
return HDF_FAILURE;
}
if (AudioEffectParseItem(effectObj, "library", &(effectDesc->library)) != HDF_SUCCESS) {
HDF_LOGE("%{public}s: parse item %{public}s fail!", __func__, "library");
OsalMemFree((void *)effectDesc->name);
return HDF_FAILURE;
}
if (AudioEffectParseItem(effectObj, "effectId", &(effectDesc->effectId)) != HDF_SUCCESS) {
HDF_LOGE("%{public}s: parse item %{public}s fail!", __func__, "library");
OsalMemFree((void *)effectDesc->name);
OsalMemFree((void *)effectDesc->library);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static void AudioEffectReleaseDescs(struct EffectConfigDescriptor *effectDescs, int32_t effectNum)
{
int32_t i = 0;
if (effectDescs == NULL || effectNum <= 0 || effectNum > HDF_EFFECT_NUM_MAX) {
HDF_LOGE("%{public}s: effectDescs is null or effectNum is invalid!", __func__);
return;
}
for (i = 0; i < effectNum; i++) {
OsalMemFree((void *)effectDescs[i].name);
OsalMemFree((void *)effectDescs[i].library);
OsalMemFree((void *)effectDescs[i].effectId);
}
}
static int32_t AudioEffectGetEffectCfgDescs(cJSON *cJsonObj, const char *item, struct ConfigDescriptor *cfgDesc)
{
HDF_LOGD("enter to %{public}s", __func__);
uint32_t effectNum;
uint32_t i;
cJSON *effectObj = NULL;
struct EffectConfigDescriptor *effectDescs = NULL;
int32_t ret;
if (cJsonObj == NULL || item == NULL || cfgDesc == NULL) {
HDF_LOGE("%{public}s: invalid parameter!", __func__);
return HDF_ERR_INVALID_PARAM;
}
cJSON *effectsObj = cJSON_GetObjectItem(cJsonObj, item);
if (effectsObj == NULL) {
HDF_LOGE("%{public}s: get effects failed!", __func__);
return HDF_FAILURE;
}
effectNum = (uint32_t)cJSON_GetArraySize(effectsObj);
if (effectNum == 0 || effectNum > HDF_EFFECT_NUM_MAX) {
HDF_LOGE("%{public}s: effectNum invalid, effectNum = %{public}d!", __func__, effectNum);
return HDF_FAILURE;
}
effectDescs = (struct EffectConfigDescriptor *)OsalMemCalloc(effectNum * sizeof(struct EffectConfigDescriptor));
if (effectDescs == NULL) {
HDF_LOGE("%{public}s: alloc effectDescs failed", __func__);
return HDF_ERR_MALLOC_FAIL;
}
for (i = 0; i < effectNum; i++) {
effectObj = cJSON_GetArrayItem(effectsObj, i);
if (effectObj == NULL) {
HDF_LOGE("%{public}s get effect item fail!", __func__);
AudioEffectReleaseDescs(effectDescs, i);
OsalMemFree((void *)effectDescs);
return HDF_FAILURE;
}
ret = AudioEffectParseEffect(effectObj, &effectDescs[i]);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%{public}s: parse effect[%{public}d] failed, ret = %{public}d", __func__, i, ret);
AudioEffectReleaseDescs(effectDescs, i);
OsalMemFree((void *)effectDescs);
return HDF_FAILURE;
}
}
cfgDesc->effectNum = effectNum;
cfgDesc->effectCfgDescs = effectDescs;
HDF_LOGD("%{public}s success", __func__);
return HDF_SUCCESS;
}
static int32_t AudioEffectParseLibrary(const cJSON *libObj, struct LibraryConfigDescriptor *libDesc)
{
if (libObj == NULL || libDesc == NULL) {
HDF_LOGE("%{public}s: invalid parameter!", __func__);
return HDF_ERR_INVALID_PARAM;
}
if (AudioEffectParseItem(libObj, "name", &(libDesc->libName)) != HDF_SUCCESS) {
HDF_LOGE("%{public}s: parse item %{public}s fail!", __func__, "name");
return HDF_FAILURE;
}
if (AudioEffectParseItem(libObj, "path", &(libDesc->libPath)) != HDF_SUCCESS) {
HDF_LOGE("%{public}s: parse item %{public}s fail!", __func__, "path");
OsalMemFree((void *)libDesc->libName);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static void AudioEffectLibraryReleaseDescs(struct LibraryConfigDescriptor *libDescs, int32_t libNum)
{
int32_t i = 0;
if (libDescs == NULL || libNum <= 0 || libNum > HDF_EFFECT_LIB_NUM_MAX) {
HDF_LOGE("%{public}s: libDescs is null or libNum is invalid!", __func__);
return;
}
for (i = 0; i < libNum; i++) {
OsalMemFree((void *)libDescs[i].libName);
OsalMemFree((void *)libDescs[i].libPath);
}
}
static int32_t AudioEffectGetLibraryCfgDescs(cJSON *cJsonObj, const char *item, struct ConfigDescriptor *cfgDesc)
{
HDF_LOGD("enter to %{public}s", __func__);
int32_t ret;
uint32_t i;
uint32_t libNum;
cJSON *libObj = NULL;
struct LibraryConfigDescriptor *libDescs = NULL;
if (cJsonObj == NULL || item == NULL || cfgDesc == NULL) {
HDF_LOGE("%{public}s: invalid parameter!", __func__);
return HDF_ERR_INVALID_PARAM;
}
cJSON *libsObj = cJSON_GetObjectItem(cJsonObj, item);
if (libsObj == NULL) {
HDF_LOGE("%{public}s: get libs failed!", __func__);
return HDF_FAILURE;
}
libNum = (uint32_t)cJSON_GetArraySize(libsObj);
if (libNum == 0 || libNum > HDF_EFFECT_NUM_MAX) {
HDF_LOGE("%{public}s: libNum invalid, libNum = %{public}d!", __func__, libNum);
return HDF_FAILURE;
}
libDescs = (struct LibraryConfigDescriptor *)OsalMemCalloc(libNum * sizeof(struct LibraryConfigDescriptor));
if (libDescs == NULL) {
HDF_LOGE("%{public}s: malloc libDescs failed", __func__);
return HDF_ERR_MALLOC_FAIL;
}
for (i = 0; i < libNum; i++) {
libObj = cJSON_GetArrayItem(libsObj, i);
if (libObj == NULL) {
HDF_LOGE("%{public}s get library item fail!", __func__);
AudioEffectLibraryReleaseDescs(libDescs, i);
OsalMemFree((void *)libDescs);
return HDF_FAILURE;
}
ret = AudioEffectParseLibrary(libObj, &libDescs[i]);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%{public}s: parse library[%{public}d] failed, ret = %{public}d", __func__, i, ret);
AudioEffectLibraryReleaseDescs(libDescs, i);
OsalMemFree((void *)libDescs);
return HDF_FAILURE;
}
}
cfgDesc->libNum = libNum;
cfgDesc->libCfgDescs = libDescs;
HDF_LOGD("%{public}s success", __func__);
return HDF_SUCCESS;
}
void AudioEffectReleaseCfgDesc(struct ConfigDescriptor *cfgDesc)
{
if (cfgDesc == NULL) {
return;
}
if (cfgDesc->libCfgDescs != NULL) {
AudioEffectLibraryReleaseDescs(cfgDesc->libCfgDescs, cfgDesc->libNum);
OsalMemFree((void *)cfgDesc->libCfgDescs);
}
if (cfgDesc->effectCfgDescs != NULL) {
AudioEffectReleaseDescs(cfgDesc->effectCfgDescs, cfgDesc->effectNum);
OsalMemFree((void *)cfgDesc->effectCfgDescs);
}
OsalMemFree((void *)cfgDesc);
cfgDesc = NULL;
}
int32_t AudioEffectGetConfigDescriptor(const char *path, struct ConfigDescriptor **cfgDesc)
{
if (path == NULL || cfgDesc == NULL) {
HDF_LOGE("%{public}s: invalid parameter!", __func__);
return HDF_ERR_INVALID_PARAM;
}
cJSON *cJsonObj = GetAudioEffectConfigToJsonObj(path);
if (cJsonObj == NULL) {
HDF_LOGE("%{public}s: get cJsonObj failed!", __func__);
return HDF_FAILURE;
}
*cfgDesc = (struct ConfigDescriptor *)OsalMemCalloc(sizeof(struct ConfigDescriptor));
if (*cfgDesc == NULL) {
HDF_LOGE("%{public}s: alloc libDescs failed", __func__);
cJSON_Delete(cJsonObj);
cJsonObj = NULL;
return HDF_ERR_MALLOC_FAIL;
}
if (AudioEffectGetLibraryCfgDescs(cJsonObj, "libraries", *cfgDesc) != HDF_SUCCESS) {
HDF_LOGE("%{public}s: get library config failed", __func__);
AudioEffectReleaseCfgDesc(*cfgDesc);
cJSON_Delete(cJsonObj);
cJsonObj = NULL;
return HDF_FAILURE;
}
if (AudioEffectGetEffectCfgDescs(cJsonObj, "effects", *cfgDesc) != HDF_SUCCESS) {
HDF_LOGE("%{public}s: get effect config failed", __func__);
AudioEffectReleaseCfgDesc(*cfgDesc);
cJSON_Delete(cJsonObj);
cJsonObj = NULL;
return HDF_FAILURE;
}
cJSON_Delete(cJsonObj);
cJsonObj = NULL;
HDF_LOGD("%{public}s success", __func__);
return HDF_SUCCESS;
}