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

284 lines
8.0 KiB
C

#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".plc_node.data.bss")
#pragma data_seg(".plc_node.data")
#pragma const_seg(".plc_node.text.const")
#pragma code_seg(".plc_node.text")
#endif
#include "jlstream.h"
#include "audio_plc.h"
#include "tech_lib/LFaudio_plc_api.h"
#include "app_config.h"
#include "effects/effects_adj.h"
#include "media/audio_splicing.h"
#if TCFG_PLC_NODE_ENABLE
enum audio_plc_type {
AUD_PLC_BYPASS = 0, //不做任何处理,但是仍然会有缓存;
AUD_PLC_NORMAL, //仅修复
AUD_PLC_WITH_FADE //修复的同时做淡入淡出的处理
};
extern int tws_api_get_low_latency_state();
struct plc_node_hdl {
u8 start;
u8 channel_num;
enum stream_scene scene; //当前场景
struct music_plc *plc;
void *esco_plc;
char *out_buf;
u16 out_buf_len;
struct stream_node *node; //节点句柄
struct node_port_data_wide data_wide;
u8 Qval;//数据的饱和位宽
};
struct music_plc {
LFaudio_PLC_API *plc_ops;
void *plc_mem;
af_DataType datatype;
};
struct music_plc *music_plc_open(struct plc_node_hdl *hdl, u32 sr, u8 ch_num)
{
struct music_plc *plc = zalloc(sizeof(struct music_plc));
if (plc) {
plc->datatype.IndataBit = hdl->data_wide.iport_data_wide;
plc->datatype.OutdataBit = hdl->data_wide.oport_data_wide;
plc->datatype.IndataInc = (ch_num == 2) ? 2 : 1;
plc->datatype.OutdataInc = (ch_num == 2) ? 2 : 1;
plc->plc_ops = get_lfaudioPLC_api();
int plc_mem_size = plc->plc_ops->need_buf(ch_num, &plc->datatype); // 3660bytes,请衡量是否使用该空间换取PLC处理
plc->plc_mem = malloc(plc_mem_size);
if (!plc->plc_mem) {
plc->plc_ops = NULL;
free(plc);
return NULL;
}
#if TCFG_USER_TWS_ENABLE
u8 mode = tws_api_get_low_latency_state() ? 4 : 0;
#else
u8 mode = 0;
#endif
plc->plc_ops->open(plc->plc_mem, ch_num, sr, mode, &plc->datatype); //4是延时最低 16个点
}
return plc;
}
void music_plc_run(struct music_plc *plc, s16 *data, u16 len, u8 repair)
{
if (plc && plc->plc_ops) {
u16 point_offset = plc->datatype.IndataBit ? 2 : 1;
u16 plc_type = repair ? AUD_PLC_WITH_FADE : AUD_PLC_BYPASS;
plc->plc_ops->run(plc->plc_mem, data, data, len >> point_offset, plc_type);
}
}
void music_plc_set_bit_wide(struct music_plc *plc, struct node_port_data_wide data_wide)
{
//TODO
}
void music_plc_close(struct music_plc *plc)
{
if (plc) {
if (plc->plc_mem) {
free(plc->plc_mem);
plc->plc_mem = NULL;
}
free(plc);
}
}
/*
*通话plc只支持单声道
* */
void *esco_plc_open(struct plc_node_hdl *hdl, u32 sr, u8 ch_num)
{
hdl->channel_num = ch_num;
af_DataType dataTypeobj = {0};
dataTypeobj.IndataBit = hdl->data_wide.iport_data_wide;
dataTypeobj.OutdataBit = hdl->data_wide.oport_data_wide;
dataTypeobj.IndataInc = 1;
dataTypeobj.OutdataInc = 1;
dataTypeobj.Qval = hdl->node->oport->fmt.Qval;
void *esco_plc = audio_plc_open(sr, 1, &dataTypeobj);
return esco_plc;
}
void esco_plc_run(struct plc_node_hdl *hdl, s16 *data, u16 len, u8 repair_flag)
{
if (!hdl->esco_plc) {
return;
}
u8 ch_num = hdl->channel_num;
u8 bit_wide = hdl->data_wide.oport_data_wide;
if (ch_num == 2) {
if (hdl->out_buf_len < len / 2) {
if (hdl->out_buf) {
free(hdl->out_buf);
hdl->out_buf = NULL;
}
}
if (!hdl->out_buf) {
hdl->out_buf = malloc(len / 2);
hdl->out_buf_len = len / 2;
}
if (hdl->out_buf) {
if (bit_wide) {
if (config_media_24bit_enable) {
pcm_dual_to_single_32bit(hdl->out_buf, data, len);
audio_plc_run(hdl->esco_plc, (s16 *)hdl->out_buf, len / 2, repair_flag);
pcm_single_to_dual_32bit(data, hdl->out_buf, len / 2);
}
} else {
pcm_dual_to_single(hdl->out_buf, data, len);
audio_plc_run(hdl->esco_plc, (s16 *)hdl->out_buf, len / 2, repair_flag);
pcm_single_to_dual(data, hdl->out_buf, len / 2);
}
}
} else {
audio_plc_run(hdl->esco_plc, (s16 *)data, len, repair_flag);
}
}
void esco_plc_close(void *esco_plc)
{
if (!esco_plc) {
return;
}
audio_plc_close(esco_plc);
}
static void plc_handle_frame(struct stream_iport *iport, struct stream_note *note)
{
struct stream_frame *frame;
struct stream_node *node = iport->node;
struct plc_node_hdl *hdl = (struct plc_node_hdl *)iport->private_data;
u8 repair_flag = 0;
while (1) {
frame = jlstream_pull_frame(iport, note);
if (!frame) {
break;
}
if ((frame->flags & (FRAME_FLAG_FILL_PACKET & ~FRAME_FLAG_FLUSH_OUT)) == (FRAME_FLAG_FILL_PACKET & ~FRAME_FLAG_FLUSH_OUT)) {
repair_flag = 1;
//putchar('Q');
}
if (hdl->scene == STREAM_SCENE_A2DP) {
music_plc_run(hdl->plc, (s16 *)frame->data, frame->len, repair_flag);
} else {
esco_plc_run(hdl, (s16 *)frame->data, frame->len, repair_flag);
}
repair_flag = 0;
if (node->oport) {
jlstream_push_frame(node->oport, frame);
} else {
jlstream_free_frame(frame);
}
}
}
/*节点预处理-在ioctl之前*/
static int plc_adapter_bind(struct stream_node *node, u16 uuid)
{
struct plc_node_hdl *hdl = malloc(sizeof(*hdl));
memset(hdl, 0, sizeof(*hdl));
hdl->node = node;
node->private_data = hdl;
return 0;
}
/*打开改节点输入接口*/
static void plc_ioc_open_iport(struct stream_iport *iport)
{
iport->handle_frame = plc_handle_frame;
iport->private_data = iport->node->private_data;
}
/*节点参数协商*/
static int plc_ioc_negotiate(struct stream_iport *iport)
{
return 0;
}
/*节点start函数*/
static void plc_ioc_start(struct plc_node_hdl *hdl, u32 sr, u8 ch_num)
{
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);
if (hdl->scene == STREAM_SCENE_A2DP) {
hdl->plc = music_plc_open(hdl, sr, ch_num);
} else {
hdl->esco_plc = esco_plc_open(hdl, sr, ch_num);
}
}
/*节点stop函数*/
static void plc_ioc_stop(struct plc_node_hdl *hdl)
{
if (hdl->scene == STREAM_SCENE_A2DP) {
if (hdl->plc) {
music_plc_close(hdl->plc);
hdl->plc = NULL;
}
} else {
if (hdl->esco_plc) {
esco_plc_close(hdl->esco_plc);
hdl->esco_plc = NULL;
}
if (hdl->out_buf) {
free(hdl->out_buf);
hdl->out_buf = NULL;
}
}
}
/*节点ioctl函数*/
static int plc_adapter_ioctl(struct stream_iport *iport, int cmd, int arg)
{
int ret = 0;
struct plc_node_hdl *hdl = (struct plc_node_hdl *)iport->private_data;
switch (cmd) {
case NODE_IOC_OPEN_IPORT:
plc_ioc_open_iport(iport);
break;
case NODE_IOC_SET_SCENE:
hdl->scene = (enum stream_scene)arg;
break;
case NODE_IOC_NEGOTIATE:
*(int *)arg |= plc_ioc_negotiate(iport);
break;
case NODE_IOC_START:
plc_ioc_start(hdl, iport->prev->fmt.sample_rate, AUDIO_CH_NUM(iport->prev->fmt.channel_mode));
break;
case NODE_IOC_SUSPEND:
case NODE_IOC_STOP:
plc_ioc_stop(hdl);
break;
}
return ret;
}
/*节点用完释放函数*/
static void plc_adapter_release(struct stream_node *node)
{
free(node->private_data);
}
/*节点adapter 注意需要在sdk_used_list声明,否则会被优化*/
REGISTER_STREAM_NODE_ADAPTER(plc_node_adapter) = {
.name = "plc",
.uuid = NODE_UUID_PLC,
.bind = plc_adapter_bind,
.ioctl = plc_adapter_ioctl,
.release = plc_adapter_release,
};
#endif