#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