Files
AC707N/SDK/audio/framework/nodes/volume_node.c
T
2025-12-03 11:12:34 +08:00

533 lines
20 KiB
C

#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".volume_node.data.bss")
#pragma data_seg(".volume_node.data")
#pragma const_seg(".volume_node.text.const")
#pragma code_seg(".volume_node.text")
#endif
#include "jlstream.h"
#include "classic/tws_api.h"
#include "media/audio_base.h"
#include "app_main.h"
#include "audio_config.h"
#include "audio_dvol.h"
#include "effects/effects_adj.h"
#include "volume_node.h"
#include "scene_switch.h"
#include "app_config.h"
struct volume_hdl {
char name[16]; //节点名称
enum stream_scene scene;
dvol_handle *dvol_hdl; //音量操作句柄
struct stream_node *node; //节点句柄
struct node_port_data_wide data_wide;
u8 Qval;//数据的饱和位宽
u8 state;
u8 bypass;//是否跳过节点处理
struct volume_cfg *vol_cfg;
u16 cfg_len;//配置数据实际大小
u8 online_update_disable;//是否支持在线音量更新
u16 target_dig_volume;//优化底噪时的固定数字音量
};
//默认音量配置
struct volume_cfg default_vol_cfg = {
.bypass = 0,
.cfg_level_max = 16,
.cfg_vol_min = -45,
.cfg_vol_max = 0,
.vol_table_custom = 0,
.cur_vol = 11,
};
__STREAM_CACHE_CODE
static void volume_handle_frame(struct stream_iport *iport, struct stream_note *note)
{
struct stream_frame *frame;
struct stream_node *node = iport->node;
struct volume_hdl *hdl = (struct volume_hdl *)iport->private_data;
while (1) {
frame = jlstream_pull_frame(iport, note);
if (!frame) {
break;
}
if (!hdl->bypass) {
audio_digital_vol_run(hdl->dvol_hdl, (s16 *)frame->data, frame->len);
}
if (node->oport) {
jlstream_push_frame(node->oport, frame);
} else {
jlstream_free_frame(frame);
}
break;
}
}
static int volume_bind(struct stream_node *node, u16 uuid)
{
struct volume_hdl *hdl = zalloc(sizeof(*hdl));
node->private_data = hdl;
hdl->node = node;
return 0;
}
static void volume_open_iport(struct stream_iport *iport)
{
iport->handle_frame = volume_handle_frame;
iport->private_data = iport->node->private_data;
}
/*节点参数协商*/
static int volume_ioc_negotiate(struct stream_iport *iport)
{
return 0;
}
void audio_digital_vol_cfg_init(dvol_handle *dvol, struct volume_cfg *vol_cfg) //初始化配置
{
if (dvol) {
dvol-> cfg_vol_max = vol_cfg->cfg_vol_max;
dvol-> cfg_vol_min = vol_cfg->cfg_vol_min;
dvol-> cfg_level_max = vol_cfg->cfg_level_max;
dvol-> vol_table_custom = vol_cfg->vol_table_custom;
#if VOL_TAB_CUSTOM_EN
if (dvol->vol_table_custom == VOLUME_TABLE_CUSTOM_EN) {
dvol->vol_table = vol_cfg->vol_table ;
}
#endif
dvol->vol_limit = (dvol->vol_limit > dvol->cfg_level_max) ? dvol->cfg_level_max : dvol->vol_limit;
u16 vol_level = dvol->vol * dvol->vol_limit / dvol->vol_max;
if (vol_level == 0) {
dvol->vol_target = 0;
} else if (dvol->vol_table) {
dvol->vol_target = dvol->vol_table[vol_level - 1];
} else {
extern float eq_db2mag(float x);
u16 step = (dvol->cfg_level_max - 1 > 0) ? (dvol->cfg_level_max - 1) : 1;
float step_db = (dvol->cfg_vol_max - dvol->cfg_vol_min) / (float)step;
float dvol_db = dvol->cfg_vol_min + (vol_level - 1) * step_db;
float dvol_gain = eq_db2mag(dvol_db);//dB转换倍数
dvol->vol_target = (s16)(DVOL_MAX_FLOAT * dvol_gain + 0.5f);
printf("vol param:%d,(%d/100)dB,cur:%d,max:%d,(%d/100)dB", dvol->vol_target, (int)step_db * 100, vol_level, vol_cfg->cfg_level_max, (int)dvol_db * 100);
#if 0
//打印音量表每一级的目标音量值和dB值,调试用
printf("=========================================vol table=================================================================");
int i = 1;
for (i = 1; i < dvol->cfg_level_max + 1; i++) {
float debug_db = dvol->cfg_vol_min + (i - 1) * step_db;
float debug_gain = eq_db2mag(debug_db);//dB转换倍数
int debug_target = (s16)(DVOL_MAX_FLOAT * debug_gain + 0.5);
printf("dvol[%d] = %d,(%d / 100)dB", i, debug_target, (int)(debug_db * 100));
}
printf("====================================================================================================================");
#endif
}
dvol->vol_fade = 0; //从0开始淡入到目标音量
if ((dvol->cfg_vol_min == -45) && (dvol->cfg_level_max == 31) && (dvol->cfg_vol_max == 0)) {
dvol-> vol_table_default = 1; //使用默认的音量表
}
}
}
static void volume_ioc_start(struct volume_hdl *hdl)
{
/*
*获取配置文件内的参数,及名字
* */
int len = 0;
struct audio_vol_params params = {0};
struct volume_cfg *vol_cfg = NULL;
if (!hdl->vol_cfg) {
struct cfg_info info = {0}; //节点配置相关信息(参数存储的目标地址、配置项大小)
int ret = jlstream_read_node_info_data(hdl->node->uuid, hdl->node->subid, hdl->name, &info);
/* printf("enter volume_node.c %d,%d,%d\n", __LINE__, ret, info.size); */
if (ret) {
hdl->cfg_len = info.size;
vol_cfg = hdl->vol_cfg = zalloc(info.size);
len = jlstream_read_form_cfg_data(&info, (void *)vol_cfg);
if (info.size > sizeof(struct volume_cfg)) { //有自定义音量表,dB转成对应音量
for (int i = 0; i < vol_cfg->cfg_level_max ; i++) {
/* printf("custom dvol [%d] = %d / 100 dB", i, (int)(hdl->vol_cfg->vol_table[i] * 100)); */
float dvol_gain = eq_db2mag(hdl->vol_cfg->vol_table[i]);//dB转换倍数
hdl->vol_cfg->vol_table [i] = (s16)(DVOL_MAX_FLOAT * dvol_gain + 0.5f);
/* printf("custom dvol[%d] = %d", i, (int)hdl->vol_cfg->vol_table[i]); */
}
}
}
} else {
len = hdl->cfg_len;
vol_cfg = hdl->vol_cfg;
}
if (!len) {
printf("%s, read node data err\n", __FUNCTION__);
}
hdl->data_wide.iport_data_wide = hdl->node->iport->prev->fmt.bit_wide;
hdl->data_wide.oport_data_wide = hdl->node->oport->fmt.bit_wide;
log_d("%s bit_wide, %d %d %d\n", __FUNCTION__, hdl->data_wide.iport_data_wide, hdl->data_wide.oport_data_wide, hdl->node->oport->fmt.Qval);
printf("%s len %d, sizeof(cfg) %d\n", __func__, len, (int)sizeof(struct volume_cfg));
if (len != hdl->cfg_len) {
if (hdl->vol_cfg) {
free(hdl->vol_cfg);
hdl->vol_cfg = NULL;
}
vol_cfg = &default_vol_cfg;
} else {
printf("vol read config ok :%d,%d,%d,%d,%d\n", vol_cfg->cfg_level_max, (int)vol_cfg->cfg_vol_min, (int)vol_cfg->cfg_vol_max, vol_cfg->vol_table_custom, vol_cfg->bypass);
}
/*
*获取在线调试的临时参数
* */
u32 online_cfg_len = sizeof(struct volume_cfg) + DIGITAL_VOLUME_LEVEL_MAX * sizeof(float);
struct volume_cfg *online_vol_cfg = zalloc(online_cfg_len);
if (jlstream_read_effects_online_param(hdl->node->uuid, hdl->name, online_vol_cfg, online_cfg_len)) {
/* printf("cfg_level_max = %d\n", online_vol_cfg->cfg_level_max); */
/* printf("cfg_vol_min = %d\n", online_vol_cfg->cfg_vol_min); */
/* printf("cfg_vol_max = %d\n", online_vol_cfg->cfg_vol_max); */
/* printf("vol_table_custom = %d\n", online_vol_cfg->vol_table_custom); */
/* printf("cur_vol = %d\n", online_vol_cfg->cur_vol); */
/* printf("tab_len = %d\n", online_vol_cfg->tab_len); */
hdl->vol_cfg-> cfg_vol_max = online_vol_cfg->cfg_vol_max;
hdl->vol_cfg-> cfg_vol_min = online_vol_cfg->cfg_vol_min;
hdl->vol_cfg-> bypass = online_vol_cfg->bypass;
#if VOL_TAB_CUSTOM_EN
if (hdl->vol_cfg->tab_len == online_vol_cfg->tab_len && hdl->vol_cfg->tab_len) {
for (int i = 0; i < hdl->vol_cfg->cfg_level_max ; i++) {//重新计算音量表的值
printf("custom dvol [%d] = %d / 100 dB", i, (int)(online_vol_cfg->vol_table[i] * 100));
float dvol_gain = eq_db2mag(online_vol_cfg->vol_table[i]);//dB转换倍数
hdl->vol_cfg->vol_table [i] = (s16)(DVOL_MAX_FLOAT * dvol_gain + 0.5f);
printf("custom dvol[%d] = %d", i, (int)online_vol_cfg->vol_table[i]);
}
}
#endif
printf("get volume online param\n");
}
free(online_vol_cfg);
hdl->bypass = vol_cfg->bypass;
switch (hdl->scene) {
case STREAM_SCENE_TONE:
case STREAM_SCENE_RING:
case STREAM_SCENE_KEY_TONE:
/*puts("set_tone_volume\n");*/
hdl->state = APP_AUDIO_STATE_WTONE;
#if TONE_BGM_FADEOUT
/*printf("tone_player.c %d tone play,BGM fade_out automatically\n", __LINE__);*/
audio_digital_vol_bg_fade(1);
#endif/*TONE_BGM_FADEOUT*/
params.vol = app_audio_get_volume(APP_AUDIO_STATE_WTONE);
params.vol_max = vol_cfg->cfg_level_max;
params.fade_step = TONE_DVOL_FS;
params.vol_limit = -1;
break;
case STREAM_SCENE_OPUS:
case STREAM_SCENE_A2DP:
case STREAM_SCENE_LINEIN:
case STREAM_SCENE_IIS:
case STREAM_SCENE_SPDIF:
case STREAM_SCENE_PC_SPK:
case STREAM_SCENE_PC_MIC:
case STREAM_SCENE_MUSIC:
case STREAM_SCENE_FM:
case STREAM_SCENE_MIC_EFFECT:
case STREAM_SCENE_HEARING_AID:
puts("set_a2dp_volume\n");
hdl->state = APP_AUDIO_STATE_MUSIC;
params.vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
params.vol_max = vol_cfg->cfg_level_max;
params.fade_step = MUSIC_DVOL_FS;
params.vol_limit = -1;
break;
case STREAM_SCENE_ESCO:
puts("set_esco_volume\n");
hdl->state = APP_AUDIO_STATE_CALL;
params.vol = app_audio_get_volume(APP_AUDIO_STATE_CALL);
params.vol_max = vol_cfg->cfg_level_max;
params.fade_step = CALL_DVOL_FS;
params.vol_limit = -1;
break;
default:
break;
}
params.bit_wide = hdl->node->oport->fmt.bit_wide;
if (!hdl->dvol_hdl) {
hdl->dvol_hdl = audio_digital_vol_open(params);
}
audio_digital_vol_cfg_init(hdl->dvol_hdl, vol_cfg);
if (hdl->dvol_hdl) {
hdl->dvol_hdl->mute_en = app_audio_get_mute_state(hdl->state);
if (hdl->dvol_hdl->mute_en) {
hdl->dvol_hdl->vol_fade = 0;
}
}
if (hdl->scene == STREAM_SCENE_MIC_EFFECT) {
return;
}
#ifdef DVOL_2P1_CH_DVOL_ADJUST_NODE
#if (DVOL_2P1_CH_DVOL_ADJUST_NODE == DVOL_2P1_CH_DVOL_ADJUST_LR)
char *substr = strstr(hdl->name, "Music");
if (!strcmp(substr, "Music") || !strcmp(substr, "Music2")) { //找到默认初始化为最大音量的节点
//printf("enter volume_node.c %d,%p,%s\n", __LINE__, hdl->dvol_hdl, substr);
audio_digital_vol_set(hdl->dvol_hdl, hdl->dvol_hdl->vol_max);
hdl->dvol_hdl->mute_en = 0;
hdl->online_update_disable = 1;
} else {
//printf("enter volume_node.c %d,%p,%s\n", __LINE__, hdl->dvol_hdl, substr);
app_audio_state_switch(hdl->state, vol_cfg->cfg_level_max, hdl->dvol_hdl);
}
#elif (DVOL_2P1_CH_DVOL_ADJUST_NODE == DVOL_2P1_CH_DVOL_ADJUST_SW)
char *substr = strstr(hdl->name, "Music");
if (!strcmp(substr, "Music") || !strcmp(substr, "Music1")) { //找到默认初始化为最大音量的节点
// printf("enter volume_node.c %d,%p,%s\n", __LINE__, hdl->dvol_hdl, substr);
audio_digital_vol_set(hdl->dvol_hdl, hdl->dvol_hdl->vol_max);
hdl->dvol_hdl->mute_en = 0;
hdl->online_update_disable = 1;
} else {
// printf("enter volume_node.c %d,%p,%s\n", __LINE__, hdl->dvol_hdl, substr);
app_audio_state_switch(hdl->state, vol_cfg->cfg_level_max, hdl->dvol_hdl);
}
#else
if (memchr(hdl->name, '1', 16) || memchr(hdl->name, '2', 16)) { //找到默认初始化为最大音量的节点
//printf("enter volume_node.c %d,%p\n", __LINE__, hdl->dvol_hdl);
audio_digital_vol_set(hdl->dvol_hdl, hdl->dvol_hdl->vol_max);
hdl->online_update_disable = 1;
hdl->dvol_hdl->mute_en = 0;
} else {
//printf("enter volume_node.c %d,%p\n", __LINE__, hdl->dvol_hdl);
app_audio_state_switch(hdl->state, vol_cfg->cfg_level_max, hdl->dvol_hdl);
}
#endif
#else
app_audio_state_switch(hdl->state, vol_cfg->cfg_level_max, hdl->dvol_hdl);
#endif
}
static void volume_ioc_stop(struct volume_hdl *hdl)
{
if (hdl->scene != STREAM_SCENE_MIC_EFFECT) {
app_audio_state_exit(hdl->state);
}
#if TONE_BGM_FADEOUT
printf("tone_player.c %d tone play,BGM fade_out close\n", __LINE__);
audio_digital_vol_bg_fade(0);
#endif/*TONE_BGM_FADEOUT*/
audio_digital_vol_close(hdl->dvol_hdl);
hdl->dvol_hdl = NULL;
}
int volume_ioc_get_cfg(const char *name, struct volume_cfg *vol_cfg)
{
char mode_index = get_current_scene();
struct cfg_info info = {0}; //节点配置相关信息(参数存储的目标地址、配置项大小)
int ret = jlstream_read_info_data(mode_index, name, 0, &info);
if (!ret) {
*vol_cfg = default_vol_cfg;
} else {
struct volume_cfg *temp_vol_cfg = zalloc(info.size);
int len = jlstream_read_form_cfg_data(&info, (void *)temp_vol_cfg);
if (len == info.size) {
*vol_cfg = *temp_vol_cfg;
} else {
*vol_cfg = default_vol_cfg;
}
free(temp_vol_cfg); //赋值完结构体释放内存
/* printf("volume node read cfg name %s", name); */
/* printf("cfg_level_max = %d\n", vol_cfg->cfg_level_max); */
/* printf("cfg_vol_min = %d\n", vol_cfg->cfg_vol_min); */
/* printf("cfg_vol_max = %d\n", vol_cfg->cfg_vol_max); */
/* printf("vol_table_custom = %d\n", vol_cfg->vol_table_custom); */
/* printf("cur_vol = %d\n", vol_cfg->cur_vol); */
}
return ret;
}
u16 volume_ioc_get_max_level(const char *name)
{
struct volume_cfg vol_cfg;
volume_ioc_get_cfg(name, &vol_cfg);
return vol_cfg.cfg_level_max;
}
float volume_ioc_2_dB(struct volume_hdl *hdl, s16 volume)
{
if (hdl->dvol_hdl) {
dvol_handle *dvol = hdl->dvol_hdl;
u8 vol_level = volume * dvol->vol_limit / dvol->vol_max;
u16 step = (dvol->cfg_level_max - 1 > 0) ? (dvol->cfg_level_max - 1) : 1;
float step_db = (dvol->cfg_vol_max - dvol->cfg_vol_min) / (float)step;
float dvol_db = dvol->cfg_vol_min + (vol_level - 1) * step_db;
printf("vol_dB :%d,%d\n", __LINE__, (int)dvol_db);
return (dvol_db);
}
return 0;
}
static int volume_ioc_update_parm(struct volume_hdl *hdl, int parm)
{
struct volume_cfg *vol_cfg = (struct volume_cfg *)parm;
int ret = false;
int cmd = (vol_cfg->bypass & 0xf0);
int value = vol_cfg->cur_vol;
switch (cmd) {
case VOLUME_NODE_CMD_SET_VOL:
s16 volume = value & 0xffff;
if (volume < 0) {
volume = 0;
}
if (hdl && hdl->dvol_hdl) {
#if defined(VOL_NOISE_OPTIMIZE) &&( VOL_NOISE_OPTIMIZE)
if (volume) {
if (volume_ioc_2_dB(hdl, volume) < TARGET_DIG_DB && hdl->state == APP_AUDIO_STATE_MUSIC) {
if (!hdl->target_dig_volume) {
s16 temp_volume = 0;
for (temp_volume = hdl->dvol_hdl->vol_max; volume_ioc_2_dB(hdl, temp_volume) > TARGET_DIG_DB; temp_volume--) {};
hdl->target_dig_volume = temp_volume + 1;
}
//printf("enter volume_node.c %d,%d/100,%d/100,%d,%d,%d\n",__LINE__,(int)(volume_ioc_2_dB(hdl,volume) * 100),(int)(volume_ioc_2_dB(hdl,hdl->target_dig_volume)* 100), hdl->target_dig_volume,volume,hdl->dvol_hdl->vol);
float dac_dB = volume_ioc_2_dB(hdl, volume) - volume_ioc_2_dB(hdl, hdl->target_dig_volume) ;
app_audio_dac_set_dB(dac_dB);
volume = hdl->target_dig_volume;
} else { //把DAC 设回0dB
app_audio_dac_set_dB(0);
}
}
#endif
audio_digital_vol_set(hdl->dvol_hdl, volume);
printf("SET VOL volume update success : %d\n", volume);
ret = true;
}
break;
case VOLUME_NODE_CMD_SET_MUTE:
s16 mute_en = value & 0xffff;
if (hdl && hdl->dvol_hdl) {
audio_digital_vol_mute_set(hdl->dvol_hdl, mute_en);
printf("SET MUTE mute update success : %d\n", mute_en);
ret = true;
}
break;
default:
if (hdl && hdl->dvol_hdl) {
if (!hdl->online_update_disable) {
hdl->dvol_hdl-> cfg_vol_max = vol_cfg->cfg_vol_max;
hdl->dvol_hdl-> cfg_vol_min = vol_cfg->cfg_vol_min;
#if VOL_TAB_CUSTOM_EN
if (hdl->vol_cfg->tab_len == vol_cfg->tab_len && hdl->vol_cfg->tab_len) {
for (int i = 0; i < hdl->vol_cfg->cfg_level_max ; i++) {//重新计算音量表的值
//printf("custom dvol [%d] = %d / 100 dB", i, (int)(vol_cfg->vol_table[i] * 100));
float dvol_gain = eq_db2mag(vol_cfg->vol_table[i]);//dB转换倍数
hdl->vol_cfg->vol_table [i] = (s16)(DVOL_MAX_FLOAT * dvol_gain + 0.5f);
//printf("custom dvol[%d] = %d", i, (int)vol_cfg->vol_table[i]);
}
if (hdl->dvol_hdl->vol_table_custom == VOLUME_TABLE_CUSTOM_EN) {
hdl->dvol_hdl->vol_table = hdl->vol_cfg->vol_table ;
}
}
#endif
hdl->bypass = vol_cfg->bypass;
audio_digital_vol_set(hdl->dvol_hdl, vol_cfg->cur_vol);
if (hdl->scene != STREAM_SCENE_MIC_EFFECT) {//混响在线调试音量不更新音量状态的值
app_audio_change_volume(app_audio_get_state(), vol_cfg->cur_vol);
}
}
/* printf("cfg_level_max = %d\n", vol_cfg->cfg_level_max); */
/* printf("cfg_vol_min = %d\n", vol_cfg->cfg_vol_min); */
/* printf("cfg_vol_max = %d\n", vol_cfg->cfg_vol_max); */
/* printf("vol_table_custom = %d\n", vol_cfg->vol_table_custom); */
/* printf("cur_vol = %d\n", vol_cfg->cur_vol); */
printf("volume update success : %d\n", vol_cfg->cur_vol);
ret = true;
return ret;
}
printf("parm update failed : %x\n", value);
break;
}
return ret;
}
static int get_volume_ioc_parm(struct volume_hdl *hdl, int parm)
{
int ret = 0;
struct volume_cfg *cfg = (struct volume_cfg *)parm;
if (hdl && hdl->dvol_hdl) {
hdl->vol_cfg->cur_vol = hdl->dvol_hdl->vol;
}
memcpy(cfg, hdl->vol_cfg, sizeof(struct volume_cfg));
ret = sizeof(struct volume_cfg);
return ret;
}
static int volume_ioctl(struct stream_iport *iport, int cmd, int arg)
{
struct volume_hdl *hdl = (struct volume_hdl *)iport->private_data;
int ret = 0;
switch (cmd) {
case NODE_IOC_OPEN_IPORT:
volume_open_iport(iport);
break;
case NODE_IOC_SET_SCENE:
hdl->scene = (enum stream_scene)arg;
break;
case NODE_IOC_NEGOTIATE:
*(int *)arg |= volume_ioc_negotiate(iport);
break;
case NODE_IOC_START:
volume_ioc_start(hdl);
break;
case NODE_IOC_STOP:
case NODE_IOC_SUSPEND:
volume_ioc_stop(hdl);
break;
case NODE_IOC_NAME_MATCH:
/* printf("volume_node name match :%s,%s\n", hdl->name, (const char *)arg); */
if (!strcmp((const char *)arg, hdl->name)) {
ret = 1;
}
break;
case NODE_IOC_SET_PARAM:
ret = volume_ioc_update_parm(hdl, arg);
break;
case NODE_IOC_GET_PARAM:
ret = get_volume_ioc_parm(hdl, arg);
break;
}
return ret;
}
static void volume_release(struct stream_node *node)
{
struct volume_hdl *hdl = (struct volume_hdl *)node->private_data;
if (hdl->vol_cfg) {
free(hdl->vol_cfg);
hdl->vol_cfg = NULL;
}
free(hdl);
}
REGISTER_STREAM_NODE_ADAPTER(volume_node_adapter) = {
.name = "volume",
.uuid = NODE_UUID_VOLUME_CTRLER,
.bind = volume_bind,
.ioctl = volume_ioctl,
.release = volume_release,
};
REGISTER_ONLINE_ADJUST_TARGET(volume) = {
.uuid = NODE_UUID_VOLUME_CTRLER,
};